feat!: generate OrganizationDomains off the OpenAPI spec by gjtorikian · Pull Request #1620 · workos/workos-node · GitHub
Skip to content

feat!: generate OrganizationDomains off the OpenAPI spec - #1620

Open
gjtorikian wants to merge 3 commits into
mainfrom
oagen/own-organization-domains
Open

gjtorikian wants to merge 3 commits into
mainfrom
oagen/own-organization-domains

Conversation

@gjtorikian

Copy link
Copy Markdown
Contributor

Description

This PR generates the OrganizationDomain category in the Node SDK from the OpenAPI spec.

Three of the four methods switched from a positional id: string to an options object:

┌──────────────────────────┬────────────────────────────────────────────┬────────────────────────────────────────────┐
│          Method          │                   Before                   │                   After                    │
├──────────────────────────┼────────────────────────────────────────────┼────────────────────────────────────────────┤
│ getOrganizationDomain    │ (id: string)                               │ (options: { id: string })                  │
├──────────────────────────┼────────────────────────────────────────────┼────────────────────────────────────────────┤
│ verifyOrganizationDomain │ (id: string)                               │ (options: { id: string })                  │
├──────────────────────────┼────────────────────────────────────────────┼────────────────────────────────────────────┤
│ deleteOrganizationDomain │ (id: string)                               │ (options: { id: string })                  │
├──────────────────────────┼────────────────────────────────────────────┼────────────────────────────────────────────┤

As well, the following output responses changed:

  • createdAt / updatedAt: string → Date. The serializer now does new Date(response.created_at). Anyone treating these as ISO strings (e.g. string ops, direct JSON passthrough) will break.
  • state and verificationStrategy are now optional (state?, verificationStrategy?) — they can be undefined where before they were guaranteed present.

Because of this, the PR should be treated as a breaking change.

oagen now owns OrganizationDomains: timestamps are typed Date (not string)
and the response-only model emits a deserializer only (no
serializeOrganizationDomain). Update the hand-owned modules that embed the
model so the SDK builds and tests pass:

- organization-domain-verification-failed.serializer.ts: drop the dead
  serialize path that depended on the removed serializeOrganizationDomain
- events.spec.ts: assert organization_domain event timestamps as Date
- organizations get-organization fixture + spec: add the spec-required
  organization_id/created_at/updated_at to the embedded domain

These files are hand-owned (not in .oagen-manifest.json); committing them
keeps the reconciliation from being wiped by the regen flow's `git restore`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gjtorikian
gjtorikian requested review from a team as code owners June 16, 2026 17:59
@gjtorikian
gjtorikian requested a review from mattgd June 16, 2026 17:59
@greptile-apps

greptile-apps Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Comment on lines +32 to 41
async createOrganizationDomain(
options: CreateOrganizationDomainOptions,
): Promise<OrganizationDomain> {
const payload = options;
const { data } = await this.workos.post<
OrganizationDomainResponse,
CreateOrganizationDomainResponse
>('/organization_domains', serializeCreateOrganizationDomain(payload));
return deserializeOrganizationDomain(data);
}

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.

P1 Inconsistent return type across CRUD methods

createOrganizationDomain returns Promise<OrganizationDomain> (deserialized via deserializeOrganizationDomain), while getOrganizationDomain and verifyOrganizationDomain return Promise<OrganizationDomainStandAlone>. Despite representing the same API resource, these two interfaces are TypeScript-incompatible: OrganizationDomain.state is typed as the OrganizationDomainState string enum, while OrganizationDomainStandAlone.state uses the OrganizationDomainStandAloneState const-object type. A user who writes a helper function handle(d: OrganizationDomainStandAlone) and passes the result of createOrganizationDomain to it will receive a TypeScript compile error, even though both values are structurally identical at runtime.

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

export enum OrganizationDomainState {
Failed = 'failed',
Pending = 'pending',
Verified = 'verified',
LegacyVerified = 'legacy_verified',
Unverified = 'unverified',
}

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 Duplicate parallel type hierarchies on the public SDK surface

OrganizationDomainState (string enum, 5 members) and OrganizationDomainStandAloneState (const object type, identical 5 members) represent the same domain concept with the same runtime string values. The same duplication exists for OrganizationDomainVerificationStrategy (enum) vs OrganizationDomainStandAloneVerificationStrategy (const type). Because TypeScript string enums are not mutually assignable with string-literal union types, code that holds the two representations side-by-side will require explicit casts, even though the underlying strings are identical. Consolidating to a single representation per concept would eliminate the ambiguity.

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 +14
// This file is auto-generated by oagen. Do not edit.

export * from './create-organization-domain-options.interface';
export * from './organization-domain.interface';
export * from './create-organization-domain.interface';
export * from './delete-organization-domain-options.interface';
export * from './get-organization-domain-options.interface';
export * from './organization-domain-stand-alone-state.interface';
export * from './organization-domain-stand-alone-verification-strategy.interface';
export * from './organization-domain-stand-alone.interface';
export * from './organization-domain-state.interface';
export * from './organization-domain-verification-failed.interface';
export * from './organization-domain-verification-strategy.interface';
export * from './organization-domain.interface';
export * from './verify-organization-domain-options.interface';

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 Non-manifest interface file may be dropped on the next oagen regeneration

interfaces/index.ts (listed in the oagen manifest) currently exports organization-domain-verification-failed.interface.ts, but that interface file itself is not in the manifest. If oagen regenerates index.ts it will only emit entries for files it tracks, silently dropping the export * from './organization-domain-verification-failed.interface' line. organization-domain-verification-failed.serializer.ts imports its types from this barrel and would fail to compile after such a regeneration. Either add the verification-failed interface to the manifest, or import it directly in the serializer rather than through the auto-generated barrel.

@gjtorikian
gjtorikian force-pushed the oagen/own-organization-domains branch from 9da89e3 to 7031028 Compare June 16, 2026 18:11
@gregsabo
gregsabo requested a review from kevinferri June 16, 2026 23:47
OrganizationDomain,
OrganizationDomainResponse,
} from './interfaces';
import { serializeCreateOrganizationDomainOptions } from './serializers/create-organization-domain-options.serializer';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

is serializeCreateOrganizationDomainOptions dead code now?

} from '../common/utils/test-utils';
import { WorkOS } from '../workos';
import getOrganizationDomainPending from './fixtures/get-organization-domain-pending.json';
import getOrganizationDomainVerified from './fixtures/get-organization-domain-verified.json';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

are getOrganizationDomainPending and getOrganizationDomainVerified dead code now?

// This file is auto-generated by oagen. Do not edit.

import type { WorkOS } from '../workos';
import type { CreateOrganizationDomainOptions } from './interfaces/create-organization-domain-options.interface';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

serializeCreateOrganizationDomain takes the generated CreateOrganizationDomain, but this method types its input as the hand-owned CreateOrganizationDomainOptions which has the same shape ({ domain, organizationId }), so we now carry two interfaces for one input type (and SerializedCreateOrganizationDomainOptions is now fully orphaned). Can the client use CreateOrganizationDomain directly so we can delete create-organization-domain-options.interface.ts?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should we assert the actual output here? toBeDefined() would pass even if the mapping were off. The fixture is snake_case (organization_id) but the serializer reads model.organizationId, so serialized.organization_id ends up undefined.

@gjtorikian gjtorikian added the autogenerated Autogenerated code or content label Jun 18, 2026
Regenerated off the collapsed spec so every method returns a single
`OrganizationDomain` type: `getOrganizationDomain` and `verifyOrganizationDomain`
now return `OrganizationDomain` (was the parallel, TS-incompatible
`OrganizationDomainStandAlone`), and `OrganizationDomainState` /
`OrganizationDomainVerificationStrategy` collapse to one enum each (real
`enum`s, matching the published surface).

Removes the now-orphaned StandAlone interface/serializer/enum/fixture files,
plus dead code flagged in review:
- `serializeCreateOrganizationDomainOptions` and the orphaned
  `SerializedCreateOrganizationDomainOptions` interface
- `get-organization-domain-{pending,verified}` fixtures

Generated serializer tests also drop to one assertion per type. Typecheck,
the dead-serializer audit (0), and `organization-domains`/`events` suites pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autogenerated Autogenerated code or content breaking change Contains a breaking change

Development

Successfully merging this pull request may close these issues.

2 participants