@workos/oagen-emitters 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/.github/workflows/ci.yml +1 -1
  2. package/.github/workflows/lint.yml +1 -1
  3. package/.github/workflows/release-please.yml +2 -2
  4. package/.github/workflows/release.yml +1 -1
  5. package/.husky/pre-push +11 -0
  6. package/.node-version +1 -1
  7. package/.release-please-manifest.json +1 -1
  8. package/CHANGELOG.md +15 -0
  9. package/README.md +35 -224
  10. package/dist/index.d.mts +9 -1
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +2 -15234
  13. package/dist/plugin-Dws9b6T7.mjs +21441 -0
  14. package/dist/plugin-Dws9b6T7.mjs.map +1 -0
  15. package/dist/plugin.d.mts +7 -0
  16. package/dist/plugin.d.mts.map +1 -0
  17. package/dist/plugin.mjs +2 -0
  18. package/docs/sdk-architecture/dotnet.md +5 -5
  19. package/oagen.config.ts +5 -373
  20. package/package.json +17 -41
  21. package/smoke/sdk-dotnet.ts +11 -5
  22. package/smoke/sdk-elixir.ts +11 -5
  23. package/smoke/sdk-go.ts +10 -4
  24. package/smoke/sdk-kotlin.ts +11 -5
  25. package/smoke/sdk-node.ts +11 -5
  26. package/smoke/sdk-php.ts +9 -4
  27. package/smoke/sdk-python.ts +10 -4
  28. package/smoke/sdk-ruby.ts +10 -4
  29. package/smoke/sdk-rust.ts +11 -5
  30. package/src/dotnet/index.ts +9 -7
  31. package/src/dotnet/manifest.ts +5 -11
  32. package/src/dotnet/models.ts +58 -82
  33. package/src/dotnet/naming.ts +44 -6
  34. package/src/dotnet/resources.ts +350 -29
  35. package/src/dotnet/tests.ts +44 -24
  36. package/src/dotnet/type-map.ts +44 -17
  37. package/src/dotnet/wrappers.ts +21 -10
  38. package/src/go/client.ts +35 -3
  39. package/src/go/enums.ts +4 -0
  40. package/src/go/index.ts +13 -8
  41. package/src/go/manifest.ts +5 -11
  42. package/src/go/models.ts +6 -1
  43. package/src/go/resources.ts +534 -73
  44. package/src/go/tests.ts +39 -3
  45. package/src/go/type-map.ts +8 -3
  46. package/src/go/wrappers.ts +79 -21
  47. package/src/index.ts +14 -0
  48. package/src/kotlin/client.ts +7 -2
  49. package/src/kotlin/enums.ts +30 -3
  50. package/src/kotlin/index.ts +3 -3
  51. package/src/kotlin/manifest.ts +9 -15
  52. package/src/kotlin/models.ts +97 -6
  53. package/src/kotlin/naming.ts +7 -1
  54. package/src/kotlin/resources.ts +370 -39
  55. package/src/kotlin/tests.ts +120 -6
  56. package/src/node/client.ts +38 -11
  57. package/src/node/field-plan.ts +12 -14
  58. package/src/node/fixtures.ts +39 -3
  59. package/src/node/index.ts +3 -3
  60. package/src/node/manifest.ts +4 -11
  61. package/src/node/models.ts +281 -37
  62. package/src/node/resources.ts +156 -52
  63. package/src/node/tests.ts +76 -27
  64. package/src/node/type-map.ts +1 -31
  65. package/src/node/utils.ts +96 -6
  66. package/src/node/wrappers.ts +31 -1
  67. package/src/php/index.ts +3 -3
  68. package/src/php/manifest.ts +5 -11
  69. package/src/php/models.ts +0 -33
  70. package/src/php/resources.ts +199 -18
  71. package/src/php/tests.ts +26 -2
  72. package/src/php/type-map.ts +16 -2
  73. package/src/php/wrappers.ts +6 -2
  74. package/src/plugin.ts +50 -0
  75. package/src/python/client.ts +13 -3
  76. package/src/python/enums.ts +28 -3
  77. package/src/python/index.ts +38 -30
  78. package/src/python/manifest.ts +5 -12
  79. package/src/python/models.ts +138 -1
  80. package/src/python/resources.ts +234 -17
  81. package/src/python/tests.ts +260 -16
  82. package/src/python/type-map.ts +16 -2
  83. package/src/ruby/client.ts +238 -0
  84. package/src/ruby/enums.ts +149 -0
  85. package/src/ruby/index.ts +93 -0
  86. package/src/ruby/manifest.ts +28 -0
  87. package/src/ruby/models.ts +360 -0
  88. package/src/ruby/naming.ts +187 -0
  89. package/src/ruby/rbi.ts +313 -0
  90. package/src/ruby/resources.ts +799 -0
  91. package/src/ruby/tests.ts +459 -0
  92. package/src/ruby/type-map.ts +97 -0
  93. package/src/ruby/wrappers.ts +161 -0
  94. package/src/shared/model-utils.ts +131 -7
  95. package/src/shared/naming-utils.ts +36 -0
  96. package/src/shared/non-spec-services.ts +13 -0
  97. package/src/shared/resolved-ops.ts +75 -1
  98. package/test/dotnet/client.test.ts +2 -2
  99. package/test/dotnet/manifest.test.ts +13 -12
  100. package/test/dotnet/models.test.ts +7 -9
  101. package/test/dotnet/resources.test.ts +135 -3
  102. package/test/dotnet/tests.test.ts +5 -5
  103. package/test/entrypoint.test.ts +89 -0
  104. package/test/go/client.test.ts +6 -6
  105. package/test/go/resources.test.ts +156 -7
  106. package/test/kotlin/models.test.ts +1 -1
  107. package/test/kotlin/resources.test.ts +210 -0
  108. package/test/node/models.test.ts +134 -1
  109. package/test/node/resources.test.ts +134 -26
  110. package/test/node/utils.test.ts +140 -0
  111. package/test/php/models.test.ts +5 -4
  112. package/test/php/resources.test.ts +66 -1
  113. package/test/plugin.test.ts +50 -0
  114. package/test/python/client.test.ts +56 -0
  115. package/test/python/manifest.test.ts +7 -7
  116. package/test/python/models.test.ts +99 -0
  117. package/test/python/resources.test.ts +294 -0
  118. package/test/python/tests.test.ts +91 -0
  119. package/test/ruby/client.test.ts +81 -0
  120. package/test/ruby/resources.test.ts +386 -0
  121. package/test/shared/resolved-ops.test.ts +122 -0
  122. package/tsconfig.json +1 -0
  123. package/tsdown.config.ts +1 -1
  124. package/dist/index.mjs.map +0 -1
  125. package/scripts/generate-php.js +0 -13
  126. package/scripts/git-push-with-published-oagen.sh +0 -21
@@ -0,0 +1,7 @@
1
+ import { OagenConfig } from "@workos/oagen";
2
+
3
+ //#region src/plugin.d.ts
4
+ declare const workosEmittersPlugin: Pick<OagenConfig, 'emitters' | 'extractors' | 'smokeRunners'>;
5
+ //#endregion
6
+ export { workosEmittersPlugin };
7
+ //# sourceMappingURL=plugin.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.mts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;cAyBa,oBAAA,EAAsB,IAAA,CAAK,WAAA"}
@@ -0,0 +1,2 @@
1
+ import { t as workosEmittersPlugin } from "./plugin-Dws9b6T7.mjs";
2
+ export { workosEmittersPlugin };
@@ -226,11 +226,11 @@ public class WorkOSList<T>
226
226
 
227
227
  The runtime translates HTTP status codes to SDK-native exceptions:
228
228
 
229
- - `AuthenticationError` (401)
230
- - `NotFoundError` (404)
231
- - `UnprocessableEntityError` (422)
232
- - `RateLimitExceededError` (429)
233
- - `ServerError` (500+)
229
+ - `AuthenticationException` (401)
230
+ - `NotFoundException` (404)
231
+ - `UnprocessableEntityException` (422)
232
+ - `RateLimitExceededException` (429)
233
+ - `ServerException` (500+)
234
234
 
235
235
  These are hand-maintained in the runtime. The emitter generates error-handling _tests_, not the error classes themselves.
236
236
 
package/oagen.config.ts CHANGED
@@ -1,377 +1,9 @@
1
- import type { OagenConfig, OperationHint } from '@workos/oagen';
2
- import { toCamelCase } from '@workos/oagen';
3
- import { nodeEmitter } from './src/node/index.js';
4
- import { pythonEmitter } from './src/python/index.js';
5
- import { phpEmitter } from './src/php/index.js';
6
- import { goEmitter } from './src/go/index.js';
7
- import { dotnetEmitter } from './src/dotnet/index.js';
8
- import { kotlinEmitter } from './src/kotlin/index.js';
9
- import { nodeExtractor } from './src/compat/extractors/node.js';
10
- import { rubyExtractor } from './src/compat/extractors/ruby.js';
11
- import { pythonExtractor } from './src/compat/extractors/python.js';
12
- import { phpExtractor } from './src/compat/extractors/php.js';
13
- import { goExtractor } from './src/compat/extractors/go.js';
14
- import { rustExtractor } from './src/compat/extractors/rust.js';
15
- import { kotlinExtractor } from './src/compat/extractors/kotlin.js';
16
- import { dotnetExtractor } from './src/compat/extractors/dotnet.js';
17
- import { elixirExtractor } from './src/compat/extractors/elixir.js';
18
-
19
- /**
20
- * NestJS-style operationId transform. Strips "Controller" and extracts the
21
- * action after the first underscore: `FooController_bar` → `bar`.
22
- */
23
- function nestjsOperationIdTransform(id: string): string {
24
- const stripped = id.replace(/Controller/g, '');
25
- const idx = stripped.indexOf('_');
26
- return idx !== -1 ? toCamelCase(stripped.slice(idx + 1)) : toCamelCase(stripped);
27
- }
28
-
29
- // ---------------------------------------------------------------------------
30
- // Operation hints — per-operation overrides for the operation resolver.
31
- // Keyed by "METHOD /path". Only operations that need overrides are listed;
32
- // the algorithm handles the rest.
33
- // ---------------------------------------------------------------------------
34
- const operationHints: Record<string, OperationHint> = {
35
- // ── Radar ────────────────────────────────────────────────────────────────
36
- 'POST /radar/lists/{type}/{action}': { name: 'add_list_entry' },
37
- 'DELETE /radar/lists/{type}/{action}': { name: 'remove_list_entry' },
38
-
39
- // ── SSO ──────────────────────────────────────────────────────────────────
40
- 'GET /sso/authorize': {
41
- name: 'get_authorization_url',
42
- defaults: { response_type: 'code' },
43
- inferFromClient: ['client_id'],
44
- urlBuilder: true,
45
- },
46
- 'GET /sso/logout': { name: 'get_logout_url', urlBuilder: true },
47
- 'GET /sso/profile': { name: 'get_profile' },
48
- 'POST /sso/token': {
49
- name: 'get_profile_and_token',
50
- defaults: { grant_type: 'authorization_code' },
51
- inferFromClient: ['client_id', 'client_secret'],
52
- },
53
-
54
- // ── SSO / JWKS (mounted on UserManagement via mountRules) ────────────────
55
- 'GET /sso/jwks/{clientId}': { name: 'get_jwks' },
56
-
57
- // ── User Management — auth ──────────────────────────────────────────────
58
- 'GET /user_management/authorize': {
59
- name: 'get_authorization_url',
60
- defaults: { response_type: 'code' },
61
- inferFromClient: ['client_id'],
62
- urlBuilder: true,
63
- },
64
- 'GET /user_management/sessions/logout': { name: 'get_logout_url', urlBuilder: true },
65
-
66
- // ── User Management — org membership actions ────────────────────────────
67
- 'PUT /user_management/organization_memberships/{id}/deactivate': {
68
- name: 'deactivate_organization_membership',
69
- },
70
- 'PUT /user_management/organization_memberships/{id}/reactivate': {
71
- name: 'reactivate_organization_membership',
72
- },
73
-
74
- // ── Admin Portal ────────────────────────────────────────────────────────
75
- 'POST /portal/generate_link': { name: 'generate_link' },
76
-
77
- // ── Feature Flags — disambiguate co-mounted list operations ─────────────
78
- 'GET /organizations/{organizationId}/feature-flags': { name: 'list_organization_feature_flags' },
79
- 'GET /user_management/users/{userId}/feature-flags': { name: 'list_user_feature_flags' },
80
-
81
- // ── External ID lookups (not derivable from path) ──────────────────────
82
- 'GET /organizations/external_id/{external_id}': { name: 'get_organization_by_external_id' },
83
- 'GET /user_management/users/external_id/{external_id}': { name: 'get_user_by_external_id' },
84
-
85
- // ── Authorization — environment-scoped roles ─────────────────────────────
86
- 'GET /authorization/roles': { name: 'list_environment_roles' },
87
- 'POST /authorization/roles': { name: 'create_environment_role' },
88
- 'GET /authorization/roles/{slug}': { name: 'get_environment_role' },
89
- 'PATCH /authorization/roles/{slug}': { name: 'update_environment_role' },
90
- 'PUT /authorization/roles/{slug}/permissions': {
91
- name: 'set_environment_role_permissions',
92
- },
93
- 'POST /authorization/roles/{slug}/permissions': {
94
- name: 'add_environment_role_permission',
95
- },
96
-
97
- // ── Authorization — singularized/shortened names ────────────────────────
98
- 'POST /authorization/permissions': { name: 'create_permission' },
99
- 'POST /authorization/resources': { name: 'create_resource' },
100
- 'POST /authorization/organization_memberships/{organization_membership_id}/check': {
101
- name: 'check',
102
- },
103
- 'POST /authorization/organization_memberships/{organization_membership_id}/role_assignments': {
104
- name: 'assign_role',
105
- },
106
- 'DELETE /authorization/organization_memberships/{organization_membership_id}/role_assignments': {
107
- name: 'remove_role',
108
- },
109
- 'POST /authorization/organizations/{organizationId}/roles': {
110
- name: 'create_organization_role',
111
- },
112
-
113
- // ── Authorization — env-scoped resource memberships ────────────────────
114
- 'GET /authorization/resources/{resource_id}/organization_memberships': { name: 'list_memberships_for_resource' },
115
-
116
- // ── User Management — singularized/shortened names ─────────────────────
117
- 'POST /user_management/users': { name: 'create_user' },
118
- 'POST /user_management/organization_memberships': {
119
- name: 'create_organization_membership',
120
- },
121
- 'POST /user_management/invitations': { name: 'send_invitation' },
122
- 'GET /user_management/invitations/by_token/{token}': {
123
- name: 'find_invitation_by_token',
124
- },
125
- 'POST /user_management/users/{id}/email_verification/send': {
126
- name: 'send_verification_email',
127
- },
128
- 'POST /user_management/users/{id}/email_verification/confirm': {
129
- name: 'verify_email',
130
- },
131
- 'POST /user_management/password_reset': { name: 'reset_password' },
132
- 'POST /user_management/password_reset/confirm': {
133
- name: 'confirm_password_reset',
134
- },
135
- 'GET /user_management/users/{id}/sessions': { name: 'list_sessions' },
136
- 'GET /user_management/users/{id}/identities': { name: 'get_user_identities' },
137
- 'POST /user_management/cors_origins': { name: 'create_cors_origin' },
138
- 'POST /user_management/redirect_uris': { name: 'create_redirect_uri' },
139
-
140
- // ── Organizations — singularized names ─────────────────────────────────
141
- 'POST /organizations': { name: 'create_organization' },
142
-
143
- // ── Directory Sync — shortened names ───────────────────────────────────
144
- 'GET /directory_groups': { name: 'list_groups' },
145
- 'GET /directory_groups/{id}': { name: 'get_group' },
146
- 'GET /directory_users': { name: 'list_users' },
147
- 'GET /directory_users/{id}': { name: 'get_user' },
148
-
149
- // ── Audit Logs — singularized names ────────────────────────────────────
150
- 'POST /audit_logs/events': { name: 'create_event' },
151
- 'POST /audit_logs/exports': { name: 'create_export' },
152
- 'POST /audit_logs/actions/{actionName}/schemas': { name: 'create_schema' },
153
-
154
- // ── Feature Flags — match SDK conventions ──────────────────────────────
155
- 'POST /feature-flags/{slug}/targets/{resourceId}': { name: 'add_flag_target' },
156
- 'DELETE /feature-flags/{slug}/targets/{resourceId}': {
157
- name: 'remove_flag_target',
158
- },
159
-
160
- // ── Organizations — audit log config (singular fetch, not a list) ───────
161
- 'GET /organizations/{id}/audit_log_configuration': {
162
- name: 'get_audit_log_configuration',
163
- },
164
-
165
- // ── Organizations — audit logs retention (mounted on AuditLogs) ─────────
166
- 'GET /organizations/{id}/audit_logs_retention': {
167
- name: 'get_organization_audit_logs_retention',
168
- mountOn: 'AuditLogs',
169
- },
170
- 'PUT /organizations/{id}/audit_logs_retention': { mountOn: 'AuditLogs' },
171
-
172
- // ── Union split: POST /user_management/authenticate (8 variants) ────────
173
- // Common optional fields appended to every variant's exposedParams so the
174
- // generated wrappers cover the full spec body shape (fraud/audit context the
175
- // server consumes when present).
176
- 'POST /user_management/authenticate': {
177
- split: [
178
- {
179
- name: 'authenticate_with_password',
180
- targetVariant: 'PasswordSessionAuthenticateRequest',
181
- defaults: { grant_type: 'password' },
182
- inferFromClient: ['client_id', 'client_secret'],
183
- exposedParams: ['email', 'password', 'invitation_token', 'ip_address', 'device_id', 'user_agent'],
184
- optionalParams: ['invitation_token', 'ip_address', 'device_id', 'user_agent'],
185
- },
186
- {
187
- name: 'authenticate_with_code',
188
- targetVariant: 'CodeSessionAuthenticateRequest',
189
- defaults: { grant_type: 'authorization_code' },
190
- inferFromClient: ['client_id', 'client_secret'],
191
- exposedParams: ['code', 'ip_address', 'device_id', 'user_agent'],
192
- optionalParams: ['ip_address', 'device_id', 'user_agent'],
193
- },
194
- {
195
- name: 'authenticate_with_refresh_token',
196
- targetVariant: 'RefreshTokenSessionAuthenticateRequest',
197
- defaults: { grant_type: 'refresh_token' },
198
- inferFromClient: ['client_id', 'client_secret'],
199
- exposedParams: ['refresh_token', 'organization_id', 'ip_address', 'device_id', 'user_agent'],
200
- optionalParams: ['organization_id', 'ip_address', 'device_id', 'user_agent'],
201
- },
202
- {
203
- name: 'authenticate_with_magic_auth',
204
- targetVariant: 'MagicAuthSessionAuthenticateRequest',
205
- defaults: { grant_type: 'urn:workos:oauth:grant-type:magic-auth:code' },
206
- inferFromClient: ['client_id', 'client_secret'],
207
- exposedParams: ['code', 'email', 'invitation_token', 'ip_address', 'device_id', 'user_agent'],
208
- optionalParams: ['invitation_token', 'ip_address', 'device_id', 'user_agent'],
209
- },
210
- {
211
- name: 'authenticate_with_email_verification',
212
- targetVariant: 'EmailVerificationSessionAuthenticateRequest',
213
- defaults: { grant_type: 'urn:workos:oauth:grant-type:email-verification:code' },
214
- inferFromClient: ['client_id', 'client_secret'],
215
- exposedParams: ['code', 'pending_authentication_token', 'ip_address', 'device_id', 'user_agent'],
216
- optionalParams: ['pending_authentication_token', 'ip_address', 'device_id', 'user_agent'],
217
- },
218
- {
219
- name: 'authenticate_with_totp',
220
- targetVariant: 'TotpSessionAuthenticateRequest',
221
- defaults: { grant_type: 'urn:workos:oauth:grant-type:mfa-totp' },
222
- inferFromClient: ['client_id', 'client_secret'],
223
- exposedParams: [
224
- 'code',
225
- 'pending_authentication_token',
226
- 'authentication_challenge_id',
227
- 'ip_address',
228
- 'device_id',
229
- 'user_agent',
230
- ],
231
- optionalParams: ['ip_address', 'device_id', 'user_agent'],
232
- },
233
- {
234
- name: 'authenticate_with_organization_selection',
235
- targetVariant: 'OrganizationSelectionSessionAuthenticateRequest',
236
- defaults: { grant_type: 'urn:workos:oauth:grant-type:organization-selection' },
237
- inferFromClient: ['client_id', 'client_secret'],
238
- exposedParams: ['pending_authentication_token', 'organization_id', 'ip_address', 'device_id', 'user_agent'],
239
- optionalParams: ['ip_address', 'device_id', 'user_agent'],
240
- },
241
- {
242
- name: 'authenticate_with_device_code',
243
- targetVariant: 'DeviceCodeSessionAuthenticateRequest',
244
- defaults: { grant_type: 'urn:ietf:params:oauth:grant-type:device_code' },
245
- inferFromClient: ['client_id'],
246
- exposedParams: ['device_code', 'ip_address', 'device_id', 'user_agent'],
247
- optionalParams: ['ip_address', 'device_id', 'user_agent'],
248
- },
249
- ],
250
- },
251
-
252
- // ── Union split: POST /connect/applications (2 variants) ────────────────
253
- 'POST /connect/applications': {
254
- split: [
255
- {
256
- name: 'create_oauth_application',
257
- targetVariant: 'CreateOAuthApplication',
258
- defaults: { application_type: 'oauth' },
259
- exposedParams: [
260
- 'name',
261
- 'is_first_party',
262
- 'description',
263
- 'scopes',
264
- 'redirect_uris',
265
- 'uses_pkce',
266
- 'organization_id',
267
- ],
268
- },
269
- {
270
- name: 'create_m2m_application',
271
- targetVariant: 'CreateM2MApplication',
272
- defaults: { application_type: 'm2m' },
273
- exposedParams: ['name', 'organization_id', 'description', 'scopes'],
274
- },
275
- ],
276
- },
277
- };
278
-
279
- // ---------------------------------------------------------------------------
280
- // Mount rules — service-level remounting. Maps IR service name → target
281
- // service/namespace (PascalCase). All operations in the source service are
282
- // mounted on the target unless overridden per-operation in operationHints.
283
- // ---------------------------------------------------------------------------
284
- const mountRules: Record<string, string> = {
285
- // MFA sub-services → MultiFactorAuth
286
- MultiFactorAuthChallenges: 'MultiFactorAuth',
287
-
288
- // RBAC permissions → Authorization
289
- Permissions: 'Authorization',
290
-
291
- // Connect sub-services → Connect
292
- WorkosConnect: 'Connect',
293
- Applications: 'Connect',
294
- ApplicationClientSecrets: 'Connect',
295
-
296
- // SSO connections → SSO
297
- Connections: 'SSO',
298
-
299
- // Directory Sync sub-services → DirectorySync
300
- Directories: 'DirectorySync',
301
- DirectoryGroups: 'DirectorySync',
302
- DirectoryUsers: 'DirectorySync',
303
-
304
- // Feature flag sub-services → FeatureFlags
305
- FeatureFlagsTargets: 'FeatureFlags',
306
- OrganizationsFeatureFlags: 'FeatureFlags',
307
- UserManagementUsersFeatureFlags: 'FeatureFlags',
308
-
309
- // Org API keys → ApiKeys
310
- OrganizationsApiKeys: 'ApiKeys',
311
-
312
- // User Management sub-services → UserManagement
313
- UserManagementSessionTokens: 'UserManagement',
314
- UserManagementAuthentication: 'UserManagement',
315
- UserManagementCorsOrigins: 'UserManagement',
316
- UserManagementUsers: 'UserManagement',
317
- UserManagementInvitations: 'UserManagement',
318
- UserManagementJWTTemplate: 'UserManagement',
319
- UserManagementMagicAuth: 'UserManagement',
320
- UserManagementOrganizationMembership: 'UserManagement',
321
- UserManagementRedirectUris: 'UserManagement',
322
- UserManagementUsersAuthorizedApplications: 'UserManagement',
323
-
324
- // Pipes / Data Providers → Pipes
325
- UserManagementDataProviders: 'Pipes',
326
-
327
- // User Management MFA → MultiFactorAuth
328
- UserManagementMultiFactorAuthentication: 'MultiFactorAuth',
329
- };
1
+ import type { OagenConfig } from '@workos/oagen';
2
+ import { workosEmittersPlugin } from './src/plugin.js';
330
3
 
4
+ // Minimal config for local emitter development.
5
+ // The canonical consumer config lives in openapi-spec/oagen.config.ts.
331
6
  const config: OagenConfig = {
332
- emitters: [nodeEmitter, pythonEmitter, phpEmitter, goEmitter, dotnetEmitter, kotlinEmitter],
333
- extractors: [
334
- nodeExtractor,
335
- rubyExtractor,
336
- pythonExtractor,
337
- phpExtractor,
338
- goExtractor,
339
- rustExtractor,
340
- kotlinExtractor,
341
- dotnetExtractor,
342
- elixirExtractor,
343
- ],
344
- smokeRunners: {
345
- node: './smoke/sdk-node.ts',
346
- ruby: './smoke/sdk-ruby.ts',
347
- python: './smoke/sdk-python.ts',
348
- php: './smoke/sdk-php.ts',
349
- go: './smoke/sdk-go.ts',
350
- rust: './smoke/sdk-rust.ts',
351
- elixir: './smoke/sdk-elixir.ts',
352
- kotlin: './smoke/sdk-kotlin.ts',
353
- dotnet: './smoke/sdk-dotnet.ts',
354
- },
355
- docUrl: 'https://workos.com/docs',
356
- operationIdTransform: nestjsOperationIdTransform,
357
- schemaNameTransform: (name: string) => {
358
- // Explicit renames for Dto models that collide with response models
359
- const COLLISION_RENAMES: Record<string, string> = {
360
- OrganizationDto: 'OrganizationInput',
361
- RedirectUriDto: 'RedirectUriInput',
362
- // Generic list-derived names that need domain-specific identifiers
363
- ListData: 'Role',
364
- ListModel: 'RoleList',
365
- // Double-List naming artifact
366
- EventListListMetadata: 'EventListMetadata',
367
- };
368
- if (COLLISION_RENAMES[name]) return COLLISION_RENAMES[name];
369
- return name
370
- .replace(/Dto/g, '')
371
- .replace(/DTO/g, '')
372
- .replace(/^Urn(?:IetfParams|Workos)O[Aa]uthGrantType/, '');
373
- },
374
- operationHints,
375
- mountRules,
7
+ ...workosEmittersPlugin,
376
8
  };
377
9
  export default config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos/oagen-emitters",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "WorkOS' oagen emitters",
5
5
  "license": "MIT",
6
6
  "author": "WorkOS",
@@ -15,6 +15,10 @@
15
15
  ".": {
16
16
  "types": "./dist/index.d.mts",
17
17
  "import": "./dist/index.mjs"
18
+ },
19
+ "./plugin": {
20
+ "types": "./dist/plugin.d.mts",
21
+ "import": "./dist/plugin.mjs"
18
22
  }
19
23
  },
20
24
  "scripts": {
@@ -28,56 +32,28 @@
28
32
  "test": "vitest run",
29
33
  "test:watch": "vitest",
30
34
  "typecheck": "tsc --noEmit",
31
- "git:push": "sh ./scripts/git-push-with-published-oagen.sh",
32
35
  "oagen:build:local": "npm --prefix ../oagen run build",
33
- "oagen:use:local": "npm run oagen:build:local && npm link ../oagen",
34
- "oagen:use:published": "sh -c 'npm unlink @workos/oagen >/dev/null 2>&1 || true; npm install --ignore-scripts @workos/oagen@^0.4.0'",
35
- "prepare": "husky",
36
- "sdk:generate:dotnet": "oagen generate --lang dotnet --output ./sdk-dotnet --namespace workos --api-surface ./sdk-dotnet-surface.json",
37
- "sdk:verify:dotnet": "oagen verify --lang dotnet --output ./sdk-dotnet --api-surface ./sdk-dotnet-surface.json",
38
- "sdk:extract:dotnet": "oagen extract --lang dotnet --sdk-path ../backend/workos-dotnet --output ./sdk-dotnet-surface.json",
39
- "sdk:generate:elixir": "oagen generate --lang elixir --output ./sdk-elixir --namespace workos --api-surface ./sdk-elixir-surface.json",
40
- "sdk:verify:elixir": "oagen verify --lang elixir --output ./sdk-elixir --api-surface ./sdk-elixir-surface.json",
41
- "sdk:extract:elixir": "oagen extract --lang elixir --sdk-path ../backend/workos-elixir --output ./sdk-elixir-surface.json",
42
- "sdk:generate:go": "oagen generate --lang go --output ./sdk-go --namespace workos --api-surface ./sdk-go-surface.json",
43
- "sdk:verify:go": "oagen verify --lang go --output ./sdk-go --api-surface ./sdk-go-surface.json",
44
- "sdk:extract:go": "oagen extract --lang go --sdk-path ../backend/workos-go --output ./sdk-go-surface.json",
45
- "sdk:generate:kotlin": "oagen generate --lang kotlin --output ./sdk-kotlin --namespace workos --api-surface ./sdk-kotlin-surface.json",
46
- "sdk:verify:kotlin": "oagen verify --lang kotlin --output ./sdk-kotlin --api-surface ./sdk-kotlin-surface.json",
47
- "sdk:extract:kotlin": "oagen extract --lang kotlin --sdk-path ../backend/workos-kotlin --output ./sdk-kotlin-surface.json",
48
- "sdk:generate:node": "oagen generate --lang node --output ./sdk-node --namespace workos --api-surface ./sdk-node-surface.json",
49
- "sdk:verify:node": "oagen verify --lang node --output ./sdk-node --api-surface ./sdk-node-surface.json",
50
- "sdk:extract:node": "oagen extract --lang node --sdk-path ../backend/workos-node --output ./sdk-node-surface.json",
51
- "sdk:generate:php": "node scripts/generate-php.js",
52
- "sdk:verify:php": "oagen verify --lang php --output ./sdk-php --api-surface ./sdk-php-surface.json",
53
- "sdk:extract:php": "oagen extract --lang php --sdk-path ../backend/workos-php --output ./sdk-php-surface.json",
54
- "sdk:generate:python": "oagen generate --lang python --output ./sdk-python --namespace workos --api-surface ./sdk-python-surface.json",
55
- "sdk:verify:python": "oagen verify --lang python --output ./sdk-python --api-surface ./sdk-python-surface.json",
56
- "sdk:extract:python": "oagen extract --lang python --sdk-path ../backend/workos-python --output ./sdk-python-surface.json",
57
- "sdk:generate:ruby": "oagen generate --lang ruby --output ./sdk-ruby --namespace workos --api-surface ./sdk-ruby-surface.json",
58
- "sdk:verify:ruby": "oagen verify --lang ruby --output ./sdk-ruby --api-surface ./sdk-ruby-surface.json",
59
- "sdk:extract:ruby": "oagen extract --lang ruby --sdk-path ../backend/workos-ruby --output ./sdk-ruby-surface.json",
60
- "sdk:generate:rust": "oagen generate --lang rust --output ./sdk-rust --namespace workos --api-surface ./sdk-rust-surface.json",
61
- "sdk:verify:rust": "oagen verify --lang rust --output ./sdk-rust --api-surface ./sdk-rust-surface.json",
62
- "sdk:extract:rust": "oagen extract --lang rust --sdk-path ../backend/workos-rust --output ./sdk-rust-surface.json"
36
+ "dev:link": "npm run oagen:build:local && npm link --prefix ../oagen && npm link @workos/oagen",
37
+ "dev:unlink": "npm install",
38
+ "prepare": "husky"
63
39
  },
64
40
  "devDependencies": {
65
41
  "@commitlint/cli": "^20.5.0",
66
42
  "@commitlint/config-conventional": "^20.5.0",
67
- "@types/node": "^25.3.3",
43
+ "@types/node": "^25.6.0",
68
44
  "husky": "^9.1.7",
69
- "oxfmt": "^0.36.0",
70
- "oxlint": "^1.51.0",
71
- "prettier": "^3.8.1",
72
- "tsdown": "^0.21.5",
73
- "tsx": "^4.19.0",
74
- "typescript": "^6.0.0-dev.20260324",
75
- "vitest": "^3.0.0"
45
+ "oxfmt": "^0.46.0",
46
+ "oxlint": "^1.61.0",
47
+ "prettier": "^3.8.3",
48
+ "tsdown": "^0.21.10",
49
+ "tsx": "^4.21.0",
50
+ "typescript": "^6.0.3",
51
+ "vitest": "^4.1.5"
76
52
  },
77
53
  "engines": {
78
54
  "node": ">=24.10.0"
79
55
  },
80
56
  "dependencies": {
81
- "@workos/oagen": "^0.6.0"
57
+ "@workos/oagen": "^0.9.0"
82
58
  }
83
59
  }
@@ -152,15 +152,21 @@ function createProxyServer(apiKey: string, captures: ProxyCapture[]): Promise<{
152
152
  // ---------------------------------------------------------------------------
153
153
 
154
154
  function loadManifest(sdkPath: string): Map<string, ManifestEntry> | null {
155
- const manifestPath = resolve(sdkPath, 'smoke-manifest.json');
155
+ const manifestPath = resolve(sdkPath, '.oagen-manifest.json');
156
156
  if (!existsSync(manifestPath)) {
157
- console.warn(`Warning: No smoke-manifest.json found at ${manifestPath}`);
158
- console.warn(' Method resolution will rely on heuristic tiers most operations may be skipped.');
157
+ console.warn(`Warning: No .oagen-manifest.json found at ${manifestPath}`);
158
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
159
+ return null;
160
+ }
161
+ const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));
162
+ const operations = parsed?.operations;
163
+ if (!operations || typeof operations !== 'object') {
164
+ console.warn('Warning: .oagen-manifest.json has no operations field');
165
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
159
166
  return null;
160
167
  }
161
- const raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));
162
168
  const manifest = new Map<string, ManifestEntry>();
163
- for (const [httpKey, entry] of Object.entries(raw)) {
169
+ for (const [httpKey, entry] of Object.entries(operations)) {
164
170
  manifest.set(httpKey, entry as ManifestEntry);
165
171
  }
166
172
  return manifest;
@@ -196,15 +196,21 @@ function startProxy(
196
196
  // ---------------------------------------------------------------------------
197
197
 
198
198
  function loadManifest(sdkPath: string): Map<string, ManifestEntry> | null {
199
- const manifestPath = resolve(sdkPath, 'smoke-manifest.json');
199
+ const manifestPath = resolve(sdkPath, '.oagen-manifest.json');
200
200
  if (!existsSync(manifestPath)) {
201
- console.warn(`Warning: No smoke-manifest.json found at ${manifestPath}`);
202
- console.warn(' Method resolution will rely on heuristic tiers most operations may be skipped.');
201
+ console.warn(`Warning: No .oagen-manifest.json found at ${manifestPath}`);
202
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
203
+ return null;
204
+ }
205
+ const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));
206
+ const operations = parsed?.operations;
207
+ if (!operations || typeof operations !== 'object') {
208
+ console.warn('Warning: .oagen-manifest.json has no operations field');
209
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
203
210
  return null;
204
211
  }
205
- const raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));
206
212
  const manifest = new Map<string, ManifestEntry>();
207
- for (const [httpKey, entry] of Object.entries(raw)) {
213
+ for (const [httpKey, entry] of Object.entries(operations)) {
208
214
  manifest.set(httpKey, entry as ManifestEntry);
209
215
  }
210
216
  return manifest;
package/smoke/sdk-go.ts CHANGED
@@ -126,15 +126,21 @@ function goFieldName(name: string): string {
126
126
  // ---------------------------------------------------------------------------
127
127
 
128
128
  function loadManifest(sdkPath: string): Map<string, ManifestEntry> | null {
129
- const manifestPath = resolve(sdkPath, 'smoke-manifest.json');
129
+ const manifestPath = resolve(sdkPath, '.oagen-manifest.json');
130
130
  if (!existsSync(manifestPath)) {
131
- console.warn(`Warning: No smoke-manifest.json found at ${manifestPath}`);
131
+ console.warn(`Warning: No .oagen-manifest.json found at ${manifestPath}`);
132
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
133
+ return null;
134
+ }
135
+ const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));
136
+ const operations = parsed?.operations;
137
+ if (!operations || typeof operations !== 'object') {
138
+ console.warn('Warning: .oagen-manifest.json has no operations field');
132
139
  console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
133
140
  return null;
134
141
  }
135
- const raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));
136
142
  const manifest = new Map<string, ManifestEntry>();
137
- for (const [httpKey, entry] of Object.entries(raw)) {
143
+ for (const [httpKey, entry] of Object.entries(operations)) {
138
144
  manifest.set(httpKey, entry as ManifestEntry);
139
145
  }
140
146
  return manifest;
@@ -175,15 +175,21 @@ function createProxyServer(
175
175
  // ---------------------------------------------------------------------------
176
176
 
177
177
  function loadManifest(sdkPath: string): Map<string, ManifestEntry> | null {
178
- const manifestPath = resolve(sdkPath, 'smoke-manifest.json');
178
+ const manifestPath = resolve(sdkPath, '.oagen-manifest.json');
179
179
  if (!existsSync(manifestPath)) {
180
- console.warn(`Warning: No smoke-manifest.json found at ${manifestPath}`);
181
- console.warn(' Method resolution will rely on heuristic tiers most operations may be skipped.');
180
+ console.warn(`Warning: No .oagen-manifest.json found at ${manifestPath}`);
181
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
182
+ return null;
183
+ }
184
+ const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));
185
+ const operations = parsed?.operations;
186
+ if (!operations || typeof operations !== 'object') {
187
+ console.warn('Warning: .oagen-manifest.json has no operations field');
188
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
182
189
  return null;
183
190
  }
184
- const raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));
185
191
  const manifest = new Map<string, ManifestEntry>();
186
- for (const [httpKey, entry] of Object.entries(raw)) {
192
+ for (const [httpKey, entry] of Object.entries(operations)) {
187
193
  manifest.set(httpKey, entry as ManifestEntry);
188
194
  }
189
195
  return manifest;
package/smoke/sdk-node.ts CHANGED
@@ -107,15 +107,21 @@ function restoreFetch(): void {
107
107
  // ---------------------------------------------------------------------------
108
108
 
109
109
  function loadManifest(sdkPath: string): Map<string, ManifestEntry> | null {
110
- const manifestPath = resolve(sdkPath, 'smoke-manifest.json');
110
+ const manifestPath = resolve(sdkPath, '.oagen-manifest.json');
111
111
  if (!existsSync(manifestPath)) {
112
- console.warn(`⚠ No smoke-manifest.json found at ${manifestPath}`);
113
- console.warn(' Method resolution will rely on heuristic tiers most operations may be skipped.');
112
+ console.warn(`Warning: No .oagen-manifest.json found at ${manifestPath}`);
113
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
114
+ return null;
115
+ }
116
+ const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));
117
+ const operations = parsed?.operations;
118
+ if (!operations || typeof operations !== 'object') {
119
+ console.warn('Warning: .oagen-manifest.json has no operations field');
120
+ console.warn(' Method resolution will rely on heuristic tiers -- most operations may be skipped.');
114
121
  return null;
115
122
  }
116
- const raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));
117
123
  const manifest = new Map<string, ManifestEntry>();
118
- for (const [httpKey, entry] of Object.entries(raw)) {
124
+ for (const [httpKey, entry] of Object.entries(operations)) {
119
125
  manifest.set(httpKey, entry as ManifestEntry);
120
126
  }
121
127
  return manifest;