Skip to content

feat: Generate Pipes off the OpenAPI spec#1625

Draft
gjtorikian wants to merge 1 commit into
mainfrom
oagen/own-pipes
Draft

feat: Generate Pipes off the OpenAPI spec#1625
gjtorikian wants to merge 1 commit into
mainfrom
oagen/own-pipes

Conversation

@gjtorikian

Copy link
Copy Markdown
Contributor

Description

This PR generates the Pipes API fresh from the OpenAPI spec.

The existing shape of methods is preserved. As well, new functions are added:

  • authorizeDataIntegration
  • getUserConnectedAccount
  • deleteUserConnectedAccount
  • listUserDataProviders

Because of this, this is a non-breaking change.

@gjtorikian gjtorikian requested review from a team as code owners June 16, 2026 21:47
@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR regenerates the Pipes module from the OpenAPI spec, preserving the existing getAccessToken method signature while adding four new methods: authorizeDataIntegration, getUserConnectedAccount, deleteUserConnectedAccount, and listUserDataProviders. All new methods use encodeURIComponent on path parameters and follow consistent URL patterns.

  • pipes.ts gains full coverage of the Pipes/Connected Accounts API surface with properly typed discriminated-union responses and wire-format serializers for every endpoint.
  • New interfaces, serializers, and fixtures are all auto-generated and introduce two minor issues: deserializeDataIntegrationAccessTokenResponse is absent from serializers/index.ts despite every other serializer being exported, and the access-token fixture combines active: true with an error field in violation of the discriminated union, while the rewritten spec removes all error-path tests for getAccessToken.

Confidence Score: 4/5

Safe to merge; no existing functionality is broken and the new methods follow established patterns correctly.

The production implementation in pipes.ts is well-structured and non-breaking. The main concerns are in the test layer: error-path coverage for getAccessToken was dropped entirely in the rewrite, and the access-token fixture encodes a logically impossible state. Neither blocks correct runtime behavior today, but a regression in the inactive-response branch of deserializeDataIntegrationAccessTokenResponse would go undetected.

src/pipes/pipes.spec.ts (missing error-branch tests for getAccessToken), src/pipes/fixtures/data-integration-access-token-response.json (contradictory active/error fields), src/pipes/serializers/index.ts (missing export for data-integration-access-token-response serializer)

Important Files Changed

Filename Overview
src/pipes/pipes.ts Core Pipes class regenerated from OpenAPI spec; adds authorizeDataIntegration, getUserConnectedAccount, deleteUserConnectedAccount, listUserDataProviders with proper encodeURIComponent usage and consistent leading-slash URLs
src/pipes/pipes.spec.ts Tests regenerated for four methods; getAccessToken loses all error-branch coverage (not_installed, needs_reauthorization, 500) that existed before
src/pipes/serializers/index.ts New serializer barrel file; missing export for data-integration-access-token-response.serializer while all other serializers in the directory are exported
src/pipes/fixtures/data-integration-access-token-response.json New fixture combines active:true and error:not_installed simultaneously, which is impossible at runtime per the discriminated union type
src/pipes/serializers/data-integration-access-token-response.serializer.ts Discriminated-union deserializer with switch on active; includes a default throw for unknown values; correctly delegates to the access-token sub-serializer
src/pipes/serializers.spec.ts New serializer unit tests; coverage is shallow (only checks toBeDefined) but exercises all serializers including round-trip fixtures
src/pipes/interfaces/data-integration-access-token-response.interface.ts Correctly models the discriminated union for active/inactive token responses with matching Wire type
src/pipes/interfaces/connected-account.interface.ts Clean interface pair (domain + wire) for connected account with correct nullable fields and state enum reference

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client
    participant Pipes
    participant WorkOS API

    Client->>Pipes: "authorizeDataIntegration({ slug, userId, organizationId?, returnTo? })"
    Pipes->>WorkOS API: POST /data-integrations/{slug}/authorize
    WorkOS API-->>Pipes: DataIntegrationAuthorizeUrlResponseWire { url }
    Pipes-->>Client: "DataIntegrationAuthorizeUrlResponse { url }"

    Client->>Pipes: "getAccessToken({ provider, userId, organizationId? })"
    Pipes->>WorkOS API: POST /data-integrations/{provider}/token
    WorkOS API-->>Pipes: DataIntegrationAccessTokenResponseWire (active=true|false)
    Pipes-->>Client: DataIntegrationAccessTokenResponse

    Client->>Pipes: "getUserConnectedAccount({ userId, slug, organizationId? })"
    Pipes->>WorkOS API: GET /user_management/users/{userId}/connected_accounts/{slug}
    WorkOS API-->>Pipes: ConnectedAccountResponse
    Pipes-->>Client: ConnectedAccount

    Client->>Pipes: "deleteUserConnectedAccount({ userId, slug, organizationId? })"
    Pipes->>WorkOS API: DELETE /user_management/users/{userId}/connected_accounts/{slug}
    WorkOS API-->>Pipes: 204 No Content
    Pipes-->>Client: void

    Client->>Pipes: "listUserDataProviders({ userId, organizationId? })"
    Pipes->>WorkOS API: GET /user_management/users/{userId}/data_providers
    WorkOS API-->>Pipes: DataIntegrationsListResponseWire
    Pipes-->>Client: DataIntegrationsListResponse
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client
    participant Pipes
    participant WorkOS API

    Client->>Pipes: "authorizeDataIntegration({ slug, userId, organizationId?, returnTo? })"
    Pipes->>WorkOS API: POST /data-integrations/{slug}/authorize
    WorkOS API-->>Pipes: DataIntegrationAuthorizeUrlResponseWire { url }
    Pipes-->>Client: "DataIntegrationAuthorizeUrlResponse { url }"

    Client->>Pipes: "getAccessToken({ provider, userId, organizationId? })"
    Pipes->>WorkOS API: POST /data-integrations/{provider}/token
    WorkOS API-->>Pipes: DataIntegrationAccessTokenResponseWire (active=true|false)
    Pipes-->>Client: DataIntegrationAccessTokenResponse

    Client->>Pipes: "getUserConnectedAccount({ userId, slug, organizationId? })"
    Pipes->>WorkOS API: GET /user_management/users/{userId}/connected_accounts/{slug}
    WorkOS API-->>Pipes: ConnectedAccountResponse
    Pipes-->>Client: ConnectedAccount

    Client->>Pipes: "deleteUserConnectedAccount({ userId, slug, organizationId? })"
    Pipes->>WorkOS API: DELETE /user_management/users/{userId}/connected_accounts/{slug}
    WorkOS API-->>Pipes: 204 No Content
    Pipes-->>Client: void

    Client->>Pipes: "listUserDataProviders({ userId, organizationId? })"
    Pipes->>WorkOS API: GET /user_management/users/{userId}/data_providers
    WorkOS API-->>Pipes: DataIntegrationsListResponseWire
    Pipes-->>Client: DataIntegrationsListResponse
Loading

Reviews (1): Last reviewed commit: "generate Pipes off the OpenAPI spec" | Re-trigger Greptile

Comment on lines +1 to +10
// This file is auto-generated by oagen. Do not edit.

export * from './connected-account.serializer';
export * from './data-integration-access-token-response-access-token.serializer';
export * from './data-integration-authorize-url-response.serializer';
export * from './data-integrations-get-data-integration-authorize-url-request.serializer';
export * from './data-integrations-get-user-token-request.serializer';
export * from './data-integrations-list-response.serializer';
export * from './data-integrations-list-response-data.serializer';
export * from './data-integrations-list-response-data-connected-account.serializer';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing serializer export

deserializeDataIntegrationAccessTokenResponse (from data-integration-access-token-response.serializer.ts) is not re-exported here, even though every other serializer in this directory is. Any SDK consumer or internal utility that imports from the barrel path will silently not find it, while all sibling serializers are available. The data-integration-access-token-response-access-token serializer IS exported, making the omission appear like an accidental gap rather than an intentional design choice.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +1 to +11
{
"active": true,
"access_token": {
"object": "access_token",
"access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
"expires_at": "2025-12-31T23:59:59.000Z",
"scopes": ["repo", "user:email"],
"missing_scopes": []
},
"error": "not_installed"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Fixture violates the discriminated-union contract

This fixture sets both "active": true (with "access_token") and "error": "not_installed" simultaneously, which is impossible at runtime — the API will only ever return one or the other. The DataIntegrationAccessTokenResponseWire type is an exclusive union keyed on active, so the error field is outright invalid in the true branch. The serializer silently ignores the extra field today, but if anyone asserts on error in a future test using this same fixture they'll get a false positive. The fixture should either represent only the happy path, or two separate fixtures should exist for the two branches.

Comment thread src/pipes/pipes.spec.ts
Comment on lines +38 to +56
expect(result.url).toBe(
'https://api.workos.com/data-integrations/q2czJKmVAraSBg8xFpT7M9uR/authorize-redirect',
);
});
});

it('returns access token without expiry date', async () => {
fetchOnce(getAccessTokenNoExpiryFixture);
const response = await workos.pipes.getAccessToken({
provider: 'test-provider',
userId: 'user_789',
});
describe('getAccessToken', () => {
it('sends the correct request and returns result', async () => {
fetchOnce(dataIntegrationAccessTokenResponseFixture);

expect(fetchURL()).toContain('/data-integrations/test-provider/token');
expect(fetchBody()).toEqual({
user_id: 'user_789',
organization_id: undefined,
});
expect(response).toEqual({
active: true,
accessToken: {
object: 'access_token',
accessToken: 'test_access_token_456',
expiresAt: null,
scopes: ['read:data'],
missingScopes: ['write:data'],
},
const result = await workos.pipes.getAccessToken({
provider: 'test_provider',
userId: 'user_id_01234',
});

expect(fetchMethod()).toBe('POST');
expect(new URL(String(fetchURL())).pathname).toBe(
'/data-integrations/test_provider/token',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 getAccessToken error-path coverage removed

The previous spec had four dedicated cases for getAccessToken: success-with-expiry, success-without-expiry, not_installed, needs_reauthorization, and a 500 error throw. The replacement is a single happy-path test. The two inactive branches (active: false) in DataIntegrationAccessTokenResponse are now completely untested at the integration level, meaning a regression in deserializeDataIntegrationAccessTokenResponse for the error branch would go undetected.

@gjtorikian gjtorikian marked this pull request as draft June 18, 2026 19:06
@gjtorikian gjtorikian added the autogenerated Autogenerated code or content label Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autogenerated Autogenerated code or content

Development

Successfully merging this pull request may close these issues.

1 participant