workos 1.5.1__py3-none-any.whl → 5.38.0__py3-none-any.whl

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 (150) hide show
  1. workos/__about__.py +1 -1
  2. workos/__init__.py +3 -7
  3. workos/_base_client.py +138 -0
  4. workos/_client_configuration.py +10 -0
  5. workos/api_keys.py +53 -0
  6. workos/async_client.py +144 -0
  7. workos/audit_logs.py +125 -0
  8. workos/client.py +110 -18
  9. workos/directory_sync.py +379 -99
  10. workos/events.py +111 -0
  11. workos/exceptions.py +53 -26
  12. workos/fga.py +649 -0
  13. workos/mfa.py +205 -0
  14. workos/organization_domains.py +179 -0
  15. workos/organizations.py +403 -73
  16. workos/passwordless.py +67 -43
  17. workos/pipes.py +93 -0
  18. workos/portal.py +51 -28
  19. workos/session.py +337 -0
  20. workos/sso.py +311 -101
  21. workos/types/__init__.py +4 -0
  22. workos/types/api_keys/__init__.py +1 -0
  23. workos/types/api_keys/api_keys.py +20 -0
  24. workos/types/audit_logs/__init__.py +6 -0
  25. workos/types/audit_logs/audit_log_event.py +16 -0
  26. workos/types/audit_logs/audit_log_event_actor.py +12 -0
  27. workos/types/audit_logs/audit_log_event_context.py +8 -0
  28. workos/types/audit_logs/audit_log_event_target.py +12 -0
  29. workos/types/audit_logs/audit_log_export.py +18 -0
  30. workos/types/audit_logs/audit_log_metadata.py +4 -0
  31. workos/types/directory_sync/__init__.py +5 -0
  32. workos/types/directory_sync/directory.py +31 -0
  33. workos/types/directory_sync/directory_group.py +16 -0
  34. workos/types/directory_sync/directory_state.py +28 -0
  35. workos/types/directory_sync/directory_type.py +24 -0
  36. workos/types/directory_sync/directory_user.py +50 -0
  37. workos/types/directory_sync/list_filters.py +21 -0
  38. workos/types/events/__init__.py +13 -0
  39. workos/types/events/authentication_payload.py +70 -0
  40. workos/types/events/connection_payload_with_legacy_fields.py +5 -0
  41. workos/types/events/directory_group_membership_payload.py +9 -0
  42. workos/types/events/directory_group_with_previous_attributes.py +6 -0
  43. workos/types/events/directory_payload.py +16 -0
  44. workos/types/events/directory_payload_with_legacy_fields.py +29 -0
  45. workos/types/events/directory_user_with_previous_attributes.py +6 -0
  46. workos/types/events/event.py +324 -0
  47. workos/types/events/event_model.py +103 -0
  48. workos/types/events/event_type.py +59 -0
  49. workos/types/events/list_filters.py +10 -0
  50. workos/types/events/organization_domain_verification_failed_payload.py +14 -0
  51. workos/types/events/previous_attributes.py +3 -0
  52. workos/types/events/session_payload.py +27 -0
  53. workos/types/feature_flags/__init__.py +3 -0
  54. workos/types/feature_flags/feature_flag.py +12 -0
  55. workos/types/feature_flags/list_filters.py +5 -0
  56. workos/types/fga/__init__.py +5 -0
  57. workos/types/fga/authorization_resource_types.py +9 -0
  58. workos/types/fga/authorization_resources.py +10 -0
  59. workos/types/fga/check.py +51 -0
  60. workos/types/fga/list_filters.py +24 -0
  61. workos/types/fga/warnings.py +33 -0
  62. workos/types/fga/warrant.py +49 -0
  63. workos/types/list_resource.py +198 -0
  64. workos/types/metadata.py +4 -0
  65. workos/types/mfa/__init__.py +5 -0
  66. workos/types/mfa/authentication_challenge.py +14 -0
  67. workos/types/mfa/authentication_challenge_verification_response.py +9 -0
  68. workos/types/mfa/authentication_factor.py +70 -0
  69. workos/types/mfa/authentication_factor_totp_and_challenge_response.py +10 -0
  70. workos/types/mfa/enroll_authentication_factor_type.py +8 -0
  71. workos/types/organization_domains/__init__.py +1 -0
  72. workos/types/organization_domains/organization_domain.py +18 -0
  73. workos/types/organizations/__init__.py +6 -0
  74. workos/types/organizations/domain_data_input.py +7 -0
  75. workos/types/organizations/list_filters.py +6 -0
  76. workos/types/organizations/organization.py +13 -0
  77. workos/types/organizations/organization_common.py +12 -0
  78. workos/types/passwordless/__init__.py +2 -0
  79. workos/types/passwordless/passwordless_session.py +12 -0
  80. workos/types/passwordless/passwordless_session_type.py +3 -0
  81. workos/types/pipes/__init__.py +6 -0
  82. workos/types/pipes/pipes.py +34 -0
  83. workos/types/portal/__init__.py +2 -0
  84. workos/types/portal/portal_link.py +7 -0
  85. workos/types/portal/portal_link_intent.py +11 -0
  86. workos/types/portal/portal_link_intent_options.py +9 -0
  87. workos/types/roles/__init__.py +0 -0
  88. workos/types/roles/role.py +27 -0
  89. workos/types/sso/__init__.py +4 -0
  90. workos/types/sso/connection.py +70 -0
  91. workos/types/sso/connection_domain.py +8 -0
  92. workos/types/sso/profile.py +35 -0
  93. workos/types/sso/sso_provider_type.py +10 -0
  94. workos/types/user_management/__init__.py +12 -0
  95. workos/types/user_management/authenticate_with_common.py +66 -0
  96. workos/types/user_management/authentication_response.py +53 -0
  97. workos/types/user_management/email_verification.py +18 -0
  98. workos/types/user_management/impersonator.py +8 -0
  99. workos/types/user_management/invitation.py +26 -0
  100. workos/types/user_management/list_filters.py +29 -0
  101. workos/types/user_management/magic_auth.py +18 -0
  102. workos/types/user_management/oauth_tokens.py +21 -0
  103. workos/types/user_management/organization_membership.py +25 -0
  104. workos/types/user_management/password_hash_type.py +4 -0
  105. workos/types/user_management/password_reset.py +18 -0
  106. workos/types/user_management/screen_hint.py +3 -0
  107. workos/types/user_management/session.py +79 -0
  108. workos/types/user_management/user.py +22 -0
  109. workos/types/user_management/user_management_provider_type.py +11 -0
  110. workos/types/vault/__init__.py +2 -0
  111. workos/types/vault/key.py +25 -0
  112. workos/types/vault/object.py +38 -0
  113. workos/types/webhooks/__init__.py +0 -0
  114. workos/types/webhooks/webhook.py +330 -0
  115. workos/types/webhooks/webhook_model.py +14 -0
  116. workos/types/webhooks/webhook_payload.py +4 -0
  117. workos/types/widgets/__init__.py +2 -0
  118. workos/types/widgets/widget_scope.py +4 -0
  119. workos/types/widgets/widget_token_response.py +7 -0
  120. workos/types/workos_model.py +26 -0
  121. workos/typing/__init__.py +1 -0
  122. workos/typing/literals.py +32 -0
  123. workos/typing/sync_or_async.py +5 -0
  124. workos/typing/untyped_literal.py +37 -0
  125. workos/typing/webhooks.py +18 -0
  126. workos/user_management.py +2400 -0
  127. workos/utils/_base_http_client.py +252 -0
  128. workos/utils/crypto_provider.py +39 -0
  129. workos/utils/http_client.py +214 -0
  130. workos/utils/pagination_order.py +4 -0
  131. workos/utils/request_helper.py +27 -0
  132. workos/vault.py +544 -0
  133. workos/webhooks.py +96 -39
  134. workos/widgets.py +55 -0
  135. {workos-1.5.1.dist-info → workos-5.38.0.dist-info}/LICENSE +1 -1
  136. workos-5.38.0.dist-info/METADATA +107 -0
  137. workos-5.38.0.dist-info/RECORD +141 -0
  138. {workos-1.5.1.dist-info → workos-5.38.0.dist-info}/WHEEL +1 -1
  139. workos/audit_trail.py +0 -172
  140. workos/resources/base.py +0 -36
  141. workos/resources/event.py +0 -42
  142. workos/resources/event_action.py +0 -11
  143. workos/resources/sso.py +0 -53
  144. workos/utils/connection_types.py +0 -17
  145. workos/utils/request.py +0 -95
  146. workos/utils/validation.py +0 -45
  147. workos-1.5.1.dist-info/METADATA +0 -77
  148. workos-1.5.1.dist-info/RECORD +0 -25
  149. /workos/{resources/__init__.py → py.typed} +0 -0
  150. {workos-1.5.1.dist-info → workos-5.38.0.dist-info}/top_level.txt +0 -0
workos/organizations.py CHANGED
@@ -1,31 +1,48 @@
1
- import workos
2
- from workos.utils.request import (
3
- RequestHelper,
1
+ from typing import Optional, Protocol, Sequence
2
+
3
+ from workos.types.feature_flags import FeatureFlag
4
+ from workos.types.feature_flags.list_filters import FeatureFlagListFilters
5
+ from workos.types.metadata import Metadata
6
+ from workos.types.organizations.domain_data_input import DomainDataInput
7
+ from workos.types.organizations.list_filters import OrganizationListFilters
8
+ from workos.types.roles.role import RoleList
9
+ from workos.typing.sync_or_async import SyncOrAsync
10
+ from workos.utils.http_client import AsyncHTTPClient, SyncHTTPClient
11
+ from workos.utils.pagination_order import PaginationOrder
12
+ from workos.utils.request_helper import (
13
+ DEFAULT_LIST_RESPONSE_LIMIT,
4
14
  REQUEST_METHOD_DELETE,
5
15
  REQUEST_METHOD_GET,
6
16
  REQUEST_METHOD_POST,
7
17
  REQUEST_METHOD_PUT,
8
18
  )
9
- from workos.utils.validation import ORGANIZATIONS_MODULE, validate_settings
19
+ from workos.types.organizations import Organization
20
+ from workos.types.list_resource import ListMetadata, ListPage, WorkOSListResource
10
21
 
11
22
  ORGANIZATIONS_PATH = "organizations"
12
- RESPONSE_LIMIT = 10
13
23
 
14
24
 
15
- class Organizations(object):
16
- @validate_settings(ORGANIZATIONS_MODULE)
17
- def __init__(self):
18
- pass
25
+ OrganizationsListResource = WorkOSListResource[
26
+ Organization, OrganizationListFilters, ListMetadata
27
+ ]
28
+
29
+ FeatureFlagsListResource = WorkOSListResource[
30
+ FeatureFlag, FeatureFlagListFilters, ListMetadata
31
+ ]
32
+
19
33
 
20
- @property
21
- def request_helper(self):
22
- if not getattr(self, "_request_helper", None):
23
- self._request_helper = RequestHelper()
24
- return self._request_helper
34
+ class OrganizationsModule(Protocol):
35
+ """Offers methods through the WorkOS Organizations service."""
25
36
 
26
37
  def list_organizations(
27
- self, domains=None, limit=RESPONSE_LIMIT, before=None, after=None
28
- ):
38
+ self,
39
+ *,
40
+ domains: Optional[Sequence[str]] = None,
41
+ limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
42
+ before: Optional[str] = None,
43
+ after: Optional[str] = None,
44
+ order: PaginationOrder = "desc",
45
+ ) -> SyncOrAsync[OrganizationsListResource]:
29
46
  """Retrieve a list of organizations that have connections configured within your WorkOS dashboard.
30
47
 
31
48
  Kwargs:
@@ -33,90 +50,403 @@ class Organizations(object):
33
50
  limit (int): Maximum number of records to return. (Optional)
34
51
  before (str): Pagination cursor to receive records before a provided Organization ID. (Optional)
35
52
  after (str): Pagination cursor to receive records after a provided Organization ID. (Optional)
53
+ order (Literal["asc","desc"]): Sort records in either ascending or descending (default) order by created_at timestamp. (Optional)
36
54
 
37
55
  Returns:
38
- dict: Organizations response from WorkOS.
56
+ OrganizationsListResource: Organizations list response from WorkOS.
39
57
  """
40
- params = {
41
- "domains": domains,
58
+ ...
59
+
60
+ def get_organization(self, organization_id: str) -> SyncOrAsync[Organization]:
61
+ """Gets details for a single Organization
62
+
63
+ Args:
64
+ organization_id (str): Organization's unique identifier
65
+ Returns:
66
+ Organization: Organization response from WorkOS
67
+ """
68
+ ...
69
+
70
+ def get_organization_by_external_id(
71
+ self, external_id: str
72
+ ) -> SyncOrAsync[Organization]:
73
+ """Gets details for a single Organization by external id
74
+
75
+ Args:
76
+ external_id (str): Organization's external id
77
+
78
+ Returns:
79
+ Organization: Organization response from WorkOS
80
+ """
81
+ ...
82
+
83
+ def create_organization(
84
+ self,
85
+ *,
86
+ name: str,
87
+ domain_data: Optional[Sequence[DomainDataInput]] = None,
88
+ idempotency_key: Optional[str] = None,
89
+ external_id: Optional[str] = None,
90
+ metadata: Optional[Metadata] = None,
91
+ ) -> SyncOrAsync[Organization]:
92
+ """Create an organization
93
+
94
+ Kwargs:
95
+ name (str): A descriptive name for the organization. (Optional)
96
+ domain_data (Sequence[DomainDataInput]): List of domains that belong to the organization. (Optional)
97
+ idempotency_key (str): Key to guarantee idempotency across requests. (Optional)
98
+
99
+ Returns:
100
+ Organization: Updated Organization response from WorkOS.
101
+ """
102
+ ...
103
+
104
+ def update_organization(
105
+ self,
106
+ *,
107
+ organization_id: str,
108
+ name: Optional[str] = None,
109
+ domain_data: Optional[Sequence[DomainDataInput]] = None,
110
+ external_id: Optional[str] = None,
111
+ metadata: Optional[Metadata] = None,
112
+ ) -> SyncOrAsync[Organization]:
113
+ """Update an organization
114
+
115
+ Kwargs:
116
+ organization (str): Organization's unique identifier.
117
+ name (str): A descriptive name for the organization. (Optional)
118
+ domain_data (Sequence[DomainDataInput]): List of domains that belong to the organization. (Optional)
119
+ stripe_customer_id (str): The ID of the Stripe customer associated with the organization. (Optional)
120
+
121
+ Returns:
122
+ Organization: Updated Organization response from WorkOS.
123
+ """
124
+ ...
125
+
126
+ def delete_organization(self, organization_id: str) -> SyncOrAsync[None]:
127
+ """Deletes a single Organization
128
+
129
+ Args:
130
+ organization_id (str): Organization unique identifier
131
+
132
+ Returns:
133
+ None
134
+ """
135
+ ...
136
+
137
+ def list_feature_flags(
138
+ self,
139
+ organization_id: str,
140
+ *,
141
+ limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
142
+ before: Optional[str] = None,
143
+ after: Optional[str] = None,
144
+ order: PaginationOrder = "desc",
145
+ ) -> SyncOrAsync[FeatureFlagsListResource]:
146
+ """Retrieve a list of feature flags for an organization
147
+
148
+ Args:
149
+ organization_id (str): Organization's unique identifier
150
+ limit (int): Maximum number of records to return. (Optional)
151
+ before (str): Pagination cursor to receive records before a provided Feature Flag ID. (Optional)
152
+ after (str): Pagination cursor to receive records after a provided Feature Flag ID. (Optional)
153
+ order (Literal["asc","desc"]): Sort records in either ascending or descending (default) order by created_at timestamp. (Optional)
154
+
155
+ Returns:
156
+ FeatureFlagsListResource: Feature flags list response from WorkOS.
157
+ """
158
+ ...
159
+
160
+
161
+ class Organizations(OrganizationsModule):
162
+ _http_client: SyncHTTPClient
163
+
164
+ def __init__(self, http_client: SyncHTTPClient):
165
+ self._http_client = http_client
166
+
167
+ def list_organizations(
168
+ self,
169
+ *,
170
+ domains: Optional[Sequence[str]] = None,
171
+ limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
172
+ before: Optional[str] = None,
173
+ after: Optional[str] = None,
174
+ order: PaginationOrder = "desc",
175
+ ) -> OrganizationsListResource:
176
+ list_params: OrganizationListFilters = {
42
177
  "limit": limit,
43
178
  "before": before,
44
179
  "after": after,
180
+ "order": order,
181
+ "domains": domains,
45
182
  }
46
- return self.request_helper.request(
183
+
184
+ response = self._http_client.request(
47
185
  ORGANIZATIONS_PATH,
48
186
  method=REQUEST_METHOD_GET,
49
- params=params,
50
- token=workos.api_key,
187
+ params=list_params,
51
188
  )
52
189
 
53
- def get_organization(self, organization):
54
- """Gets details for a single Organization
55
- Args:
56
- organization (str): Organization's unique identifier
57
- Returns:
58
- dict: Organization response from WorkOS
59
- """
60
- return self.request_helper.request(
61
- "organizations/{organization}".format(organization=organization),
190
+ return WorkOSListResource[Organization, OrganizationListFilters, ListMetadata](
191
+ list_method=self.list_organizations,
192
+ list_args=list_params,
193
+ **ListPage[Organization](**response).model_dump(),
194
+ )
195
+
196
+ def get_organization(self, organization_id: str) -> Organization:
197
+ response = self._http_client.request(
198
+ f"organizations/{organization_id}", method=REQUEST_METHOD_GET
199
+ )
200
+
201
+ return Organization.model_validate(response)
202
+
203
+ def get_organization_by_external_id(self, external_id: str) -> Organization:
204
+ response = self._http_client.request(
205
+ "organizations/external_id/{external_id}".format(external_id=external_id),
62
206
  method=REQUEST_METHOD_GET,
63
- token=workos.api_key,
64
207
  )
65
208
 
66
- def create_organization(self, organization):
67
- """Create an organization
209
+ return Organization.model_validate(response)
68
210
 
69
- Args:
70
- organization (dict) - An organization object
71
- organization[name] (str) - A unique, descriptive name for the organization
72
- organization[allow_profiles_outside_organization] (boolean) - Whether Connections
73
- within the Organization allow profiles that are outside of the Organization's
74
- configured User Email Domains. (Optional)
75
- organization[domains] (list) - List of domains that belong to the organization
211
+ def create_organization(
212
+ self,
213
+ *,
214
+ name: str,
215
+ domain_data: Optional[Sequence[DomainDataInput]] = None,
216
+ idempotency_key: Optional[str] = None,
217
+ external_id: Optional[str] = None,
218
+ metadata: Optional[Metadata] = None,
219
+ ) -> Organization:
220
+ headers = {}
221
+ if idempotency_key:
222
+ headers["idempotency-key"] = idempotency_key
76
223
 
77
- Returns:
78
- dict: Created Organization response from WorkOS.
79
- """
80
- return self.request_helper.request(
224
+ json = {
225
+ "name": name,
226
+ "domain_data": domain_data,
227
+ "idempotency_key": idempotency_key,
228
+ "external_id": external_id,
229
+ "metadata": metadata,
230
+ }
231
+
232
+ response = self._http_client.request(
81
233
  ORGANIZATIONS_PATH,
82
234
  method=REQUEST_METHOD_POST,
83
- params=organization,
84
- token=workos.api_key,
235
+ json=json,
236
+ headers=headers,
85
237
  )
86
238
 
87
- def update_organization(self, organization, name, domains=None):
88
- """Update an organization
239
+ return Organization.model_validate(response)
89
240
 
90
- Args:
91
- organization(str) - Organization's unique identifier.
92
- name (str) - A unique, descriptive name for the organization.
93
- organization[allow_profiles_outside_organization] (boolean) - Whether Connections
94
- within the Organization allow profiles that are outside of the Organization's
95
- configured User Email Domains. (Optional)
96
- domains (list) - List of domains that belong to the organization. (Optional)
241
+ def update_organization(
242
+ self,
243
+ *,
244
+ organization_id: str,
245
+ name: Optional[str] = None,
246
+ domain_data: Optional[Sequence[DomainDataInput]] = None,
247
+ stripe_customer_id: Optional[str] = None,
248
+ external_id: Optional[str] = None,
249
+ metadata: Optional[Metadata] = None,
250
+ ) -> Organization:
251
+ json = {
252
+ "name": name,
253
+ "domain_data": domain_data,
254
+ "stripe_customer_id": stripe_customer_id,
255
+ "external_id": external_id,
256
+ "metadata": metadata,
257
+ }
97
258
 
98
- Returns:
99
- dict: Updated Organization response from WorkOS.
100
- """
101
- params = {
259
+ response = self._http_client.request(
260
+ f"organizations/{organization_id}", method=REQUEST_METHOD_PUT, json=json
261
+ )
262
+
263
+ return Organization.model_validate(response)
264
+
265
+ def delete_organization(self, organization_id: str) -> None:
266
+ self._http_client.request(
267
+ f"organizations/{organization_id}",
268
+ method=REQUEST_METHOD_DELETE,
269
+ )
270
+
271
+ def list_organization_roles(self, organization_id: str) -> RoleList:
272
+ response = self._http_client.request(
273
+ f"organizations/{organization_id}/roles",
274
+ method=REQUEST_METHOD_GET,
275
+ )
276
+
277
+ return RoleList.model_validate(response)
278
+
279
+ def list_feature_flags(
280
+ self,
281
+ organization_id: str,
282
+ *,
283
+ limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
284
+ before: Optional[str] = None,
285
+ after: Optional[str] = None,
286
+ order: PaginationOrder = "desc",
287
+ ) -> FeatureFlagsListResource:
288
+ list_params: FeatureFlagListFilters = {
289
+ "limit": limit,
290
+ "before": before,
291
+ "after": after,
292
+ "order": order,
293
+ }
294
+
295
+ response = self._http_client.request(
296
+ f"organizations/{organization_id}/feature-flags",
297
+ method=REQUEST_METHOD_GET,
298
+ params=list_params,
299
+ )
300
+
301
+ return WorkOSListResource[FeatureFlag, FeatureFlagListFilters, ListMetadata](
302
+ list_method=self.list_feature_flags,
303
+ list_args=list_params,
304
+ **ListPage[FeatureFlag](**response).model_dump(),
305
+ )
306
+
307
+
308
+ class AsyncOrganizations(OrganizationsModule):
309
+ _http_client: AsyncHTTPClient
310
+
311
+ def __init__(self, http_client: AsyncHTTPClient):
312
+ self._http_client = http_client
313
+
314
+ async def list_organizations(
315
+ self,
316
+ *,
317
+ domains: Optional[Sequence[str]] = None,
318
+ limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
319
+ before: Optional[str] = None,
320
+ after: Optional[str] = None,
321
+ order: PaginationOrder = "desc",
322
+ ) -> OrganizationsListResource:
323
+ list_params: OrganizationListFilters = {
324
+ "limit": limit,
325
+ "before": before,
326
+ "after": after,
327
+ "order": order,
102
328
  "domains": domains,
329
+ }
330
+
331
+ response = await self._http_client.request(
332
+ ORGANIZATIONS_PATH,
333
+ method=REQUEST_METHOD_GET,
334
+ params=list_params,
335
+ )
336
+
337
+ return WorkOSListResource[Organization, OrganizationListFilters, ListMetadata](
338
+ list_method=self.list_organizations,
339
+ list_args=list_params,
340
+ **ListPage[Organization](**response).model_dump(),
341
+ )
342
+
343
+ async def get_organization(self, organization_id: str) -> Organization:
344
+ response = await self._http_client.request(
345
+ f"organizations/{organization_id}", method=REQUEST_METHOD_GET
346
+ )
347
+
348
+ return Organization.model_validate(response)
349
+
350
+ async def get_organization_by_external_id(self, external_id: str) -> Organization:
351
+ response = await self._http_client.request(
352
+ "organizations/external_id/{external_id}".format(external_id=external_id),
353
+ method=REQUEST_METHOD_GET,
354
+ )
355
+
356
+ return Organization.model_validate(response)
357
+
358
+ async def create_organization(
359
+ self,
360
+ *,
361
+ name: str,
362
+ domain_data: Optional[Sequence[DomainDataInput]] = None,
363
+ idempotency_key: Optional[str] = None,
364
+ external_id: Optional[str] = None,
365
+ metadata: Optional[Metadata] = None,
366
+ ) -> Organization:
367
+ headers = {}
368
+ if idempotency_key:
369
+ headers["idempotency-key"] = idempotency_key
370
+
371
+ json = {
103
372
  "name": name,
373
+ "domain_data": domain_data,
374
+ "idempotency_key": idempotency_key,
375
+ "external_id": external_id,
376
+ "metadata": metadata,
104
377
  }
105
- return self.request_helper.request(
106
- "organizations/{organization}".format(organization=organization),
107
- method=REQUEST_METHOD_PUT,
108
- params=params,
109
- token=workos.api_key,
378
+
379
+ response = await self._http_client.request(
380
+ ORGANIZATIONS_PATH,
381
+ method=REQUEST_METHOD_POST,
382
+ json=json,
383
+ headers=headers,
110
384
  )
111
385
 
112
- def delete_organization(self, organization):
113
- """Deletes a single Organization
386
+ return Organization.model_validate(response)
114
387
 
115
- Args:
116
- organization (str): Organization unique identifier
117
- """
118
- return self.request_helper.request(
119
- "organizations/{organization}".format(organization=organization),
388
+ async def update_organization(
389
+ self,
390
+ *,
391
+ organization_id: str,
392
+ name: Optional[str] = None,
393
+ domain_data: Optional[Sequence[DomainDataInput]] = None,
394
+ stripe_customer_id: Optional[str] = None,
395
+ external_id: Optional[str] = None,
396
+ metadata: Optional[Metadata] = None,
397
+ ) -> Organization:
398
+ json = {
399
+ "name": name,
400
+ "domain_data": domain_data,
401
+ "stripe_customer_id": stripe_customer_id,
402
+ "external_id": external_id,
403
+ "metadata": metadata,
404
+ }
405
+
406
+ response = await self._http_client.request(
407
+ f"organizations/{organization_id}", method=REQUEST_METHOD_PUT, json=json
408
+ )
409
+
410
+ return Organization.model_validate(response)
411
+
412
+ async def delete_organization(self, organization_id: str) -> None:
413
+ await self._http_client.request(
414
+ f"organizations/{organization_id}",
120
415
  method=REQUEST_METHOD_DELETE,
121
- token=workos.api_key,
416
+ )
417
+
418
+ async def list_organization_roles(self, organization_id: str) -> RoleList:
419
+ response = await self._http_client.request(
420
+ f"organizations/{organization_id}/roles",
421
+ method=REQUEST_METHOD_GET,
422
+ )
423
+
424
+ return RoleList.model_validate(response)
425
+
426
+ async def list_feature_flags(
427
+ self,
428
+ organization_id: str,
429
+ *,
430
+ limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
431
+ before: Optional[str] = None,
432
+ after: Optional[str] = None,
433
+ order: PaginationOrder = "desc",
434
+ ) -> FeatureFlagsListResource:
435
+ list_params: FeatureFlagListFilters = {
436
+ "limit": limit,
437
+ "before": before,
438
+ "after": after,
439
+ "order": order,
440
+ }
441
+
442
+ response = await self._http_client.request(
443
+ f"organizations/{organization_id}/feature-flags",
444
+ method=REQUEST_METHOD_GET,
445
+ params=list_params,
446
+ )
447
+
448
+ return WorkOSListResource[FeatureFlag, FeatureFlagListFilters, ListMetadata](
449
+ list_method=self.list_feature_flags,
450
+ list_args=list_params,
451
+ **ListPage[FeatureFlag](**response).model_dump(),
122
452
  )
workos/passwordless.py CHANGED
@@ -1,54 +1,46 @@
1
- import workos
2
- from workos.utils.request import RequestHelper, REQUEST_METHOD_POST
3
- from workos.utils.validation import PASSWORDLESS_MODULE, validate_settings
1
+ from typing import Literal, Optional, Protocol
4
2
 
3
+ from workos.types.passwordless.passwordless_session_type import PasswordlessSessionType
4
+ from workos.utils.http_client import SyncHTTPClient
5
+ from workos.utils.request_helper import REQUEST_METHOD_POST
6
+ from workos.types.passwordless.passwordless_session import PasswordlessSession
5
7
 
6
- class Passwordless(object):
7
- """Offers methods through the WorkOS Passwordless service."""
8
-
9
- @validate_settings(PASSWORDLESS_MODULE)
10
- def __init__(self):
11
- pass
12
8
 
13
- @property
14
- def request_helper(self):
15
- if not getattr(self, "_request_helper", None):
16
- self._request_helper = RequestHelper()
17
- return self._request_helper
9
+ class PasswordlessModule(Protocol):
10
+ """Offers methods through the WorkOS Passwordless service."""
18
11
 
19
- def create_session(self, session_options):
12
+ def create_session(
13
+ self,
14
+ *,
15
+ email: str,
16
+ type: PasswordlessSessionType,
17
+ redirect_uri: Optional[str] = None,
18
+ state: Optional[str] = None,
19
+ expires_in: Optional[int] = None,
20
+ ) -> PasswordlessSession:
20
21
  """Create a Passwordless Session.
21
22
 
22
- Args:
23
- session_options (dict) - An session options object
24
- session_options[email] (str): The email of the user to authenticate.
25
- session_options[redirect_uri] (str): Optional parameter to
26
- specify the redirect endpoint which will handle the callback
27
- from WorkOS. Defaults to the default Redirect URI in the
28
- WorkOS dashboard.
29
- session_options[state] (str): Optional parameter that the redirect
30
- URI received from WorkOS will contain. The state parameter
31
- can be used to encode arbitrary information to help
32
- restore application state between redirects.
33
- session_options[type] (str): The type of Passwordless Session to
34
- create. Currently, the only supported value is 'MagicLink'.
35
- session_options[connection] (str): Optional parameter for the ID of a
36
- specific connection. Can be used to create a Passwordless Session
37
- for a specific connection rather than using the domain from the email
38
- to determine the Organization and Connection.
23
+ Kwargs:
24
+ email (str): The email of the user to authenticate.
25
+ type (PasswordlessSessionType): The type of Passwordless Session to
26
+ create. Currently, the only supported value is 'MagicLink'.
27
+ redirect_uri (str): Optional parameter to
28
+ specify the redirect endpoint which will handle the callback
29
+ from WorkOS. Defaults to the default Redirect URI in the
30
+ WorkOS dashboard. (Optional)
31
+ state (str): Optional parameter that the redirect
32
+ URI received from WorkOS will contain. The state parameter
33
+ can be used to encode arbitrary information to help
34
+ restore application state between redirects. (Optional)
35
+ expires_in (int): The number of seconds the Passwordless Session should live before expiring.
36
+ This value must be between 900 (15 minutes) and 86400 (24 hours), inclusive. (Optional)
39
37
 
40
38
  Returns:
41
- dict: Passwordless Session
39
+ PasswordlessSession: A passwordless session object.
42
40
  """
41
+ ...
43
42
 
44
- return self.request_helper.request(
45
- "passwordless/sessions",
46
- method=REQUEST_METHOD_POST,
47
- params=session_options,
48
- token=workos.api_key,
49
- )
50
-
51
- def send_session(self, session_id):
43
+ def send_session(self, session_id: str) -> Literal[True]:
52
44
  """Send a Passwordless Session via email.
53
45
 
54
46
  Args:
@@ -58,10 +50,42 @@ class Passwordless(object):
58
50
  Returns:
59
51
  boolean: Returns True
60
52
  """
61
- self.request_helper.request(
53
+ ...
54
+
55
+
56
+ class Passwordless(PasswordlessModule):
57
+ _http_client: SyncHTTPClient
58
+
59
+ def __init__(self, http_client: SyncHTTPClient):
60
+ self._http_client = http_client
61
+
62
+ def create_session(
63
+ self,
64
+ *,
65
+ email: str,
66
+ type: PasswordlessSessionType,
67
+ redirect_uri: Optional[str] = None,
68
+ state: Optional[str] = None,
69
+ expires_in: Optional[int] = None,
70
+ ) -> PasswordlessSession:
71
+ json = {
72
+ "email": email,
73
+ "type": type,
74
+ "expires_in": expires_in,
75
+ "redirect_uri": redirect_uri,
76
+ "state": state,
77
+ }
78
+
79
+ response = self._http_client.request(
80
+ "passwordless/sessions", method=REQUEST_METHOD_POST, json=json
81
+ )
82
+
83
+ return PasswordlessSession.model_validate(response)
84
+
85
+ def send_session(self, session_id: str) -> Literal[True]:
86
+ self._http_client.request(
62
87
  "passwordless/sessions/{session_id}/send".format(session_id=session_id),
63
88
  method=REQUEST_METHOD_POST,
64
- token=workos.api_key,
65
89
  )
66
90
 
67
91
  return True