feat!: Generate AdminPortal from OpenAPI spec#1629
Conversation
Greptile SummaryThis PR migrates the
Confidence Score: 4/5The implementation changes are correct — serializers, interfaces, and the API call are all wired up properly. The main concern is test coverage: the primary breaking change (field rename) is never exercised in any test, and all serializer tests now only check toBeDefined(). The serialization logic for the renamed itContactEmails field and the new domainVerification intent option are implemented correctly. However, the test suite was substantially simplified — round-trip assertions were dropped in favour of existence checks, and the admin-portal.spec.ts lost all intent-specific and error-case tests. A dead generated file (generate-link-intent.interface.ts) is also present but unused. src/admin-portal/serializers.spec.ts and src/admin-portal/admin-portal.spec.ts would benefit from stronger assertions; src/admin-portal/interfaces/generate-link-intent.interface.ts should either be wired up or removed. Important Files Changed
|
| // This file is auto-generated by oagen. Do not edit. | ||
|
|
||
| export const GenerateLinkIntent = { | ||
| SSO: 'sso', | ||
| DSync: 'dsync', | ||
| AuditLogs: 'audit_logs', | ||
| LogStreams: 'log_streams', | ||
| DomainVerification: 'domain_verification', | ||
| CertificateRenewal: 'certificate_renewal', | ||
| BringYourOwnKey: 'bring_your_own_key', | ||
| } as const; | ||
|
|
||
| export type GenerateLinkIntent = | ||
| (typeof GenerateLinkIntent)[keyof typeof GenerateLinkIntent]; |
There was a problem hiding this comment.
Unused generated file — never imported
This file duplicates src/common/interfaces/generate-link-intent.interface.ts exactly, but nothing imports it. generate-link.interface.ts still imports GenerateLinkIntent from ../../common/interfaces/generate-link-intent.interface, and interfaces/index.ts does not re-export this file. The generator appears to have produced the file but did not update the import path in generate-link.interface.ts to use the local copy, leaving this file as dead code.
| describe('SSOIntentOptionsSerializer', () => { | ||
| it('round-trips through serialize/deserialize', () => { | ||
| it('serializes correctly', () => { | ||
| const fixture = ssoIntentOptionsFixture as SSOIntentOptionsResponse; | ||
| const deserialized = deserializeSSOIntentOptions(fixture); | ||
| const reserialized = serializeSSOIntentOptions(deserialized); | ||
| expect(reserialized).toEqual(expect.objectContaining(fixture)); | ||
| const serialized = serializeSSOIntentOptions(fixture as any); | ||
| expect(serialized).toBeDefined(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('DomainVerificationIntentOptionsSerializer', () => { | ||
| it('serializes correctly', () => { | ||
| const fixture = | ||
| domainVerificationIntentOptionsFixture as DomainVerificationIntentOptionsResponse; | ||
| const serialized = serializeDomainVerificationIntentOptions(fixture as any); | ||
| expect(serialized).toBeDefined(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('IntentOptionsSerializer', () => { | ||
| it('round-trips through serialize/deserialize', () => { | ||
| it('serializes correctly', () => { | ||
| const fixture = intentOptionsFixture as IntentOptionsResponse; | ||
| const deserialized = deserializeIntentOptions(fixture); | ||
| const reserialized = serializeIntentOptions(deserialized); | ||
| expect(reserialized).toEqual(expect.objectContaining(fixture)); | ||
| const serialized = serializeIntentOptions(fixture as any); | ||
| expect(serialized).toBeDefined(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('GenerateLinkSerializer', () => { | ||
| it('round-trips through serialize/deserialize', () => { | ||
| it('serializes correctly', () => { | ||
| const fixture = generateLinkFixture as GenerateLinkResponse; | ||
| const deserialized = deserializeGenerateLink(fixture); | ||
| const reserialized = serializeGenerateLink(deserialized); | ||
| expect(reserialized).toEqual(expect.objectContaining(fixture)); | ||
| const serialized = serializeGenerateLink(fixture as any); | ||
| expect(serialized).toBeDefined(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('PortalLinkResponseSerializer', () => { | ||
| it('round-trips through serialize/deserialize', () => { | ||
| it('deserializes correctly', () => { | ||
| const fixture = portalLinkResponseFixture as PortalLinkResponseWire; | ||
| const deserialized = deserializePortalLinkResponse(fixture); | ||
| const reserialized = serializePortalLinkResponse(deserialized); | ||
| expect(reserialized).toEqual(expect.objectContaining(fixture)); | ||
| expect(deserialized).toBeDefined(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Tests only verify existence, not correctness
All serializer tests were downgraded from round-trip assertions (expect(reserialized).toEqual(expect.objectContaining(fixture))) to expect(serialized).toBeDefined(). A call that returns {} or an object where every field is undefined would still pass. Notably, the renamed field itContactEmails → it_contact_emails (the key breaking change in this PR) is never verified to round-trip correctly through any of these tests.
| async generateLink(options: GenerateLink): Promise<PortalLinkResponse> { | ||
| const payload = options; | ||
| const { data } = await this.workos.post< | ||
| PortalLinkResponseWire, | ||
| GenerateLinkResponse | ||
| >('/portal/generate_link', serializeGenerateLink(payload)); |
There was a problem hiding this comment.
The intermediate
const payload = options; assignment adds no value — options can be passed directly to serializeGenerateLink.
| async generateLink(options: GenerateLink): Promise<PortalLinkResponse> { | |
| const payload = options; | |
| const { data } = await this.workos.post< | |
| PortalLinkResponseWire, | |
| GenerateLinkResponse | |
| >('/portal/generate_link', serializeGenerateLink(payload)); | |
| async generateLink(options: GenerateLink): Promise<PortalLinkResponse> { | |
| const { data } = await this.workos.post< | |
| PortalLinkResponseWire, | |
| GenerateLinkResponse | |
| >('/portal/generate_link', serializeGenerateLink(options)); |
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!
Description
This PR generates the AdminPortal category in the Node SDK from the OpenAPI spec.
It renames one field:
Because of this, the PR should be treated as a breaking change.