Skip to content

feat!: Regenerate SDK from the OpenAPI spec via oagen - #111

Merged
gjtorikian merged 16 commits into
mainfrom
autogen-elixir
Jul 29, 2026
Merged

feat!: Regenerate SDK from the OpenAPI spec via oagen#111
gjtorikian merged 16 commits into
mainfrom
autogen-elixir

Conversation

@gjtorikian

Copy link
Copy Markdown
Contributor

Summary

  • Replaces the hand-written SDK with oagen-generated code. The hand-maintained resource modules covered only a slice of the WorkOS API and drifted as endpoints changed; generated output covers the full surface and stays in lockstep with openapi-spec on every regeneration

  • Removes global application config — this is the main breaking change. Build an instance-scoped client with WorkOS.Client.new/1 and pass it as the first argument to every resource function. config/*.exs is gone. Elixir >= 1.18 is now required, since JSON goes through the stdlib JSON module instead of Jason. Version bumps to 2.0.0.

  • Keeps the non-spec helper surface hand-maintained. Passwordless (Magic Link), webhook signature verification, AuthKit Actions, sealed session cookies (AES-256-GCM), PKCE utilities, JWKS conveniences, client-side Vault encrypt/decrypt (LEB128-framed, interoperable with the other SDKs), and a PKCE-only public-client preset all carry @oagen-ignore-file and sit outside the manifest, so regeneration never overwrites or prunes them. The entry module, client, Cast, Page, and error modules are marked the same way.

  • Fixes four endpoints that were unusable with their documented parameters. Array query params raised ArgumentError before the request left the process — Req passes :params to URI.encode_query, which rejects lists — breaking list_organizations with :domains, list_events with :events, list_applications with :registration_types, and list_organization_memberships with :statuses. build_url/3 and request/5 now share one normalizer so they can't drift apart again.

  • Closes the remaining gaps against the SDK runtime contract. Per-request :max_retries and :base_url overrides now work alongside headers/timeout/idempotency key; retried POSTs get a generated idempotency key (previously only 1 of 211 operations opted in via the spec, so a retried POST could be replayed with no key); ApiError gains :param; nil query values are dropped rather than sent as key=.

gjtorikian and others added 9 commits July 24, 2026 12:12
Replace the hand-written SDK with code generated by oagen from
the openapi-spec repo. Hand-maintained resource modules covered
only a slice of the WorkOS API and drifted as endpoints changed;
generated code covers the full surface and stays in lockstep
with the spec on regeneration.

BREAKING CHANGE: Global application config is removed — build an
instance-scoped client with `WorkOS.Client.new/1` and pass it to
every resource function. Requires Elixir >= 1.18 (JSON is handled
by the stdlib `JSON` module instead of Jason). Version bumps to
2.0.0.
…njection

Regenerated with oagen-emitters wrapper/url-builder support:

- 10 authenticate_with_* wrappers plus create_oauth_application /
  create_m2m_application on Connect, each pinning grant_type or
  application_type and reading client_id/client_secret from the client
- SSO.get_authorization_url / get_logout_url and
  UserManagement.get_authorization_url / get_logout_url emitted as URL
  builders (no HTTP request)
- SSO.get_profile_and_token injects grant_type and client credentials
- WorkOS.Client gains :client_id (WORKOS_CLIENT_ID fallback), build_url/3,
  and param-injection helpers
- Connect.complete_oauth_2 renamed to complete_oauth2 (reviewed name)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports the @oagen-ignore-file helper surface to Elixir: Passwordless
(Magic Link) endpoints, webhook signature verification, AuthKit Actions,
sealed session cookies (AES-256-GCM), PKCE utilities, AuthKit and SSO
PKCE/device/logout flow helpers, JWKS conveniences, client-side Vault
encrypt/decrypt (LEB128-framed, SDK-interoperable), and a PKCE-only
public-client preset. All files carry @oagen-ignore-file and live
outside the oagen manifest, so regeneration never overwrites or prunes
them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The entry module, client, Cast, Page, errors, test_helper, fixture loader,
and client runtime-contract tests are spec-independent. They are now marked
@oagen-ignore-file so oagen never overwrites or prunes them; the emitter no
longer generates them. The manifest drops their entries accordingly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Passing an array query parameter raised ArgumentError before the request
ever left the process: Req hands :params to URI.encode_query, which
rejects list values outright. build_url/3 comma-joined them correctly but
request/5 did not, so four live endpoints were unusable with their
documented parameters — list_organizations with :domains, list_events with
:events, list_applications with :registration_types, and
list_organization_memberships with :statuses. Both paths now share one
normalizer so they cannot drift apart again.

The remaining changes close gaps against text/sdk-runtime-contract.md:

Per-request :max_retries and :base_url overrides were missing from the
five the contract requires; only headers, timeout, and idempotency key
were honored.

Retried POSTs now get a generated idempotency key. Retries are enabled by
default and only one of 211 operations opted in via the spec's
injectIdempotencyKey, so by default a POST could be replayed against the
API with no key at all. :idempotency still works with retries disabled,
for the spec-driven case.

ApiError gains :param, which the contract asks implementations to preserve
where possible; WorkOS reports the offending field either at the top level
or per-entry under errors.

Nil query values are dropped rather than sent as `key=`, matching
build_url/3.
Emitter output only; no hand-authored changes here. Every generated
success test now pins the request method, the request path, and real field
values, and each service gains empty-page, query-encoding, and
per-request-option coverage alongside new per-group round-trip tests. 321
tests to 545.

Two model changes come from the spec rather than the emitter:
Connection drops callback_endpoint, which the spec no longer declares, and
several models gain deprecation notes for fields the spec marked
deprecated.

The union-split parents create_authenticate and create_application are
gone, replaced by their wrapper methods; the spec-driven split makes the
parent unreachable.
These six moduledocs named a symbol this SDK does not define — docs for
`MfaTotpSessionAuthenticateRequest` sat under `defmodule
WorkOS.MFATotpSessionAuthenticateRequest`, and one rendered a raw
snake_case fragment as `ConnectApplication_redirect_uri`.

Regenerated output of the emitter fix; no hand edits.
openapi-spec v0.50.0 and v0.51.0 add a free-form `config` string map to
the DataIntegration request bodies and configuration response, and a
`client_credentials` value to the connected-account auth method enums.

Regenerated output; no hand edits.
@gjtorikian
gjtorikian requested a review from a team as a code owner July 28, 2026 20:33
@greptile-apps

greptile-apps Bot commented Jul 28, 2026

Copy link
Copy Markdown

Too many files changed for review. (1082 files found, 100 file limit)

# Conflicts:
#	lib/workos/user_management/organization_membership.ex
#	test/support/user_management_client_mock.ex
Elixir 1.20 warns when a variable used inside size(...) of a
bitstring pattern was bound outside the match, and the lint job
compiles with --warnings-as-errors on the newest pair — so these
four patterns failed CI even though the matches were correct.

The warning does not exist on 1.19 or earlier, which is why
`script/ci` passes locally while CI goes red.
The regenerated SDK requires Elixir ~> 1.18 because JSON now goes
through the stdlib JSON module instead of Jason. Mix refuses to
run on 1.16 and 1.17 outright, so both legs failed before reaching
a single test — they are leftovers from the hand-written SDK's
support window.
The lint job runs `mix credo --strict -a`, which enables the
low-priority design checks. AliasUsage flagged 20 fully-qualified
references to three-deep modules, failing CI with exit 2.

Only hand-maintained files were affected — nothing here changes
generated output or the emitter.
script/ci ran `mix credo --all` while lint.yml runs
`mix credo --strict -a` — 57 checks locally versus 69 in CI. It also
compiled in dev, where elixirc_paths omits test/support, while every
CI job sets MIX_ENV=test. Both gaps let a clean local run precede a
red PR, which is the one thing this script exists to prevent.
@gjtorikian
gjtorikian merged commit f99dc9a into main Jul 29, 2026
8 checks passed
@gjtorikian
gjtorikian deleted the autogen-elixir branch July 29, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant