@workos/oagen-emitters 0.0.1
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.
- package/.github/workflows/ci.yml +20 -0
- package/.github/workflows/lint-pr-title.yml +16 -0
- package/.github/workflows/lint.yml +21 -0
- package/.github/workflows/release-please.yml +28 -0
- package/.github/workflows/release.yml +32 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +1 -0
- package/.node-version +1 -0
- package/.oxfmtrc.json +10 -0
- package/.oxlintrc.json +29 -0
- package/.vscode/settings.json +11 -0
- package/LICENSE.txt +21 -0
- package/README.md +123 -0
- package/commitlint.config.ts +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2158 -0
- package/docs/endpoint-coverage.md +275 -0
- package/docs/sdk-architecture/node.md +355 -0
- package/oagen.config.ts +51 -0
- package/package.json +83 -0
- package/renovate.json +26 -0
- package/smoke/sdk-dotnet.ts +903 -0
- package/smoke/sdk-elixir.ts +771 -0
- package/smoke/sdk-go.ts +948 -0
- package/smoke/sdk-kotlin.ts +799 -0
- package/smoke/sdk-node.ts +516 -0
- package/smoke/sdk-php.ts +699 -0
- package/smoke/sdk-python.ts +738 -0
- package/smoke/sdk-ruby.ts +723 -0
- package/smoke/sdk-rust.ts +774 -0
- package/src/compat/extractors/dotnet.ts +8 -0
- package/src/compat/extractors/elixir.ts +8 -0
- package/src/compat/extractors/go.ts +8 -0
- package/src/compat/extractors/kotlin.ts +8 -0
- package/src/compat/extractors/node.ts +8 -0
- package/src/compat/extractors/php.ts +8 -0
- package/src/compat/extractors/python.ts +8 -0
- package/src/compat/extractors/ruby.ts +8 -0
- package/src/compat/extractors/rust.ts +8 -0
- package/src/index.ts +1 -0
- package/src/node/client.ts +356 -0
- package/src/node/common.ts +203 -0
- package/src/node/config.ts +70 -0
- package/src/node/enums.ts +87 -0
- package/src/node/errors.ts +205 -0
- package/src/node/fixtures.ts +139 -0
- package/src/node/index.ts +57 -0
- package/src/node/manifest.ts +23 -0
- package/src/node/models.ts +323 -0
- package/src/node/naming.ts +96 -0
- package/src/node/resources.ts +380 -0
- package/src/node/serializers.ts +286 -0
- package/src/node/tests.ts +336 -0
- package/src/node/type-map.ts +56 -0
- package/src/node/utils.ts +164 -0
- package/test/compat/extractors/node.test.ts +145 -0
- package/test/fixtures/sample-sdk-node/package.json +7 -0
- package/test/fixtures/sample-sdk-node/src/client.ts +24 -0
- package/test/fixtures/sample-sdk-node/src/index.ts +4 -0
- package/test/fixtures/sample-sdk-node/src/models.ts +28 -0
- package/test/fixtures/sample-sdk-node/tsconfig.json +13 -0
- package/test/node/client.test.ts +165 -0
- package/test/node/enums.test.ts +128 -0
- package/test/node/errors.test.ts +65 -0
- package/test/node/models.test.ts +301 -0
- package/test/node/naming.test.ts +212 -0
- package/test/node/resources.test.ts +260 -0
- package/test/node/serializers.test.ts +206 -0
- package/test/node/type-map.test.ts +127 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +8 -0
- package/vitest.config.ts +4 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Endpoint Coverage: OpenAPI Spec vs Generated SDK vs workos-node
|
|
2
|
+
|
|
3
|
+
Comparison of HTTP verb + path pairs across three sources, with path parameters normalized to `{}`.
|
|
4
|
+
|
|
5
|
+
- **Spec**: OpenAPI spec baseline (from `smoke-results-spec-baseline.json`)
|
|
6
|
+
- **Gen SDK**: Generated SDK in `./sdk` (from `smoke-results-sdk-node.json`)
|
|
7
|
+
- **workos-node**: Live SDK at `/workos-node` (extracted via static analysis of `this.workos.<verb>()` calls)
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
| Source | Endpoints |
|
|
12
|
+
| ------------- | --------- |
|
|
13
|
+
| OpenAPI Spec | 154 |
|
|
14
|
+
| Generated SDK | 154 |
|
|
15
|
+
| workos-node | 134 |
|
|
16
|
+
| **In all 3** | **114** |
|
|
17
|
+
|
|
18
|
+
## Full Comparison
|
|
19
|
+
|
|
20
|
+
| Endpoint | Spec | Gen SDK | workos-node |
|
|
21
|
+
| ------------------------------------------------------------------------------ | :--: | :-----: | :---------: |
|
|
22
|
+
| `DELETE /api_keys/{}` | Y | Y | Y |
|
|
23
|
+
| `DELETE /auth/factors/{}` | Y | Y | Y |
|
|
24
|
+
| `DELETE /authorization/organization_memberships/{}/role_assignments` | Y | Y | Y |
|
|
25
|
+
| `DELETE /authorization/organization_memberships/{}/role_assignments/{}` | Y | Y | Y |
|
|
26
|
+
| `DELETE /authorization/organizations/{}/resources/{}/{}` | Y | Y | Y |
|
|
27
|
+
| `DELETE /authorization/organizations/{}/roles/{}` | Y | Y | Y |
|
|
28
|
+
| `DELETE /authorization/organizations/{}/roles/{}/permissions/{}` | Y | Y | Y |
|
|
29
|
+
| `DELETE /authorization/permissions/{}` | Y | Y | Y |
|
|
30
|
+
| `DELETE /authorization/resources/{}` | Y | Y | Y |
|
|
31
|
+
| `DELETE /connect/applications/{}` | Y | Y | Y |
|
|
32
|
+
| `DELETE /connect/client_secrets/{}` | Y | Y | Y |
|
|
33
|
+
| `DELETE /connections/{}` | Y | Y | Y |
|
|
34
|
+
| `DELETE /directories/{}` | Y | Y | Y |
|
|
35
|
+
| `DELETE /feature-flags/{}/targets/{}` | Y | Y | Y |
|
|
36
|
+
| `DELETE /fga/v1/resources/{}/{}` | | | Y |
|
|
37
|
+
| `DELETE /organization_domains/{}` | Y | Y | Y |
|
|
38
|
+
| `DELETE /organizations/{}` | Y | Y | Y |
|
|
39
|
+
| `DELETE /radar/lists/{}/{}` | Y | Y | Y |
|
|
40
|
+
| `DELETE /user_management/organization_memberships/{}` | Y | Y | Y |
|
|
41
|
+
| `DELETE /user_management/users/{}` | Y | Y | Y |
|
|
42
|
+
| `DELETE /user_management/users/{}/authorized_applications/{}` | Y | Y | |
|
|
43
|
+
| `DELETE /user_management/users/{}/connected_accounts/{}` | Y | Y | |
|
|
44
|
+
| `DELETE /vault/v1/kv/{}` | | | Y |
|
|
45
|
+
| `DELETE /webhook_endpoints/{}` | Y | Y | Y |
|
|
46
|
+
| `GET /audit_logs/actions` | Y | Y | |
|
|
47
|
+
| `GET /audit_logs/actions/{}/schemas` | Y | Y | |
|
|
48
|
+
| `GET /audit_logs/exports/{}` | Y | Y | Y |
|
|
49
|
+
| `GET /auth/factors/{}` | Y | Y | Y |
|
|
50
|
+
| `GET /authorization/organization_memberships/{}/resources` | Y | Y | Y |
|
|
51
|
+
| `GET /authorization/organization_memberships/{}/role_assignments` | Y | Y | Y |
|
|
52
|
+
| `GET /authorization/organizations/{}/resources/{}/{}` | Y | Y | Y |
|
|
53
|
+
| `GET /authorization/organizations/{}/resources/{}/{}/organization_memberships` | Y | Y | Y |
|
|
54
|
+
| `GET /authorization/organizations/{}/roles` | Y | Y | Y |
|
|
55
|
+
| `GET /authorization/organizations/{}/roles/{}` | Y | Y | Y |
|
|
56
|
+
| `GET /authorization/permissions` | Y | Y | Y |
|
|
57
|
+
| `GET /authorization/permissions/{}` | Y | Y | Y |
|
|
58
|
+
| `GET /authorization/resources` | Y | Y | Y |
|
|
59
|
+
| `GET /authorization/resources/{}` | Y | Y | Y |
|
|
60
|
+
| `GET /authorization/resources/{}/organization_memberships` | Y | Y | Y |
|
|
61
|
+
| `GET /authorization/roles` | Y | Y | Y |
|
|
62
|
+
| `GET /authorization/roles/{}` | Y | Y | Y |
|
|
63
|
+
| `GET /connect/applications` | Y | Y | |
|
|
64
|
+
| `GET /connect/applications/{}` | Y | Y | Y |
|
|
65
|
+
| `GET /connect/applications/{}/client_secrets` | Y | Y | Y |
|
|
66
|
+
| `GET /connections` | Y | Y | |
|
|
67
|
+
| `GET /connections/{}` | Y | Y | Y |
|
|
68
|
+
| `GET /directories` | Y | Y | |
|
|
69
|
+
| `GET /directories/{}` | Y | Y | Y |
|
|
70
|
+
| `GET /directory_groups` | Y | Y | |
|
|
71
|
+
| `GET /directory_groups/{}` | Y | Y | Y |
|
|
72
|
+
| `GET /directory_users` | Y | Y | |
|
|
73
|
+
| `GET /directory_users/{}` | Y | Y | Y |
|
|
74
|
+
| `GET /events` | Y | Y | |
|
|
75
|
+
| `GET /feature-flags` | Y | Y | |
|
|
76
|
+
| `GET /feature-flags/{}` | Y | Y | Y |
|
|
77
|
+
| `GET /fga/v1/resources/{}/{}` | | | Y |
|
|
78
|
+
| `GET /organization_domains/{}` | Y | Y | Y |
|
|
79
|
+
| `GET /organizations` | Y | Y | |
|
|
80
|
+
| `GET /organizations/external_id/{}` | Y | Y | Y |
|
|
81
|
+
| `GET /organizations/{}` | Y | Y | Y |
|
|
82
|
+
| `GET /organizations/{}/api_keys` | Y | Y | |
|
|
83
|
+
| `GET /organizations/{}/audit_log_configuration` | Y | Y | |
|
|
84
|
+
| `GET /organizations/{}/audit_logs_retention` | Y | Y | |
|
|
85
|
+
| `GET /organizations/{}/feature-flags` | Y | Y | |
|
|
86
|
+
| `GET /organizations/{}/roles` | | | Y |
|
|
87
|
+
| `GET /sso/authorize` | Y | Y | |
|
|
88
|
+
| `GET /sso/jwks/{}` | Y | Y | |
|
|
89
|
+
| `GET /sso/logout` | Y | Y | |
|
|
90
|
+
| `GET /sso/profile` | Y | Y | |
|
|
91
|
+
| `GET /user_management/authorize` | Y | Y | |
|
|
92
|
+
| `GET /user_management/email_verification/{}` | Y | Y | Y |
|
|
93
|
+
| `GET /user_management/invitations` | Y | Y | |
|
|
94
|
+
| `GET /user_management/invitations/by_token/{}` | Y | Y | Y |
|
|
95
|
+
| `GET /user_management/invitations/{}` | Y | Y | Y |
|
|
96
|
+
| `GET /user_management/magic_auth/{}` | Y | Y | Y |
|
|
97
|
+
| `GET /user_management/organization_memberships` | Y | Y | |
|
|
98
|
+
| `GET /user_management/organization_memberships/{}` | Y | Y | Y |
|
|
99
|
+
| `GET /user_management/password_reset/{}` | Y | Y | Y |
|
|
100
|
+
| `GET /user_management/sessions/logout` | Y | Y | |
|
|
101
|
+
| `GET /user_management/users` | Y | Y | |
|
|
102
|
+
| `GET /user_management/users/external_id/{}` | Y | Y | Y |
|
|
103
|
+
| `GET /user_management/users/{}` | Y | Y | Y |
|
|
104
|
+
| `GET /user_management/users/{}/auth_factors` | Y | Y | |
|
|
105
|
+
| `GET /user_management/users/{}/authorized_applications` | Y | Y | |
|
|
106
|
+
| `GET /user_management/users/{}/connected_accounts/{}` | Y | Y | |
|
|
107
|
+
| `GET /user_management/users/{}/data_providers` | Y | Y | |
|
|
108
|
+
| `GET /user_management/users/{}/feature-flags` | Y | Y | |
|
|
109
|
+
| `GET /user_management/users/{}/identities` | Y | Y | Y |
|
|
110
|
+
| `GET /user_management/users/{}/sessions` | Y | Y | |
|
|
111
|
+
| `GET /vault/v1/kv/name/{}` | | | Y |
|
|
112
|
+
| `GET /vault/v1/kv/{}` | | | Y |
|
|
113
|
+
| `GET /vault/v1/kv/{}/metadata` | | | Y |
|
|
114
|
+
| `GET /vault/v1/kv/{}/versions` | | | Y |
|
|
115
|
+
| `GET /webhook_endpoints` | Y | Y | |
|
|
116
|
+
| `PATCH /authorization/organizations/{}/resources/{}/{}` | Y | Y | Y |
|
|
117
|
+
| `PATCH /authorization/organizations/{}/roles/{}` | Y | Y | Y |
|
|
118
|
+
| `PATCH /authorization/permissions/{}` | Y | Y | Y |
|
|
119
|
+
| `PATCH /authorization/resources/{}` | Y | Y | Y |
|
|
120
|
+
| `PATCH /authorization/roles/{}` | Y | Y | Y |
|
|
121
|
+
| `POST /api_keys/validations` | Y | Y | Y |
|
|
122
|
+
| `POST /audit_logs/actions/{}/schemas` | Y | Y | Y |
|
|
123
|
+
| `POST /audit_logs/events` | Y | Y | Y |
|
|
124
|
+
| `POST /audit_logs/exports` | Y | Y | Y |
|
|
125
|
+
| `POST /auth/challenges/{}/verify` | Y | Y | Y |
|
|
126
|
+
| `POST /auth/factors/enroll` | Y | Y | Y |
|
|
127
|
+
| `POST /auth/factors/{}/challenge` | Y | Y | Y |
|
|
128
|
+
| `POST /authkit/oauth2/complete` | Y | Y | Y |
|
|
129
|
+
| `POST /authorization/organization_memberships/{}/check` | Y | Y | Y |
|
|
130
|
+
| `POST /authorization/organization_memberships/{}/role_assignments` | Y | Y | Y |
|
|
131
|
+
| `POST /authorization/organizations/{}/roles` | Y | Y | Y |
|
|
132
|
+
| `POST /authorization/organizations/{}/roles/{}/permissions` | Y | Y | Y |
|
|
133
|
+
| `POST /authorization/permissions` | Y | Y | Y |
|
|
134
|
+
| `POST /authorization/resources` | Y | Y | Y |
|
|
135
|
+
| `POST /authorization/roles` | Y | Y | Y |
|
|
136
|
+
| `POST /authorization/roles/{}/permissions` | Y | Y | Y |
|
|
137
|
+
| `POST /connect/applications` | Y | Y | Y |
|
|
138
|
+
| `POST /connect/applications/{}/client_secrets` | Y | Y | Y |
|
|
139
|
+
| `POST /data-integrations/{}/authorize` | Y | Y | Y |
|
|
140
|
+
| `POST /data-integrations/{}/token` | Y | Y | Y |
|
|
141
|
+
| `POST /feature-flags/{}/targets/{}` | Y | Y | Y |
|
|
142
|
+
| `POST /fga/v1/check` | | | Y |
|
|
143
|
+
| `POST /fga/v1/resources` | | | Y |
|
|
144
|
+
| `POST /fga/v1/resources/batch` | | | Y |
|
|
145
|
+
| `POST /fga/v1/warrants` | | | Y |
|
|
146
|
+
| `POST /organization_domains` | Y | Y | Y |
|
|
147
|
+
| `POST /organization_domains/{}/verify` | Y | Y | Y |
|
|
148
|
+
| `POST /organizations` | Y | Y | Y |
|
|
149
|
+
| `POST /organizations/{}/api_keys` | Y | Y | Y |
|
|
150
|
+
| `POST /passwordless/sessions` | | | Y |
|
|
151
|
+
| `POST /passwordless/sessions/{}/send` | | | Y |
|
|
152
|
+
| `POST /portal/generate_link` | Y | Y | Y |
|
|
153
|
+
| `POST /radar/attempts` | Y | Y | Y |
|
|
154
|
+
| `POST /radar/lists/{}/{}` | Y | Y | Y |
|
|
155
|
+
| `POST /sso/logout/authorize` | Y | Y | |
|
|
156
|
+
| `POST /sso/token` | Y | Y | |
|
|
157
|
+
| `POST /user_management/authenticate` | Y | Y | Y |
|
|
158
|
+
| `POST /user_management/authorize/device` | Y | Y | |
|
|
159
|
+
| `POST /user_management/cors_origins` | Y | Y | |
|
|
160
|
+
| `POST /user_management/invitations` | Y | Y | Y |
|
|
161
|
+
| `POST /user_management/invitations/{}/accept` | Y | Y | Y |
|
|
162
|
+
| `POST /user_management/invitations/{}/resend` | Y | Y | Y |
|
|
163
|
+
| `POST /user_management/invitations/{}/revoke` | Y | Y | Y |
|
|
164
|
+
| `POST /user_management/magic_auth` | Y | Y | Y |
|
|
165
|
+
| `POST /user_management/organization_memberships` | Y | Y | Y |
|
|
166
|
+
| `POST /user_management/password_reset` | Y | Y | Y |
|
|
167
|
+
| `POST /user_management/password_reset/confirm` | Y | Y | Y |
|
|
168
|
+
| `POST /user_management/redirect_uris` | Y | Y | |
|
|
169
|
+
| `POST /user_management/sessions/revoke` | Y | Y | Y |
|
|
170
|
+
| `POST /user_management/users` | Y | Y | Y |
|
|
171
|
+
| `POST /user_management/users/{}/auth_factors` | Y | Y | Y |
|
|
172
|
+
| `POST /user_management/users/{}/email_verification/confirm` | Y | Y | Y |
|
|
173
|
+
| `POST /user_management/users/{}/email_verification/send` | Y | Y | Y |
|
|
174
|
+
| `POST /vault/v1/keys/data-key` | | | Y |
|
|
175
|
+
| `POST /vault/v1/keys/decrypt` | | | Y |
|
|
176
|
+
| `POST /vault/v1/kv` | | | Y |
|
|
177
|
+
| `POST /webhook_endpoints` | Y | Y | Y |
|
|
178
|
+
| `POST /widgets/token` | Y | Y | Y |
|
|
179
|
+
| `POST data-integrations/{}/token` | | | Y |
|
|
180
|
+
| `PUT /authorization/organizations/{}/roles/priority` | Y | Y | |
|
|
181
|
+
| `PUT /authorization/organizations/{}/roles/{}/permissions` | Y | Y | Y |
|
|
182
|
+
| `PUT /authorization/roles/{}/permissions` | Y | Y | Y |
|
|
183
|
+
| `PUT /connect/applications/{}` | Y | Y | Y |
|
|
184
|
+
| `PUT /feature-flags/{}/disable` | Y | Y | Y |
|
|
185
|
+
| `PUT /feature-flags/{}/enable` | Y | Y | Y |
|
|
186
|
+
| `PUT /fga/v1/resources/{}/{}` | | | Y |
|
|
187
|
+
| `PUT /organizations/{}` | Y | Y | Y |
|
|
188
|
+
| `PUT /organizations/{}/audit_logs_retention` | Y | Y | |
|
|
189
|
+
| `PUT /radar/attempts/{}` | Y | Y | Y |
|
|
190
|
+
| `PUT /user_management/jwt_template` | Y | Y | |
|
|
191
|
+
| `PUT /user_management/organization_memberships/{}` | Y | Y | Y |
|
|
192
|
+
| `PUT /user_management/organization_memberships/{}/deactivate` | Y | Y | Y |
|
|
193
|
+
| `PUT /user_management/organization_memberships/{}/reactivate` | Y | Y | Y |
|
|
194
|
+
| `PUT /user_management/users/{}` | Y | Y | Y |
|
|
195
|
+
| `PUT /vault/v1/kv/{}` | | | Y |
|
|
196
|
+
|
|
197
|
+
## In Spec + Generated SDK but NOT in workos-node (40)
|
|
198
|
+
|
|
199
|
+
Many of these are list endpoints that workos-node handles via a shared paginated fetch helper which constructs URLs dynamically. Static analysis of the source does not capture these, so the actual runtime coverage is likely higher.
|
|
200
|
+
|
|
201
|
+
| Endpoint | Notes |
|
|
202
|
+
| ------------------------------------------------------------- | ------------------------------- |
|
|
203
|
+
| `DELETE /user_management/users/{}/authorized_applications/{}` | |
|
|
204
|
+
| `DELETE /user_management/users/{}/connected_accounts/{}` | |
|
|
205
|
+
| `GET /audit_logs/actions` | List endpoint |
|
|
206
|
+
| `GET /audit_logs/actions/{}/schemas` | |
|
|
207
|
+
| `GET /connect/applications` | List endpoint |
|
|
208
|
+
| `GET /connections` | List endpoint |
|
|
209
|
+
| `GET /directories` | List endpoint |
|
|
210
|
+
| `GET /directory_groups` | List endpoint |
|
|
211
|
+
| `GET /directory_users` | List endpoint |
|
|
212
|
+
| `GET /events` | List endpoint |
|
|
213
|
+
| `GET /feature-flags` | List endpoint |
|
|
214
|
+
| `GET /organizations` | List endpoint |
|
|
215
|
+
| `GET /organizations/{}/api_keys` | |
|
|
216
|
+
| `GET /organizations/{}/audit_log_configuration` | |
|
|
217
|
+
| `GET /organizations/{}/audit_logs_retention` | |
|
|
218
|
+
| `GET /organizations/{}/feature-flags` | |
|
|
219
|
+
| `GET /sso/authorize` | URL construction, not HTTP call |
|
|
220
|
+
| `GET /sso/jwks/{}` | |
|
|
221
|
+
| `GET /sso/logout` | URL construction, not HTTP call |
|
|
222
|
+
| `GET /sso/profile` | |
|
|
223
|
+
| `GET /user_management/authorize` | URL construction, not HTTP call |
|
|
224
|
+
| `GET /user_management/invitations` | List endpoint |
|
|
225
|
+
| `GET /user_management/organization_memberships` | List endpoint |
|
|
226
|
+
| `GET /user_management/sessions/logout` | URL construction, not HTTP call |
|
|
227
|
+
| `GET /user_management/users` | List endpoint |
|
|
228
|
+
| `GET /user_management/users/{}/auth_factors` | |
|
|
229
|
+
| `GET /user_management/users/{}/authorized_applications` | |
|
|
230
|
+
| `GET /user_management/users/{}/connected_accounts/{}` | |
|
|
231
|
+
| `GET /user_management/users/{}/data_providers` | |
|
|
232
|
+
| `GET /user_management/users/{}/feature-flags` | |
|
|
233
|
+
| `GET /user_management/users/{}/sessions` | |
|
|
234
|
+
| `GET /webhook_endpoints` | List endpoint |
|
|
235
|
+
| `POST /sso/logout/authorize` | |
|
|
236
|
+
| `POST /sso/token` | |
|
|
237
|
+
| `POST /user_management/authorize/device` | |
|
|
238
|
+
| `POST /user_management/cors_origins` | |
|
|
239
|
+
| `POST /user_management/redirect_uris` | |
|
|
240
|
+
| `PUT /authorization/organizations/{}/roles/priority` | |
|
|
241
|
+
| `PUT /organizations/{}/audit_logs_retention` | |
|
|
242
|
+
| `PUT /user_management/jwt_template` | |
|
|
243
|
+
|
|
244
|
+
## In workos-node but NOT in Spec (20)
|
|
245
|
+
|
|
246
|
+
These are legacy, deprecated, or separate-product endpoints not present in the current OpenAPI spec.
|
|
247
|
+
|
|
248
|
+
| Endpoint | Notes |
|
|
249
|
+
| ------------------------------------- | -------------------------------------------------------------------------- |
|
|
250
|
+
| `DELETE /fga/v1/resources/{}/{}` | FGA v1 (separate product) |
|
|
251
|
+
| `DELETE /vault/v1/kv/{}` | Vault v1 (separate product) |
|
|
252
|
+
| `GET /fga/v1/resources/{}/{}` | FGA v1 (separate product) |
|
|
253
|
+
| `GET /organizations/{}/roles` | Different path pattern from spec's `/authorization/organizations/{}/roles` |
|
|
254
|
+
| `GET /vault/v1/kv/name/{}` | Vault v1 (separate product) |
|
|
255
|
+
| `GET /vault/v1/kv/{}` | Vault v1 (separate product) |
|
|
256
|
+
| `GET /vault/v1/kv/{}/metadata` | Vault v1 (separate product) |
|
|
257
|
+
| `GET /vault/v1/kv/{}/versions` | Vault v1 (separate product) |
|
|
258
|
+
| `POST /fga/v1/check` | FGA v1 (separate product) |
|
|
259
|
+
| `POST /fga/v1/resources` | FGA v1 (separate product) |
|
|
260
|
+
| `POST /fga/v1/resources/batch` | FGA v1 (separate product) |
|
|
261
|
+
| `POST /fga/v1/warrants` | FGA v1 (separate product) |
|
|
262
|
+
| `POST /passwordless/sessions` | Deprecated passwordless API |
|
|
263
|
+
| `POST /passwordless/sessions/{}/send` | Deprecated passwordless API |
|
|
264
|
+
| `POST /vault/v1/keys/data-key` | Vault v1 (separate product) |
|
|
265
|
+
| `POST /vault/v1/keys/decrypt` | Vault v1 (separate product) |
|
|
266
|
+
| `POST /vault/v1/kv` | Vault v1 (separate product) |
|
|
267
|
+
| `POST data-integrations/{}/token` | Missing leading `/` — likely a source bug |
|
|
268
|
+
| `PUT /fga/v1/resources/{}/{}` | FGA v1 (separate product) |
|
|
269
|
+
| `PUT /vault/v1/kv/{}` | Vault v1 (separate product) |
|
|
270
|
+
|
|
271
|
+
## Caveats
|
|
272
|
+
|
|
273
|
+
- **workos-node list endpoints**: Many list/paginated GET endpoints in workos-node are handled by a shared `fetchAndDeserialize` or `AutoPaginatable` helper that constructs the URL dynamically. Static grep analysis does not capture these, so the 134 count is a **lower bound**. The actual runtime coverage is likely closer to the spec's 154.
|
|
274
|
+
- **URL-construction-only endpoints**: Some spec endpoints (e.g., `GET /sso/authorize`, `GET /user_management/authorize`) are authorization URLs that the SDK constructs and returns as strings rather than making HTTP calls. These appear as "missing" from workos-node but are functionally present.
|
|
275
|
+
- **Path parameter normalization**: All path parameters are normalized to `{}` for comparison. The spec uses `<ID>`, the generated SDK uses `{paramName}`, and workos-node uses template literals like `${id}`.
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# Node SDK Architecture
|
|
2
|
+
|
|
3
|
+
Derived from the existing WorkOS Node SDK at `workos-node`.
|
|
4
|
+
|
|
5
|
+
## Architecture Overview
|
|
6
|
+
|
|
7
|
+
- **Main client**: `WorkOS` class with HTTP methods (`get`, `post`, `put`, `patch`, `delete`) and readonly resource accessors (e.g., `workos.organizations`).
|
|
8
|
+
- **Resource classes**: One per service, constructor receives `WorkOS` client, async methods return deserialized domain types.
|
|
9
|
+
- **Dual interface system**: Domain interfaces (camelCase) and wire/response interfaces (snake_case with `Response` suffix).
|
|
10
|
+
- **Explicit serialization**: `deserialize{Model}` and `serialize{Options}` functions per model/operation.
|
|
11
|
+
- **Pagination**: `AutoPaginatable<T>` with cursor-based `after` param, `autoPagination()` async generator, 350ms rate-limit delay.
|
|
12
|
+
- **Error hierarchy**: Status-code-specific exception classes extending `Error`.
|
|
13
|
+
- **Constructor**: Accepts `string | WorkOSOptions`, env var fallback for `WORKOS_API_KEY`.
|
|
14
|
+
- **Factory**: `createWorkOS()` with overloads for `PublicWorkOS` (no API key) and full `WorkOS`.
|
|
15
|
+
|
|
16
|
+
## Naming Conventions
|
|
17
|
+
|
|
18
|
+
| Concept | Convention | Example |
|
|
19
|
+
| ---------------- | ---------- | ----------------------------------------------- |
|
|
20
|
+
| Class/Interface | PascalCase | `Organization`, `UserManagement` |
|
|
21
|
+
| Method | camelCase | `listOrganizations`, `createOrganization` |
|
|
22
|
+
| Domain field | camelCase | `allowProfilesOutsideOrganization` |
|
|
23
|
+
| Wire field | snake_case | `allow_profiles_outside_organization` |
|
|
24
|
+
| File | kebab-case | `organization.interface.ts` |
|
|
25
|
+
| Directory | kebab-case | `organizations/`, `user-management/` |
|
|
26
|
+
| Service property | camelCase | `workos.organizations`, `workos.userManagement` |
|
|
27
|
+
|
|
28
|
+
### Overlay Resolution
|
|
29
|
+
|
|
30
|
+
All service-derived names (class, directory, file, property) are resolved through the overlay before falling back to the default PascalCase convention. This allows the generated SDK to match existing class names in the live SDK. For example, the IR service `MultiFactorAuth` (derived from the `multi-factor-auth` OpenAPI tag) is resolved to `Mfa` via the overlay, producing:
|
|
31
|
+
|
|
32
|
+
- Class: `Mfa`
|
|
33
|
+
- Directory: `src/mfa/`
|
|
34
|
+
- File: `mfa.ts`
|
|
35
|
+
- Property: `workos.mfa`
|
|
36
|
+
|
|
37
|
+
Method names are also overlay-resolved per operation (`resolveMethodName`), and interface names per model (`resolveInterfaceName`).
|
|
38
|
+
|
|
39
|
+
## Type Mapping
|
|
40
|
+
|
|
41
|
+
| IR TypeRef | TypeScript (Domain) | TypeScript (Wire/Response) |
|
|
42
|
+
| ------------------------- | ------------------- | -------------------------- |
|
|
43
|
+
| `string` | `string` | `string` |
|
|
44
|
+
| `string` (date/date-time) | `string` | `string` |
|
|
45
|
+
| `integer` | `number` | `number` |
|
|
46
|
+
| `number` | `number` | `number` |
|
|
47
|
+
| `boolean` | `boolean` | `boolean` |
|
|
48
|
+
| `unknown` | `any` | `any` |
|
|
49
|
+
| `array(T)` | `T[]` | `T[]` |
|
|
50
|
+
| `model(Name)` | `Name` | `NameResponse` |
|
|
51
|
+
| `enum(Name)` | `Name` | `Name` |
|
|
52
|
+
| `nullable(T)` | `T \| null` | `T \| null` |
|
|
53
|
+
| `union(V1,V2)` | `V1 \| V2` | `V1 \| V2` |
|
|
54
|
+
| `map(V)` | `Record<string, V>` | `Record<string, V>` |
|
|
55
|
+
| `literal(v)` | `'v'` | `'v'` |
|
|
56
|
+
|
|
57
|
+
## Model Pattern
|
|
58
|
+
|
|
59
|
+
From `src/organizations/interfaces/organization.interface.ts`:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Domain interface (camelCase)
|
|
63
|
+
export interface Organization {
|
|
64
|
+
object: "organization";
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
allowProfilesOutsideOrganization: boolean;
|
|
68
|
+
domains: OrganizationDomain[];
|
|
69
|
+
stripeCustomerId?: string;
|
|
70
|
+
createdAt: string;
|
|
71
|
+
updatedAt: string;
|
|
72
|
+
externalId: string | null;
|
|
73
|
+
metadata: Record<string, string>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Wire interface (snake_case, Response suffix)
|
|
77
|
+
export interface OrganizationResponse {
|
|
78
|
+
object: "organization";
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
allow_profiles_outside_organization: boolean;
|
|
82
|
+
domains: OrganizationDomainResponse[];
|
|
83
|
+
stripe_customer_id?: string;
|
|
84
|
+
created_at: string;
|
|
85
|
+
updated_at: string;
|
|
86
|
+
external_id?: string | null;
|
|
87
|
+
metadata?: Record<string, string>;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Key patterns:
|
|
92
|
+
|
|
93
|
+
- Required domain fields may be optional in the response interface
|
|
94
|
+
- Model refs in response use `Response` suffix
|
|
95
|
+
- Nullable fields use `| null`, optional fields use `?`
|
|
96
|
+
|
|
97
|
+
## Enum Pattern
|
|
98
|
+
|
|
99
|
+
String literal union types:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
export type OrganizationDomainVerificationStrategy = "dns" | "manual";
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Serialization Pattern
|
|
106
|
+
|
|
107
|
+
From `src/organizations/serializers/organization.serializer.ts`:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
export const deserializeOrganization = (
|
|
111
|
+
organization: OrganizationResponse,
|
|
112
|
+
): Organization => ({
|
|
113
|
+
object: organization.object,
|
|
114
|
+
id: organization.id,
|
|
115
|
+
name: organization.name,
|
|
116
|
+
allowProfilesOutsideOrganization:
|
|
117
|
+
organization.allow_profiles_outside_organization,
|
|
118
|
+
domains: organization.domains.map(deserializeOrganizationDomain),
|
|
119
|
+
...(typeof organization.stripe_customer_id === "undefined"
|
|
120
|
+
? undefined
|
|
121
|
+
: { stripeCustomerId: organization.stripe_customer_id }),
|
|
122
|
+
createdAt: organization.created_at,
|
|
123
|
+
updatedAt: organization.updated_at,
|
|
124
|
+
externalId: organization.external_id ?? null,
|
|
125
|
+
metadata: organization.metadata ?? {},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
export const serializeCreateOrganizationOptions = (
|
|
129
|
+
options: CreateOrganizationOptions,
|
|
130
|
+
): SerializedCreateOrganizationOptions => ({
|
|
131
|
+
name: options.name,
|
|
132
|
+
domain_data: options.domainData,
|
|
133
|
+
external_id: options.externalId,
|
|
134
|
+
metadata: options.metadata,
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Key patterns:
|
|
139
|
+
|
|
140
|
+
- Deserialize: snake_case → camelCase, map nested models recursively
|
|
141
|
+
- Optional wire fields: spread conditional (`typeof x === 'undefined' ? undefined : { ... }`)
|
|
142
|
+
- Nullable domain fields: `?? null` fallback
|
|
143
|
+
- Default values for optional collections: `?? {}`
|
|
144
|
+
|
|
145
|
+
## Resource Pattern
|
|
146
|
+
|
|
147
|
+
From `src/organizations/organizations.ts`:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
export class Organizations {
|
|
151
|
+
constructor(private readonly workos: WorkOS) {}
|
|
152
|
+
|
|
153
|
+
async listOrganizations(
|
|
154
|
+
options?: ListOrganizationsOptions,
|
|
155
|
+
): Promise<AutoPaginatable<Organization, ListOrganizationsOptions>> {
|
|
156
|
+
return new AutoPaginatable(
|
|
157
|
+
await fetchAndDeserialize<OrganizationResponse, Organization>(
|
|
158
|
+
this.workos,
|
|
159
|
+
"/organizations",
|
|
160
|
+
deserializeOrganization,
|
|
161
|
+
options,
|
|
162
|
+
),
|
|
163
|
+
(params) =>
|
|
164
|
+
fetchAndDeserialize<OrganizationResponse, Organization>(
|
|
165
|
+
this.workos,
|
|
166
|
+
"/organizations",
|
|
167
|
+
deserializeOrganization,
|
|
168
|
+
params,
|
|
169
|
+
),
|
|
170
|
+
options,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async createOrganization(
|
|
175
|
+
payload: CreateOrganizationOptions,
|
|
176
|
+
requestOptions: CreateOrganizationRequestOptions = {},
|
|
177
|
+
): Promise<Organization> {
|
|
178
|
+
const { data } = await this.workos.post<OrganizationResponse>(
|
|
179
|
+
"/organizations",
|
|
180
|
+
serializeCreateOrganizationOptions(payload),
|
|
181
|
+
requestOptions,
|
|
182
|
+
);
|
|
183
|
+
return deserializeOrganization(data);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async getOrganization(id: string): Promise<Organization> {
|
|
187
|
+
const { data } = await this.workos.get<OrganizationResponse>(
|
|
188
|
+
`/organizations/${id}`,
|
|
189
|
+
);
|
|
190
|
+
return deserializeOrganization(data);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async deleteOrganization(id: string): Promise<void> {
|
|
194
|
+
await this.workos.delete(`/organizations/${id}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Key patterns:
|
|
200
|
+
|
|
201
|
+
- Constructor takes `private readonly workos: WorkOS`
|
|
202
|
+
- List methods return `AutoPaginatable<T>` via `fetchAndDeserialize`
|
|
203
|
+
- Create/update methods: serialize body → POST → deserialize response
|
|
204
|
+
- Get methods: GET with path param → deserialize response
|
|
205
|
+
- Delete methods: return `Promise<void>`
|
|
206
|
+
- Idempotent POSTs: accept `requestOptions` with `idempotencyKey`
|
|
207
|
+
|
|
208
|
+
## Pagination Pattern
|
|
209
|
+
|
|
210
|
+
From `src/common/utils/pagination.ts`:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
export class AutoPaginatable<
|
|
214
|
+
ResourceType,
|
|
215
|
+
ParametersType extends PaginationOptions = PaginationOptions,
|
|
216
|
+
> {
|
|
217
|
+
readonly object = 'list' as const;
|
|
218
|
+
constructor(
|
|
219
|
+
protected list: List<ResourceType>,
|
|
220
|
+
private apiCall: (params: PaginationOptions) => Promise<List<ResourceType>>,
|
|
221
|
+
options?: ParametersType,
|
|
222
|
+
) { ... }
|
|
223
|
+
|
|
224
|
+
get data(): ResourceType[] { return this.list.data; }
|
|
225
|
+
get listMetadata() { return this.list.listMetadata; }
|
|
226
|
+
async autoPagination(): Promise<ResourceType[]> { ... }
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Error Handling
|
|
231
|
+
|
|
232
|
+
From `src/common/exceptions/`:
|
|
233
|
+
|
|
234
|
+
| Exception Class | Status Code |
|
|
235
|
+
| -------------------------------- | ----------- |
|
|
236
|
+
| `BadRequestException` | 400 |
|
|
237
|
+
| `UnauthorizedException` | 401 |
|
|
238
|
+
| `ApiKeyRequiredException` | 403 |
|
|
239
|
+
| `NotFoundException` | 404 |
|
|
240
|
+
| `ConflictException` | 409 |
|
|
241
|
+
| `UnprocessableEntityException` | 422 |
|
|
242
|
+
| `RateLimitExceededException` | 429 |
|
|
243
|
+
| `GenericServerException` | 500+ |
|
|
244
|
+
| `OAuthException` | varies |
|
|
245
|
+
| `NoApiKeyProvidedException` | runtime |
|
|
246
|
+
| `SignatureVerificationException` | runtime |
|
|
247
|
+
|
|
248
|
+
Each exception: extends `Error`, has `readonly status`, `readonly name`, `requestID`, optional `code`.
|
|
249
|
+
|
|
250
|
+
## Client Architecture
|
|
251
|
+
|
|
252
|
+
From `src/workos.ts`:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
export class WorkOS {
|
|
256
|
+
readonly baseURL: string;
|
|
257
|
+
readonly client: HttpClient;
|
|
258
|
+
readonly organizations = new Organizations(this);
|
|
259
|
+
// ... other resource accessors
|
|
260
|
+
|
|
261
|
+
constructor(keyOrOptions?: string | WorkOSOptions, maybeOptions?: WorkOSOptions) { ... }
|
|
262
|
+
|
|
263
|
+
async post<Result, Entity>(path, entity, options?: PostOptions): Promise<{ data: Result }> { ... }
|
|
264
|
+
async get<Result>(path, options?: GetOptions): Promise<{ data: Result }> { ... }
|
|
265
|
+
async put<Result, Entity>(path, entity, options?): Promise<{ data: Result }> { ... }
|
|
266
|
+
async delete(path, options?): Promise<void> { ... }
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## HTTP Client (Retry Logic)
|
|
271
|
+
|
|
272
|
+
From `src/common/net/http-client.ts`:
|
|
273
|
+
|
|
274
|
+
- `MAX_RETRY_ATTEMPTS = 3`
|
|
275
|
+
- `BACKOFF_MULTIPLIER = 1.5`
|
|
276
|
+
- `MINIMUM_SLEEP_TIME_IN_MILLISECONDS = 500`
|
|
277
|
+
- `RETRY_STATUS_CODES = [408, 500, 502, 504]`
|
|
278
|
+
- Path-specific retry: only for `/fga/`, `/vault/`, `/audit_logs/events`
|
|
279
|
+
- Jitter: `sleepTime * (Math.random() + 0.5)`
|
|
280
|
+
|
|
281
|
+
## Testing Pattern
|
|
282
|
+
|
|
283
|
+
Framework: Jest + `jest-fetch-mock`
|
|
284
|
+
|
|
285
|
+
From `src/organizations/organizations.spec.ts`:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import fetch from "jest-fetch-mock";
|
|
289
|
+
import {
|
|
290
|
+
fetchOnce,
|
|
291
|
+
fetchURL,
|
|
292
|
+
fetchSearchParams,
|
|
293
|
+
fetchBody,
|
|
294
|
+
} from "../common/utils/test-utils";
|
|
295
|
+
|
|
296
|
+
const workos = new WorkOS("sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU");
|
|
297
|
+
|
|
298
|
+
describe("Organizations", () => {
|
|
299
|
+
beforeEach(() => fetch.resetMocks());
|
|
300
|
+
|
|
301
|
+
it("returns organizations and metadata", async () => {
|
|
302
|
+
fetchOnce(listOrganizationsFixture);
|
|
303
|
+
const { data, listMetadata } =
|
|
304
|
+
await workos.organizations.listOrganizations();
|
|
305
|
+
expect(fetchSearchParams()).toEqual({ order: "desc" });
|
|
306
|
+
expect(data).toHaveLength(7);
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Test utilities: `fetchOnce`, `fetchURL`, `fetchSearchParams`, `fetchHeaders`, `fetchBody`.
|
|
312
|
+
|
|
313
|
+
## Directory Structure
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
src/
|
|
317
|
+
├── workos.ts # Main client class
|
|
318
|
+
├── index.ts # Barrel export
|
|
319
|
+
├── factory.ts # createWorkOS factory
|
|
320
|
+
├── common/
|
|
321
|
+
│ ├── exceptions/ # Error hierarchy
|
|
322
|
+
│ ├── interfaces/ # WorkOSOptions, PostOptions, GetOptions, PaginationOptions
|
|
323
|
+
│ ├── net/ # HttpClient abstract base
|
|
324
|
+
│ ├── serializers/ # list, event, pagination serializers
|
|
325
|
+
│ └── utils/ # AutoPaginatable, fetchAndDeserialize, test-utils
|
|
326
|
+
├── {service}/
|
|
327
|
+
│ ├── {service}.ts # Resource class
|
|
328
|
+
│ ├── {service}.spec.ts # Tests
|
|
329
|
+
│ ├── interfaces/ # Model, Response, Options interfaces
|
|
330
|
+
│ │ └── index.ts # Re-exports
|
|
331
|
+
│ ├── serializers/ # Serialize/deserialize functions
|
|
332
|
+
│ │ └── index.ts # Re-exports
|
|
333
|
+
│ └── fixtures/ # JSON test data
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Structural Guidelines
|
|
337
|
+
|
|
338
|
+
| Category | Choice |
|
|
339
|
+
| ----------------- | ---------------------------------------- |
|
|
340
|
+
| Testing Framework | Jest |
|
|
341
|
+
| HTTP Mocking | jest-fetch-mock |
|
|
342
|
+
| Type Signatures | TypeScript interfaces (inline) |
|
|
343
|
+
| HTTP Client | Abstract HttpClient with FetchHttpClient |
|
|
344
|
+
| JSON Parsing | Built-in JSON.parse/stringify |
|
|
345
|
+
| Package Manager | npm |
|
|
346
|
+
| Build Tool | TypeScript compiler + bundler |
|
|
347
|
+
| Module Format | CJS + ESM dual |
|
|
348
|
+
|
|
349
|
+
## Additional Generator Files
|
|
350
|
+
|
|
351
|
+
Beyond the standard scaffold, this emitter requires:
|
|
352
|
+
|
|
353
|
+
- `serializers.ts` — explicit serialize/deserialize function generation
|
|
354
|
+
- `common.ts` — AutoPaginatable, fetchAndDeserialize, List types, shared utilities
|
|
355
|
+
- `config.ts` — WorkOSOptions, PostOptions, GetOptions, PaginationOptions
|