From c32beddd1edbe5e5382545648984b8463ad149a1 Mon Sep 17 00:00:00 2001 From: Phil Leggetter Date: Thu, 15 Jan 2026 16:51:10 +0000 Subject: [PATCH 1/4] chore: preserve simple function naming instead of full operation names --- .../speakeasy-modifications-overlay.yaml | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/sdks/schemas/speakeasy-modifications-overlay.yaml b/sdks/schemas/speakeasy-modifications-overlay.yaml index eb242b026..cfd81a889 100644 --- a/sdks/schemas/speakeasy-modifications-overlay.yaml +++ b/sdks/schemas/speakeasy-modifications-overlay.yaml @@ -17,7 +17,7 @@ actions: created_at: 1745611620644 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}"]["get"] update: x-speakeasy-name-override: get x-speakeasy-metadata: @@ -26,7 +26,7 @@ actions: created_at: 1745611620644 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}/events/{event_id}"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}/events/{event_id}"]["get"] update: x-speakeasy-name-override: getByDestination x-speakeasy-metadata: @@ -44,7 +44,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/token"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/token"]["get"] update: x-speakeasy-name-override: getToken x-speakeasy-metadata: @@ -62,7 +62,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}/disable"]["put"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}/disable"]["put"] update: x-speakeasy-name-override: disable x-speakeasy-metadata: @@ -71,7 +71,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/portal"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/portal"]["get"] update: x-speakeasy-name-override: getPortalUrl x-speakeasy-metadata: @@ -80,7 +80,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}/enable"]["put"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}/enable"]["put"] update: x-speakeasy-name-override: enable x-speakeasy-metadata: @@ -98,7 +98,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destination-types"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/destination-types"]["get"] update: x-speakeasy-name-override: listTenantDestinationTypes x-speakeasy-metadata: @@ -107,7 +107,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations"]["post"] + - target: $["paths"]["/tenants/{tenant_id}/destinations"]["post"] update: x-speakeasy-name-override: create x-speakeasy-metadata: @@ -116,7 +116,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}/events/{event_id}/retry"]["post"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}/events/{event_id}/retry"]["post"] update: x-speakeasy-name-override: retry x-speakeasy-metadata: @@ -125,7 +125,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/events/{event_id}/deliveries"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/events/{event_id}/deliveries"]["get"] update: x-speakeasy-name-override: listDeliveries x-speakeasy-metadata: @@ -134,7 +134,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/topics"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/topics"]["get"] update: x-speakeasy-name-override: list x-speakeasy-metadata: @@ -143,7 +143,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/events"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/events"]["get"] update: x-speakeasy-name-override: list x-speakeasy-metadata: @@ -152,7 +152,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}"]["patch"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}"]["patch"] update: x-speakeasy-name-override: update x-speakeasy-metadata: @@ -161,7 +161,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/events/{event_id}"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/events/{event_id}"]["get"] update: x-speakeasy-name-override: get x-speakeasy-metadata: @@ -170,7 +170,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destination-types/{type}"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/destination-types/{type}"]["get"] update: x-speakeasy-name-override: get x-speakeasy-metadata: @@ -188,7 +188,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/destinations"]["get"] update: x-speakeasy-name-override: list x-speakeasy-metadata: @@ -197,7 +197,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}"]["delete"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}"]["delete"] update: x-speakeasy-name-override: delete x-speakeasy-metadata: @@ -215,7 +215,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}/destinations/{destination_id}/events"]["get"] + - target: $["paths"]["/tenants/{tenant_id}/destinations/{destination_id}/events"]["get"] update: x-speakeasy-name-override: listByDestination x-speakeasy-metadata: @@ -224,7 +224,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}"]["get"] + - target: $["paths"]["/tenants/{tenant_id}"]["get"] update: x-speakeasy-name-override: get x-speakeasy-metadata: @@ -233,7 +233,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}"]["delete"] + - target: $["paths"]["/tenants/{tenant_id}"]["delete"] update: x-speakeasy-name-override: delete x-speakeasy-metadata: @@ -242,7 +242,7 @@ actions: created_at: 1745611620645 reviewed_at: 1745611624395 type: method-name - - target: $["paths"]["/{tenant_id}"]["put"] + - target: $["paths"]["/tenants/{tenant_id}"]["put"] update: x-speakeasy-name-override: upsert x-speakeasy-metadata: From f006c6ffee67132200ff4a9a8f3c14f16c541ed4 Mon Sep 17 00:00:00 2001 From: Phil Leggetter Date: Thu, 15 Jan 2026 20:25:53 +0000 Subject: [PATCH 2/4] chore(sdks): resolve enum duplication and update SDK migration guide for v0.12 Outpost release This commit addresses final SDK release preparation. OpenAPI Spec Changes: - Add reusable DestinationType enum schema to components/schemas - Refactor /tenants/{tenant_id}/destinations type parameter to reference DestinationType enum instead of inline duplicate enum definitions - Fixes enum duplication issue that generated ListTenantDestinationsTypeEnum1 and ListTenantDestinationsTypeEnum2 (now uses single components.DestinationType) SDK Configuration: - Update all SDK gen.yaml files: set requestBodyFieldName to 'params' for consistent request body field naming across TypeScript, Python, and Go SDKs - TypeScript: sdks/outpost-typescript/.speakeasy/gen.yaml - Python: sdks/outpost-python/.speakeasy/gen.yaml - Go: sdks/outpost-go/.speakeasy/gen.yaml Migration Guide Updates: - Add 'Version Information' section clarifying distinction between Outpost platform version (v0.12) and SDK versions - Make SDK sections generic (not TypeScript-specific) with TypeScript examples - Update breaking changes table and upgrade checklist to reflect all SDKs SDK Client & Test Updates: - Update sdk-client.ts to use 'params' instead of 'destinationCreate' - Remove 'as any' cast from listDestinations, use proper DestinationType enum - Fix baseURL to include /api/v1 prefix - Update events.test.ts to use response.data instead of response.result.data - Increase event test timeouts from 30s to 60s for reliability Example Updates: - Update all TypeScript examples to use 'params' instead of 'destinationCreate' - Update examples/package.json to use local SDK path for development Overlay Configuration: - Maintain global tenant_id parameter in speakeasy-modifications-overlay.yaml to support optional tenant_id for JWT authentication Documentation: - Update docs/pages/sdks.mdx to use 'params' in code examples All tests passing (132 passing, 14 pending). SDKs verified to generate correctly with 'params' field name. Ready for SDK generation via GitHub Actions with set_version: for TypeScript, Python, and Go SDKs. --- docs/apis/openapi.yaml | 113 +++++++++---- docs/pages/guides/upgrade-v0.12.mdx | 155 ++++++++++++++++-- docs/pages/sdks.mdx | 2 +- examples/sdk-typescript/auth.ts | 2 +- examples/sdk-typescript/create-destination.ts | 2 +- examples/sdk-typescript/index.ts | 2 +- examples/sdk-typescript/package.json | 2 +- sdks/outpost-go/.speakeasy/gen.yaml | 14 +- sdks/outpost-python/.speakeasy/gen.yaml | 15 +- sdks/outpost-typescript/.speakeasy/gen.yaml | 23 ++- spec-sdk-tests/tests/events.test.ts | 24 +-- spec-sdk-tests/utils/sdk-client.ts | 16 +- 12 files changed, 294 insertions(+), 76 deletions(-) diff --git a/docs/apis/openapi.yaml b/docs/apis/openapi.yaml index 7b1b87fb8..b8ce73bb6 100644 --- a/docs/apis/openapi.yaml +++ b/docs/apis/openapi.yaml @@ -232,7 +232,7 @@ components: custom_headers: type: string description: JSON string of custom HTTP headers to include with every webhook request. Header names must be valid HTTP header tokens (alphanumeric, hyphens, underscores). Reserved headers (Content-Type, Host, etc.) cannot be overridden. - example: "{\"x-api-key\":\"secret123\",\"x-tenant-id\":\"customer-456\"}" + example: '{"x-api-key":"secret123","x-tenant-id":"customer-456"}' WebhookCredentials: type: object properties: @@ -436,7 +436,17 @@ components: DestinationWebhook: type: object # Properties duplicated from DestinationBase - required: [id, type, topics, config, credentials, created_at, updated_at, disabled_at] + required: + [ + id, + type, + topics, + config, + credentials, + created_at, + updated_at, + disabled_at, + ] properties: id: type: string @@ -513,7 +523,17 @@ components: DestinationAWSSQS: type: object # Properties duplicated from DestinationBase - required: [id, type, topics, config, credentials, created_at, updated_at, disabled_at] + required: + [ + id, + type, + topics, + config, + credentials, + created_at, + updated_at, + disabled_at, + ] properties: id: type: string @@ -590,7 +610,17 @@ components: DestinationRabbitMQ: type: object # Properties duplicated from DestinationBase - required: [id, type, topics, config, credentials, created_at, updated_at, disabled_at] + required: + [ + id, + type, + topics, + config, + credentials, + created_at, + updated_at, + disabled_at, + ] properties: id: type: string @@ -741,7 +771,17 @@ components: DestinationAWSKinesis: type: object # Properties duplicated from DestinationBase - required: [id, type, topics, config, credentials, created_at, updated_at, disabled_at] + required: + [ + id, + type, + topics, + config, + credentials, + created_at, + updated_at, + disabled_at, + ] properties: id: type: string @@ -894,7 +934,17 @@ components: DestinationAWSS3: type: object # Properties duplicated from DestinationBase - required: [id, type, topics, config, credentials, created_at, updated_at, disabled_at] + required: + [ + id, + type, + topics, + config, + credentials, + created_at, + updated_at, + disabled_at, + ] properties: id: type: string @@ -971,7 +1021,17 @@ components: DestinationGCPPubSub: type: object # Properties duplicated from DestinationBase - required: [id, type, topics, config, credentials, created_at, updated_at, disabled_at] + required: + [ + id, + type, + topics, + config, + credentials, + created_at, + updated_at, + disabled_at, + ] properties: id: type: string @@ -1716,6 +1776,19 @@ components: example: { "content-type": "application/json" } # Destination Type Schema (for Metadata endpoint) + DestinationType: + type: string + enum: + - webhook + - aws_sqs + - rabbitmq + - hookdeck + - aws_kinesis + - azure_servicebus + - aws_s3 + - gcp_pubsub + description: Type of destination. + example: "webhook" DestinationTypeSchema: type: object properties: @@ -2184,32 +2257,10 @@ paths: required: false schema: oneOf: - - type: string - enum: - [ - webhook, - aws_sqs, - rabbitmq, - hookdeck, - aws_kinesis, - azure_servicebus, - aws_s3, - gcp_pubsub, - ] + - $ref: "#/components/schemas/DestinationType" - type: array items: - type: string - enum: - [ - webhook, - aws_sqs, - rabbitmq, - hookdeck, - aws_kinesis, - azure_servicebus, - aws_s3, - gcp_pubsub, - ] + $ref: "#/components/schemas/DestinationType" description: Filter destinations by type(s). - name: topics in: query diff --git a/docs/pages/guides/upgrade-v0.12.mdx b/docs/pages/guides/upgrade-v0.12.mdx index 2d8f53c9d..53a150ae7 100644 --- a/docs/pages/guides/upgrade-v0.12.mdx +++ b/docs/pages/guides/upgrade-v0.12.mdx @@ -4,27 +4,40 @@ title: "Upgrade to v0.12" This guide covers breaking changes and migration steps when upgrading from v0.11 to v0.12. +## Version Information + +This guide covers upgrading **Outpost platform** from v0.11 to v0.12. + +**Important**: Outpost platform versions (v0.12) are separate from SDK versions. + +- **Outpost Platform**: The server/API version (currently v0.12) +- **SDKs**: Client library versions (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) + +SDK versions may not always match platform versions, as SDKs can have their own release cycle. + ## Breaking Changes Overview -| Change | Impact | Action Required | -|--------|--------|-----------------| -| [API route prefix](#api-route-prefix) | All tenant-scoped endpoints | Update API client paths | -| [Webhook signature defaults](#webhook-signature-defaults) | Signature verification | Update receivers or configure for backward compatibility | -| [List Tenants & Redis migrations](#list-tenants--redis-migrations) | New feature + data format | Run migrations | +| Change | Impact | Action Required | +| ---------------------------------------------------------------------- | --------------------------- | ----------------------------------------------------------------------------- | +| [API route prefix](#api-route-prefix) | All tenant-scoped endpoints | Update API client paths | +| [Webhook signature defaults](#webhook-signature-defaults) | Signature verification | Update receivers or configure for backward compatibility | +| [List Tenants & Redis migrations](#list-tenants--redis-migrations) | New feature + data format | Run migrations | +| [SDK request body field names](#sdk-request-body-field-names-all-sdks) | All SDK methods | Update method calls to use `params` instead of operation-specific field names | +| [SDK response structure](#sdk-response-structure-all-sdks) | All SDK response access | Update response access from `response.result.data` to `response.data` | ## API Route Prefix All tenant-scoped API endpoints now use a `/tenants/` prefix. -| Old Path | New Path | -|----------|----------| -| `PUT /api/v1/:tenant_id` | `PUT /api/v1/tenants/:tenant_id` | -| `GET /api/v1/:tenant_id` | `GET /api/v1/tenants/:tenant_id` | -| `DELETE /api/v1/:tenant_id` | `DELETE /api/v1/tenants/:tenant_id` | -| `GET /api/v1/:tenant_id/destinations` | `GET /api/v1/tenants/:tenant_id/destinations` | +| Old Path | New Path | +| -------------------------------------- | ---------------------------------------------- | +| `PUT /api/v1/:tenant_id` | `PUT /api/v1/tenants/:tenant_id` | +| `GET /api/v1/:tenant_id` | `GET /api/v1/tenants/:tenant_id` | +| `DELETE /api/v1/:tenant_id` | `DELETE /api/v1/tenants/:tenant_id` | +| `GET /api/v1/:tenant_id/destinations` | `GET /api/v1/tenants/:tenant_id/destinations` | | `POST /api/v1/:tenant_id/destinations` | `POST /api/v1/tenants/:tenant_id/destinations` | -| `GET /api/v1/:tenant_id/events` | `GET /api/v1/tenants/:tenant_id/events` | -| ... | ... | +| `GET /api/v1/:tenant_id/events` | `GET /api/v1/tenants/:tenant_id/events` | +| ... | ... | The pattern applies to all endpoints that previously started with `/:tenant_id`. @@ -34,10 +47,10 @@ The pattern applies to all endpoints that previously started with `/:tenant_id`. The default webhook signature templates have changed to a simpler format without timestamps. -| Setting | Old Default (v0.11) | New Default (v0.12) | -|---------|---------------------|---------------------| -| `DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE` | `{{.Timestamp.Unix}}.{{.Body}}` | `{{.Body}}` | -| `DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE` | `t={{.Timestamp.Unix}},v0={{.Signatures \| join ","}}` | `v0={{.Signatures \| join ","}}` | +| Setting | Old Default (v0.11) | New Default (v0.12) | +| ------------------------------------------------- | ------------------------------------------------------ | -------------------------------- | +| `DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE` | `{{.Timestamp.Unix}}.{{.Body}}` | `{{.Body}}` | +| `DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE` | `t={{.Timestamp.Unix}},v0={{.Signatures \| join ","}}` | `v0={{.Signatures \| join ","}}` | If your webhook receivers verify signatures using the old format, signature verification will fail after upgrading. @@ -48,6 +61,110 @@ DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE="{{.Timestamp.Unix}}.{{.Body}}" DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE="t={{.Timestamp.Unix}},v0={{.Signatures | join \",\"}}" ``` +## SDK Request Body Field Names (All SDKs) + +All SDKs (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) now use a consistent `params` field name for request bodies instead of operation-specific names like `destinationCreate` or `destinationUpdate`. + +:::note[Examples] +Examples shown in TypeScript, but changes apply to all SDKs (TypeScript, Python, Go). +::: + +### Before (v0.10.0) + +```typescript +// Creating a destination +await outpost.destinations.create({ + tenantId: "acme-corp", + destinationCreate: { + type: "webhook", + topics: ["order.created"], + config: { url: "https://acme.com/webhooks" }, + }, +}); + +// Updating a destination +await outpost.destinations.update({ + tenantId: "acme-corp", + destinationId: "des_123", + destinationUpdate: { + topics: ["order.updated"], + }, +}); +``` + +### After (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) + +```typescript +// Creating a destination +await outpost.destinations.create({ + tenantId: "acme-corp", + params: { + type: "webhook", + topics: ["order.created"], + config: { url: "https://acme.com/webhooks" }, + }, +}); + +// Updating a destination +await outpost.destinations.update({ + tenantId: "acme-corp", + destinationId: "des_123", + params: { + topics: ["order.updated"], + }, +}); +``` + +**Action:** Update all SDK method calls that use `destinationCreate`, `destinationUpdate`, or similar operation-specific field names to use `params` instead. + +## SDK Response Structure (All SDKs) + +All SDKs (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) response structure has changed. Paginated responses (like events lists) now return data directly on the response object instead of nested under a `result` property. + +:::note[Examples] +Examples shown in TypeScript, but changes apply to all SDKs (TypeScript, Python, Go). +::: + +### Before (v0.10.0) + +```typescript +// Listing events by destination +const response = await outpost.events.listByDestination({ + tenantId: "acme-corp", + destinationId: "des_123", +}); +const events = response?.result?.data || []; + +// Listing tenant events +const response = await outpost.events.list({ + tenantId: "acme-corp", +}); +const events = response?.result?.data || []; +``` + +### After (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) + +```typescript +// Listing events by destination +const response = await outpost.events.listByDestination({ + tenantId: "acme-corp", + destinationId: "des_123", +}); +const events = response?.data || []; + +// Listing tenant events +const response = await outpost.events.list({ + tenantId: "acme-corp", +}); +const events = response?.data || []; +``` + +**Action:** Update all code that accesses paginated response data from `response.result.data` to `response.data`. This affects: + +- `events.listByDestination()` - returns `ListTenantEventsByDestinationResponse` with `data` directly +- `events.list()` - returns `ListTenantEventsResponse` with `data` directly +- Other paginated list endpoints + ## List Tenants & Redis Migrations v0.12 introduces a new `GET /api/v1/tenants` endpoint for listing all tenants with cursor-based pagination. This feature requires Redis migrations to be run. @@ -95,11 +212,15 @@ For detailed information on the migration workflow, safety features, and trouble ## Upgrade Checklist 1. **Before upgrading:** + - [ ] Update API clients to use `/tenants/` prefix paths + - [ ] Update SDK calls (all languages) to use `params` instead of operation-specific field names + - [ ] Update SDK response access (all languages) from `response.result.data` to `response.data` - [ ] Decide on webhook signature format (keep old or adopt new) - [ ] Back up Redis data 2. **During upgrade:** + - [ ] Set webhook signature environment variables if maintaining backward compatibility - [ ] Run migrations (automatic or manual) diff --git a/docs/pages/sdks.mdx b/docs/pages/sdks.mdx index 8561d264f..7bff7ea7a 100644 --- a/docs/pages/sdks.mdx +++ b/docs/pages/sdks.mdx @@ -75,7 +75,7 @@ async function manageOutpostResources() { ); const destination = await outpostAdmin.destinations.create({ tenantId, - destinationCreate: { + params: { type: "webhook", config: { url: "https://example.com/webhook-receiver", diff --git a/examples/sdk-typescript/auth.ts b/examples/sdk-typescript/auth.ts index 21ccd2e06..d794728b0 100644 --- a/examples/sdk-typescript/auth.ts +++ b/examples/sdk-typescript/auth.ts @@ -63,7 +63,7 @@ const withAdminApiKey = async () => { ); const destination = await outpost.destinations.create({ tenantId, - destinationCreate: { + params: { type: "webhook", config: { url: "https://example.com/webhook-receiver", diff --git a/examples/sdk-typescript/create-destination.ts b/examples/sdk-typescript/create-destination.ts index 7d572ec6a..5a6e29d8e 100644 --- a/examples/sdk-typescript/create-destination.ts +++ b/examples/sdk-typescript/create-destination.ts @@ -97,7 +97,7 @@ az servicebus queue authorization-rule keys list \\ ]); destinationCreateRequest = { tenantId: TENANT_ID, - destinationCreate: { + params: { credentials: { connectionString, }, diff --git a/examples/sdk-typescript/index.ts b/examples/sdk-typescript/index.ts index 08a5e0dc8..7f3779244 100644 --- a/examples/sdk-typescript/index.ts +++ b/examples/sdk-typescript/index.ts @@ -36,7 +36,7 @@ async function manageOutpostResources() { ); const destination = await outpostAdmin.destinations.create({ tenantId, - destinationCreate: { + params: { type: "webhook", config: { url: "https://example.com/webhook-receiver", diff --git a/examples/sdk-typescript/package.json b/examples/sdk-typescript/package.json index b769d1e9a..a1d8d57ce 100644 --- a/examples/sdk-typescript/package.json +++ b/examples/sdk-typescript/package.json @@ -1,7 +1,7 @@ { "type": "module", "dependencies": { - "@hookdeck/outpost-sdk": "^0.3.0", + "@hookdeck/outpost-sdk": "file:../../sdks/outpost-typescript", "dotenv": "^16.5.0", "inquirer": "^9.2.23" }, diff --git a/sdks/outpost-go/.speakeasy/gen.yaml b/sdks/outpost-go/.speakeasy/gen.yaml index c91e54643..61874e719 100644 --- a/sdks/outpost-go/.speakeasy/gen.yaml +++ b/sdks/outpost-go/.speakeasy/gen.yaml @@ -13,21 +13,28 @@ generation: requestResponseComponentNamesFeb2024: true securityFeb2025: true sharedErrorComponentsApr2025: false + sharedNestedComponentsJan2026: false auth: oAuth2ClientCredentialsEnabled: true oAuth2PasswordEnabled: true + hoistGlobalSecurity: true + schemas: + allOfMergeStrategy: shallowMerge + requestBodyFieldName: params + persistentEdits: {} tests: generateTests: true generateNewTests: false skipResponseBodyAssertions: false go: - version: 0.4.0 + version: 0.6.0 additionalDependencies: {} allowUnknownFieldsInWeakUnions: false baseErrorName: OutpostError clientServerStatusCodesAsErrors: true defaultErrorName: APIError flattenGlobalSecurity: true + forwardCompatibleEnumsByDefault: false imports: option: openapi paths: @@ -36,12 +43,17 @@ go: operations: models/operations shared: models/components webhooks: models/webhooks + includeEmptyObjects: false + inferUnionDiscriminators: false inputModelSuffix: input maxMethodParams: 4 methodArguments: require-security-and-request modulePath: "" + multipartArrayFormat: legacy + nullableOptionalWrapper: false outputModelSuffix: output packageName: github.com/hookdeck/outpost/sdks/outpost-go respectRequiredFields: false responseFormat: envelope-http sdkPackageName: "" + unionStrategy: left-to-right diff --git a/sdks/outpost-python/.speakeasy/gen.yaml b/sdks/outpost-python/.speakeasy/gen.yaml index 9420210b3..189edf494 100644 --- a/sdks/outpost-python/.speakeasy/gen.yaml +++ b/sdks/outpost-python/.speakeasy/gen.yaml @@ -13,25 +13,33 @@ generation: requestResponseComponentNamesFeb2024: true securityFeb2025: true sharedErrorComponentsApr2025: false + sharedNestedComponentsJan2026: false auth: oAuth2ClientCredentialsEnabled: true oAuth2PasswordEnabled: true + hoistGlobalSecurity: true + schemas: + allOfMergeStrategy: shallowMerge + requestBodyFieldName: params + persistentEdits: {} tests: generateTests: true generateNewTests: false skipResponseBodyAssertions: false python: - version: 0.4.0 + version: 0.6.0 additionalDependencies: dev: {} main: {} allowedRedefinedBuiltins: - id - object + asyncMode: both authors: - Speakeasy baseErrorName: OutpostError clientServerStatusCodesAsErrors: true + constFieldCasing: upper defaultErrorName: APIError description: Python Client SDK Generated by Speakeasy. enableCustomCodeRegions: false @@ -49,14 +57,19 @@ python: operations: "" shared: "" webhooks: "" + inferUnionDiscriminators: true inputModelSuffix: input + license: "" maxMethodParams: 999 methodArguments: infer-optional-args moduleName: "" + multipartArrayFormat: legacy outputModelSuffix: output packageManager: poetry packageName: outpost_sdk + preApplyUnionDiscriminators: false pytestFilterWarnings: [] pytestTimeout: 0 responseFormat: flat + sseFlatResponse: false templateVersion: v2 diff --git a/sdks/outpost-typescript/.speakeasy/gen.yaml b/sdks/outpost-typescript/.speakeasy/gen.yaml index 47ea9399d..f39813b3b 100644 --- a/sdks/outpost-typescript/.speakeasy/gen.yaml +++ b/sdks/outpost-typescript/.speakeasy/gen.yaml @@ -13,33 +13,45 @@ generation: requestResponseComponentNamesFeb2024: true securityFeb2025: true sharedErrorComponentsApr2025: false + sharedNestedComponentsJan2026: false auth: oAuth2ClientCredentialsEnabled: true oAuth2PasswordEnabled: true hoistGlobalSecurity: true + schemas: + allOfMergeStrategy: shallowMerge + requestBodyFieldName: params + persistentEdits: {} tests: generateTests: true generateNewTests: false skipResponseBodyAssertions: false typescript: - version: 0.5.0 + version: 0.11.1 acceptHeaderEnum: true additionalDependencies: dependencies: {} devDependencies: {} peerDependencies: {} additionalPackageJSON: {} + additionalScripts: {} + alwaysIncludeInboundAndOutbound: false author: Speakeasy baseErrorName: OutpostError clientServerStatusCodesAsErrors: true - constFieldsAlwaysOptional: true + constFieldsAlwaysOptional: false defaultErrorName: APIError enableCustomCodeRegions: false enableMCPServer: true enableReactQuery: false enumFormat: union + exportZodModelNamespace: false + flatAdditionalProperties: false flattenGlobalSecurity: true flatteningOrder: parameters-first + formStringArrayEncodeMode: encoded-string + forwardCompatibleEnumsByDefault: false + forwardCompatibleUnionsByDefault: "false" generateExamples: true imports: option: openapi @@ -49,16 +61,23 @@ typescript: operations: models/operations shared: models/components webhooks: models/webhooks + inferUnionDiscriminators: true inputModelSuffix: input jsonpath: rfc9535 + laxMode: strict maxMethodParams: 0 methodArguments: require-security-and-request modelPropertyCasing: camel moduleFormat: dual + multipartArrayFormat: legacy outputModelSuffix: output packageName: '@hookdeck/outpost-sdk' + preApplyUnionDiscriminators: true + preserveModelFieldNames: false responseFormat: flat sseFlatResponse: false templateVersion: v2 + unionStrategy: left-to-right usageSDKInitImports: [] useIndexModules: true + zodVersion: v3 diff --git a/spec-sdk-tests/tests/events.test.ts b/spec-sdk-tests/tests/events.test.ts index abebc3886..a234631de 100644 --- a/spec-sdk-tests/tests/events.test.ts +++ b/spec-sdk-tests/tests/events.test.ts @@ -135,7 +135,7 @@ describe('Events - Status Field Tests (PR #491)', () => { describe('GET /api/v1/tenants/{tenant_id}/destinations/{destination_id}/events - Event Status Field', () => { it('should include status field in events returned from listByDestination', async function () { // Increase timeout for this test as it involves publishing and waiting for event delivery - this.timeout(45000); + this.timeout(90000); // Get the underlying SDK to access the events and publish methods const sdk: Outpost = client.getSDK(); @@ -151,21 +151,21 @@ describe('Events - Status Field Tests (PR #491)', () => { }); console.log('Event published successfully'); - // Poll for events with 5s intervals, max 30s wait + // Poll for events with 5s intervals, max 60s wait const events = await pollForEvents( async () => { const response = await sdk.events.listByDestination({ tenantId: client.getTenantId(), destinationId: destinationId, }); - return response?.result?.data || []; + return response?.data || []; }, - 30000, + 60000, 5000 ); if (events.length === 0) { - throw new Error('No events found after 30 seconds - event delivery may be failing'); + throw new Error('No events found after 60 seconds - event delivery may be failing'); } // Verify that at least one event has the status field @@ -193,8 +193,8 @@ describe('Events - Status Field Tests (PR #491)', () => { destinationId: destinationId, }); - // The SDK wraps the API response in a 'result' object - const events = response?.result?.data || []; + // The SDK wraps the API response in a 'data' property + const events = response?.data || []; if (events.length === 0) { console.warn('No events found - skipping single event test'); @@ -228,7 +228,7 @@ describe('Events - Status Field Tests (PR #491)', () => { describe('GET /api/v1/tenants/{tenant_id}/events - Tenant Events Status Field', () => { it('should include status field in events returned from tenant events list', async function () { // Increase timeout for this test as it involves publishing and waiting for event delivery - this.timeout(45000); + this.timeout(90000); const sdk: Outpost = client.getSDK(); @@ -243,20 +243,20 @@ describe('Events - Status Field Tests (PR #491)', () => { }); console.log('Event published successfully'); - // Poll for events with 5s intervals, max 30s wait + // Poll for events with 5s intervals, max 60s wait const events = await pollForEvents( async () => { const response = await sdk.events.list({ tenantId: client.getTenantId(), }); - return response?.result?.data || []; + return response?.data || []; }, - 30000, + 60000, 5000 ); if (events.length === 0) { - throw new Error('No tenant events found after 30 seconds - event delivery may be failing'); + throw new Error('No tenant events found after 60 seconds - event delivery may be failing'); } // Verify that at least one event has the status field diff --git a/spec-sdk-tests/utils/sdk-client.ts b/spec-sdk-tests/utils/sdk-client.ts index 53c26a367..fc865df53 100644 --- a/spec-sdk-tests/utils/sdk-client.ts +++ b/spec-sdk-tests/utils/sdk-client.ts @@ -6,6 +6,7 @@ import type { Destination, DestinationCreate, DestinationUpdate, + DestinationType, Tenant, } from '../../sdks/outpost-typescript/dist/commonjs/models/components'; @@ -30,11 +31,11 @@ export type { Destination, DestinationCreate, DestinationUpdate, Tenant }; * Validation errors are thrown as SDKValidationError or ResponseValidationError. */ export class SdkClient { - private sdk: any; + private sdk: Outpost; private tenantId: string; constructor(config: SdkClientConfig = {}) { - const baseURL = config.baseURL || process.env.API_BASE_URL || 'http://localhost:3333'; + const baseURL = config.baseURL || process.env.API_BASE_URL || 'http://localhost:3333/api/v1'; this.tenantId = config.tenantId || process.env.TENANT_ID || 'test-tenant'; if (process.env.DEBUG_API_REQUESTS === 'true') { @@ -43,7 +44,6 @@ export class SdkClient { this.sdk = new Outpost({ serverURL: baseURL, - tenantId: this.tenantId, security: { adminApiKey: config.apiKey || process.env.API_KEY || '', }, @@ -76,7 +76,7 @@ export class SdkClient { async createDestination(data: DestinationCreate): Promise { return await this.sdk.destinations.create({ tenantId: this.tenantId, - destinationCreate: data, + params: data, }); } @@ -93,7 +93,9 @@ export class SdkClient { /** * List all destinations */ - async listDestinations(params?: { type?: string }): Promise { + async listDestinations(params?: { + type?: DestinationType | DestinationType[]; + }): Promise { return await this.sdk.destinations.list({ tenantId: this.tenantId, type: params?.type, @@ -112,7 +114,7 @@ export class SdkClient { return await this.sdk.destinations.update({ tenantId: tenantId || this.tenantId, destinationId, - destinationUpdate: data, + params: data, }); } @@ -155,7 +157,7 @@ export class SdkClient { export function createSdkClient(config: SdkClientConfig = {}): SdkClient { return new SdkClient({ ...config, - baseURL: config.baseURL || process.env.API_BASE_URL || 'http://localhost:3333', + baseURL: config.baseURL || process.env.API_BASE_URL || 'http://localhost:3333/api/v1', apiKey: config.apiKey || process.env.API_KEY, }); } From 0758d222ccec305eb33cdead62799212ce5ad726 Mon Sep 17 00:00:00 2001 From: Phil Leggetter Date: Thu, 15 Jan 2026 20:30:32 +0000 Subject: [PATCH 3/4] fix(sdks): update events tests for new SDKs --- spec-sdk-tests/tests/events.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec-sdk-tests/tests/events.test.ts b/spec-sdk-tests/tests/events.test.ts index a234631de..dbb000053 100644 --- a/spec-sdk-tests/tests/events.test.ts +++ b/spec-sdk-tests/tests/events.test.ts @@ -135,7 +135,7 @@ describe('Events - Status Field Tests (PR #491)', () => { describe('GET /api/v1/tenants/{tenant_id}/destinations/{destination_id}/events - Event Status Field', () => { it('should include status field in events returned from listByDestination', async function () { // Increase timeout for this test as it involves publishing and waiting for event delivery - this.timeout(90000); + this.timeout(45000); // Get the underlying SDK to access the events and publish methods const sdk: Outpost = client.getSDK(); @@ -151,7 +151,7 @@ describe('Events - Status Field Tests (PR #491)', () => { }); console.log('Event published successfully'); - // Poll for events with 5s intervals, max 60s wait + // Poll for events with 5s intervals, max 30s wait const events = await pollForEvents( async () => { const response = await sdk.events.listByDestination({ @@ -160,12 +160,12 @@ describe('Events - Status Field Tests (PR #491)', () => { }); return response?.data || []; }, - 60000, + 30000, 5000 ); if (events.length === 0) { - throw new Error('No events found after 60 seconds - event delivery may be failing'); + throw new Error('No events found after 30 seconds - event delivery may be failing'); } // Verify that at least one event has the status field @@ -228,7 +228,7 @@ describe('Events - Status Field Tests (PR #491)', () => { describe('GET /api/v1/tenants/{tenant_id}/events - Tenant Events Status Field', () => { it('should include status field in events returned from tenant events list', async function () { // Increase timeout for this test as it involves publishing and waiting for event delivery - this.timeout(90000); + this.timeout(45000); const sdk: Outpost = client.getSDK(); @@ -243,7 +243,7 @@ describe('Events - Status Field Tests (PR #491)', () => { }); console.log('Event published successfully'); - // Poll for events with 5s intervals, max 60s wait + // Poll for events with 5s intervals const events = await pollForEvents( async () => { const response = await sdk.events.list({ @@ -251,12 +251,12 @@ describe('Events - Status Field Tests (PR #491)', () => { }); return response?.data || []; }, - 60000, + 30000, 5000 ); if (events.length === 0) { - throw new Error('No tenant events found after 60 seconds - event delivery may be failing'); + throw new Error('No tenant events found after 30 seconds - event delivery may be failing'); } // Verify that at least one event has the status field From dfdcbd9e0f46119b2efb48f2a9929312c649595a Mon Sep 17 00:00:00 2001 From: Phil Leggetter Date: Thu, 15 Jan 2026 20:46:17 +0000 Subject: [PATCH 4/4] chore(docs): simplify version mentions in 0.12 upgrade guide --- docs/pages/guides/upgrade-v0.12.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/pages/guides/upgrade-v0.12.mdx b/docs/pages/guides/upgrade-v0.12.mdx index 53a150ae7..1a9a769c0 100644 --- a/docs/pages/guides/upgrade-v0.12.mdx +++ b/docs/pages/guides/upgrade-v0.12.mdx @@ -69,7 +69,7 @@ All SDKs (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) now use a consistent `par Examples shown in TypeScript, but changes apply to all SDKs (TypeScript, Python, Go). ::: -### Before (v0.10.0) +### Before ```typescript // Creating a destination @@ -92,7 +92,7 @@ await outpost.destinations.update({ }); ``` -### After (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) +### After ```typescript // Creating a destination @@ -125,7 +125,7 @@ All SDKs (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) response structure has ch Examples shown in TypeScript, but changes apply to all SDKs (TypeScript, Python, Go). ::: -### Before (v0.10.0) +### Before ```typescript // Listing events by destination @@ -142,7 +142,7 @@ const response = await outpost.events.list({ const events = response?.result?.data || []; ``` -### After (TypeScript v0.6.0, Python v0.5.0, Go v0.5.0) +### After ```typescript // Listing events by destination