@tula-tech/core 0.2.0 → 0.3.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/dist/index.d.ts +1132 -92
- package/dist/index.js +684 -399
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,27 @@ import { DeviceKey as DeviceKey2 } from "@tula-tech/contract/device-binding";
|
|
|
4
4
|
import { ErrorCode as ErrorCode2 } from "@tula-tech/contract/error-codes";
|
|
5
5
|
/** Schemas of the client API (`/v1/client/*`), by their name in the OpenAPI document. */
|
|
6
6
|
interface Schemas {
|
|
7
|
+
AcceptedInvitation: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
slug: string;
|
|
11
|
+
role: string;
|
|
12
|
+
permissions: string[];
|
|
13
|
+
createdAt: string;
|
|
14
|
+
};
|
|
15
|
+
ActiveOrganization: {
|
|
16
|
+
sessionId: string;
|
|
17
|
+
organizationId: string | null;
|
|
18
|
+
accessToken?: string;
|
|
19
|
+
accessTokenExpiresAt?: string;
|
|
20
|
+
};
|
|
21
|
+
AssignableRole: {
|
|
22
|
+
key: string;
|
|
23
|
+
name: string;
|
|
24
|
+
};
|
|
25
|
+
AssignableRoleList: {
|
|
26
|
+
data: Schemas["AssignableRole"][];
|
|
27
|
+
};
|
|
7
28
|
BackupCodes: {
|
|
8
29
|
codes: string[];
|
|
9
30
|
};
|
|
@@ -31,6 +52,50 @@ interface Schemas {
|
|
|
31
52
|
phone?: {
|
|
32
53
|
enabled: boolean;
|
|
33
54
|
};
|
|
55
|
+
organizations?: {
|
|
56
|
+
enabled: boolean;
|
|
57
|
+
allowUserCreated: boolean;
|
|
58
|
+
personalAccount: boolean;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
CreateMySetupLinkRequest: {
|
|
62
|
+
name?: string;
|
|
63
|
+
expiresInDays?: number;
|
|
64
|
+
};
|
|
65
|
+
CreateMySsoConnectionRequest: {
|
|
66
|
+
protocol?: "oidc" | "saml";
|
|
67
|
+
name: string;
|
|
68
|
+
issuer?: string;
|
|
69
|
+
clientId?: string;
|
|
70
|
+
clientSecret?: string;
|
|
71
|
+
saml?: Schemas["SamlSettingsInput"];
|
|
72
|
+
attributeMapping?: Schemas["SsoAttributeMapping"];
|
|
73
|
+
defaultRole?: Schemas["OrganizationRoleKey"];
|
|
74
|
+
domains?: Schemas["OrganizationDomainName"][];
|
|
75
|
+
};
|
|
76
|
+
CreateOrganizationInvitationRequest: {
|
|
77
|
+
email: string;
|
|
78
|
+
role: Schemas["OrganizationRoleKey"];
|
|
79
|
+
redirectUrl: string;
|
|
80
|
+
};
|
|
81
|
+
CreateOrganizationRequest: {
|
|
82
|
+
name: string;
|
|
83
|
+
slug: Schemas["OrganizationSlug"];
|
|
84
|
+
};
|
|
85
|
+
CreatedSetupLink: {
|
|
86
|
+
id: string;
|
|
87
|
+
organizationId: string;
|
|
88
|
+
name: string;
|
|
89
|
+
/** The start of the token, to tell links apart in a list. */
|
|
90
|
+
prefix: string;
|
|
91
|
+
expiresAt: string;
|
|
92
|
+
revokedAt: string | null;
|
|
93
|
+
lastUsedAt: string | null;
|
|
94
|
+
createdAt: string;
|
|
95
|
+
/** The setup token. Shown once; only its hash is stored. */
|
|
96
|
+
token: string;
|
|
97
|
+
/** The address to send to the IT administrator. The token is in its fragment. */
|
|
98
|
+
url: string;
|
|
34
99
|
};
|
|
35
100
|
CurrentUser: {
|
|
36
101
|
id: string;
|
|
@@ -64,7 +129,7 @@ interface Schemas {
|
|
|
64
129
|
status: "verified";
|
|
65
130
|
};
|
|
66
131
|
EmailVerificationStrategy: "email_code" | "email_link";
|
|
67
|
-
ErrorCode: "auth.invalid_credentials" | "auth.unauthenticated" | "auth.invalid_key" | "auth.forbidden" | "auth.user_banned" | "auth.method_disabled" | "auth.step_up_required" | "flow.not_found" | "flow.invalid_step" | "email.invalid" | "email.already_set" | "password.too_short" | "password.too_long" | "password.missing_lowercase" | "password.missing_uppercase" | "password.missing_number" | "password.missing_special" | "password.too_few_character_classes" | "password.contains_user_info" | "password.common" | "password.breached" | "password.repeated_characters" | "password.sequence" | "password.reused" | "password.not_set" | "verification.invalid_code" | "verification.expired" | "verification.too_many_attempts" | "verification.different_browser" | "mfa.invalid_code" | "mfa.already_enabled" | "mfa.not_enabled" | "mfa.enrolment_expired" | "mfa.not_available" | "mfa.enrolment_needs_other_sign_in" | "mfa.needs_other_sign_in" | "mfa.sms_not_allowed" | "mfa.phone_number_required" | "mfa.required_by_policy" | "oauth.access_denied" | "oauth.provider_error" | "oauth.state_invalid" | "oauth.ticket_invalid" | "oauth.different_browser" | "oauth.email_missing" | "oauth.email_unverified" | "oauth.account_exists" | "oauth.identity_in_use" | "oauth.already_linked" | "identity.last_sign_in_method" | "webhook.url_not_allowed" | "webhook.cannot_redeliver" | "webhook.rotation_refused" | "hook.denied" | "hook.unavailable" | "hook.url_not_allowed" | "passkey.registration_failed" | "passkey.already_registered" | "passkey.limit_reached" | "passkey.last_sign_in_method" | "phone.invalid" | "sms.disabled" | "sms.country_not_allowed" | "sms.unavailable" | "session.invalid_token" | "session.expired" | "session.revoked" | "session.reuse_detected" | "session.limit_reached" | "device.proof_invalid" | "device.nonce_required" | "device.binding_not_supported" | "device.binding_required" | "rate_limited" | "request.malformed" | "request.too_large" | "request.origin_not_allowed" | "request.redirect_not_allowed" | "validation.failed" | "resource.not_found" | "resource.conflict" | "precondition.required" | "precondition.failed" | "not_implemented" | "service.unavailable" | "internal";
|
|
132
|
+
ErrorCode: "auth.invalid_credentials" | "auth.unauthenticated" | "auth.invalid_key" | "auth.forbidden" | "auth.user_banned" | "auth.method_disabled" | "auth.step_up_required" | "flow.not_found" | "flow.invalid_step" | "email.invalid" | "email.already_set" | "password.too_short" | "password.too_long" | "password.missing_lowercase" | "password.missing_uppercase" | "password.missing_number" | "password.missing_special" | "password.too_few_character_classes" | "password.contains_user_info" | "password.common" | "password.breached" | "password.repeated_characters" | "password.sequence" | "password.reused" | "password.not_set" | "import.unsupported_algorithm" | "import.hash_malformed" | "import.hash_parameters_too_weak" | "import.hash_parameters_too_costly" | "verification.invalid_code" | "verification.expired" | "verification.too_many_attempts" | "verification.different_browser" | "mfa.invalid_code" | "mfa.already_enabled" | "mfa.not_enabled" | "mfa.enrolment_expired" | "mfa.not_available" | "mfa.enrolment_needs_other_sign_in" | "mfa.needs_other_sign_in" | "mfa.sms_not_allowed" | "mfa.phone_number_required" | "mfa.required_by_policy" | "oauth.access_denied" | "oauth.provider_error" | "oauth.state_invalid" | "oauth.ticket_invalid" | "oauth.different_browser" | "oauth.email_missing" | "oauth.email_unverified" | "oauth.account_exists" | "oauth.identity_in_use" | "oauth.already_linked" | "identity.last_sign_in_method" | "webhook.url_not_allowed" | "webhook.cannot_redeliver" | "webhook.rotation_refused" | "hook.denied" | "hook.unavailable" | "hook.url_not_allowed" | "passkey.registration_failed" | "passkey.already_registered" | "passkey.limit_reached" | "passkey.last_sign_in_method" | "phone.invalid" | "sms.disabled" | "sms.country_not_allowed" | "sms.unavailable" | "session.invalid_token" | "session.expired" | "session.revoked" | "session.reuse_detected" | "session.limit_reached" | "device.proof_invalid" | "device.nonce_required" | "device.binding_not_supported" | "device.binding_required" | "user.last_organization_manager" | "user.managed" | "organization.disabled" | "organization.slug_taken" | "organization.member_exists" | "organization.last_manager" | "organization.role_unknown" | "organization.not_a_member" | "organization.creation_disabled" | "organization.limit_reached" | "organization.personal_account_disabled" | "organization.role_exists" | "organization.role_in_use" | "organization.role_built_in" | "organization.role_limit" | "organization.permission_required" | "organization.role_not_assignable" | "organization.invitation_exists" | "organization.invitation_not_found" | "organization.invitation_expired" | "organization.invitation_revoked" | "organization.invitation_used" | "organization.invitation_wrong_account" | "organization.invitation_email_unverified" | "organization.invitation_role_gone" | "organization.domain_public" | "organization.domain_taken" | "organization.domain_address_mismatch" | "organization.domain_limit" | "organization.suggestion_unavailable" | "sso.disabled" | "sso.connection_not_found" | "sso.name_taken" | "sso.domain_taken" | "sso.domain_not_verified" | "sso.issuer_not_allowed" | "sso.saml_invalid" | "sso.connection_in_use" | "sso.invalid_transition" | "sso.url_not_https" | "sso.test_required" | "sso.test_not_found" | "sso.role_not_allowed" | "sso.unavailable" | "sso.provider_error" | "sso.user_not_provisioned" | "sso.email_domain_mismatch" | "rate_limited" | "request.malformed" | "request.too_large" | "request.origin_not_allowed" | "request.redirect_not_allowed" | "validation.failed" | "resource.not_found" | "resource.conflict" | "precondition.required" | "precondition.failed" | "not_implemented" | "service.unavailable" | "internal";
|
|
68
133
|
ErrorEnvelope: {
|
|
69
134
|
status: number;
|
|
70
135
|
code: Schemas["ErrorCode"];
|
|
@@ -110,7 +175,7 @@ interface Schemas {
|
|
|
110
175
|
strategy: Schemas["PreparedFirstFactorStrategy"];
|
|
111
176
|
redirectUrl?: string;
|
|
112
177
|
};
|
|
113
|
-
FirstFactorStrategy: "password" | "email_code" | "email_link" | "passkey" | "sms_code" | "oauth_google" | "oauth_github" | "oauth_apple" | "oauth_microsoft" | "oauth_discord" | "oauth_linkedin" | "oauth_x" | "oauth_facebook";
|
|
178
|
+
FirstFactorStrategy: "password" | "email_code" | "email_link" | "passkey" | "sms_code" | "oauth_google" | "oauth_github" | "oauth_apple" | "oauth_microsoft" | "oauth_discord" | "oauth_linkedin" | "oauth_x" | "oauth_facebook" | "sso";
|
|
114
179
|
FlowAttempt: {
|
|
115
180
|
id: string;
|
|
116
181
|
kind: Schemas["FlowKind"];
|
|
@@ -185,7 +250,26 @@ interface Schemas {
|
|
|
185
250
|
IdentityList: {
|
|
186
251
|
data: Schemas["Identity"][];
|
|
187
252
|
};
|
|
253
|
+
InvitationPreview: {
|
|
254
|
+
organizationName: string;
|
|
255
|
+
role: string;
|
|
256
|
+
email: string;
|
|
257
|
+
expiresAt: string;
|
|
258
|
+
};
|
|
259
|
+
InvitationTokenRequest: {
|
|
260
|
+
token: string;
|
|
261
|
+
};
|
|
188
262
|
MfaPolicy: "off" | "optional" | "required";
|
|
263
|
+
MyOrganizationInvitation: {
|
|
264
|
+
id: string;
|
|
265
|
+
organizationName: string;
|
|
266
|
+
role: string;
|
|
267
|
+
expiresAt: string;
|
|
268
|
+
};
|
|
269
|
+
MyOrganizationInvitationList: {
|
|
270
|
+
meta: Schemas["PaginationMeta"];
|
|
271
|
+
data: Schemas["MyOrganizationInvitation"][];
|
|
272
|
+
};
|
|
189
273
|
NewPasswordReason: "expired";
|
|
190
274
|
NewPasswordRequest: {
|
|
191
275
|
password: string;
|
|
@@ -205,6 +289,64 @@ interface Schemas {
|
|
|
205
289
|
provider: Schemas["OAuthProvider"];
|
|
206
290
|
redirectUrl: string;
|
|
207
291
|
};
|
|
292
|
+
OrganizationDomain: {
|
|
293
|
+
id: string;
|
|
294
|
+
domain: string;
|
|
295
|
+
mode: Schemas["OrganizationDomainMode"];
|
|
296
|
+
status: Schemas["OrganizationDomainStatus"];
|
|
297
|
+
verifiedAt: string | null;
|
|
298
|
+
expiresAt: string | null;
|
|
299
|
+
codeExpiresAt: string | null;
|
|
300
|
+
createdAt: string;
|
|
301
|
+
updatedAt: string;
|
|
302
|
+
};
|
|
303
|
+
OrganizationDomainList: {
|
|
304
|
+
data: Schemas["OrganizationDomain"][];
|
|
305
|
+
};
|
|
306
|
+
OrganizationDomainMode: "suggest" | "auto_join";
|
|
307
|
+
OrganizationDomainName: string;
|
|
308
|
+
OrganizationDomainStatus: "pending" | "verified" | "needs_reverification";
|
|
309
|
+
OrganizationInvitation: {
|
|
310
|
+
id: string;
|
|
311
|
+
organizationId: string;
|
|
312
|
+
email: string;
|
|
313
|
+
role: string;
|
|
314
|
+
status: "pending" | "accepted" | "declined" | "revoked" | "expired";
|
|
315
|
+
invitedBy: string | null;
|
|
316
|
+
expiresAt: string;
|
|
317
|
+
createdAt: string;
|
|
318
|
+
};
|
|
319
|
+
OrganizationInvitationList: {
|
|
320
|
+
meta: Schemas["PaginationMeta"];
|
|
321
|
+
data: Schemas["OrganizationInvitation"][];
|
|
322
|
+
};
|
|
323
|
+
OrganizationMember: {
|
|
324
|
+
userId: string;
|
|
325
|
+
name: string | null;
|
|
326
|
+
email: string | null;
|
|
327
|
+
role: string;
|
|
328
|
+
createdAt: string;
|
|
329
|
+
};
|
|
330
|
+
OrganizationMemberList: {
|
|
331
|
+
meta: Schemas["PaginationMeta"];
|
|
332
|
+
data: Schemas["OrganizationMember"][];
|
|
333
|
+
};
|
|
334
|
+
OrganizationRoleKey: string;
|
|
335
|
+
OrganizationSlug: string;
|
|
336
|
+
OrganizationSuggestion: {
|
|
337
|
+
id: string;
|
|
338
|
+
name: string;
|
|
339
|
+
slug: string;
|
|
340
|
+
};
|
|
341
|
+
OrganizationSuggestionList: {
|
|
342
|
+
data: Schemas["OrganizationSuggestion"][];
|
|
343
|
+
};
|
|
344
|
+
PaginationMeta: {
|
|
345
|
+
totalCount: number;
|
|
346
|
+
totalPages: number;
|
|
347
|
+
page: number;
|
|
348
|
+
perPage: number;
|
|
349
|
+
};
|
|
208
350
|
Passkey: {
|
|
209
351
|
id: string;
|
|
210
352
|
name: string;
|
|
@@ -339,6 +481,26 @@ interface Schemas {
|
|
|
339
481
|
RevokedSessions: {
|
|
340
482
|
revoked: number;
|
|
341
483
|
};
|
|
484
|
+
SamlConnection: {
|
|
485
|
+
idpEntityId: string;
|
|
486
|
+
ssoUrl: string;
|
|
487
|
+
metadataUrl: string | null;
|
|
488
|
+
certificates: {
|
|
489
|
+
fingerprint: string;
|
|
490
|
+
notAfter: string;
|
|
491
|
+
expired: boolean;
|
|
492
|
+
}[];
|
|
493
|
+
spEntityId: string;
|
|
494
|
+
acsUrl: string;
|
|
495
|
+
spMetadataUrl: string;
|
|
496
|
+
};
|
|
497
|
+
SamlSettingsInput: {
|
|
498
|
+
metadataXml?: string;
|
|
499
|
+
metadataUrl?: string;
|
|
500
|
+
idpEntityId?: string;
|
|
501
|
+
ssoUrl?: string;
|
|
502
|
+
certificates?: string[];
|
|
503
|
+
};
|
|
342
504
|
SecondFactorMethod: "totp" | "passkey" | "backup_code" | "sms_code";
|
|
343
505
|
SecondFactorPrepareRequest: {
|
|
344
506
|
method: Schemas["PreparedSecondFactorMethod"];
|
|
@@ -377,6 +539,23 @@ interface Schemas {
|
|
|
377
539
|
accessTokenExpiresAt?: string;
|
|
378
540
|
refreshToken?: string;
|
|
379
541
|
};
|
|
542
|
+
SetActiveOrganizationRequest: {
|
|
543
|
+
organizationId: string | null;
|
|
544
|
+
};
|
|
545
|
+
SetupLink: {
|
|
546
|
+
id: string;
|
|
547
|
+
organizationId: string;
|
|
548
|
+
name: string;
|
|
549
|
+
/** The start of the token, to tell links apart in a list. */
|
|
550
|
+
prefix: string;
|
|
551
|
+
expiresAt: string;
|
|
552
|
+
revokedAt: string | null;
|
|
553
|
+
lastUsedAt: string | null;
|
|
554
|
+
createdAt: string;
|
|
555
|
+
};
|
|
556
|
+
SetupLinkList: {
|
|
557
|
+
links: Schemas["SetupLink"][];
|
|
558
|
+
};
|
|
380
559
|
SignInStartRequest: {
|
|
381
560
|
identifier: string;
|
|
382
561
|
};
|
|
@@ -395,6 +574,75 @@ interface Schemas {
|
|
|
395
574
|
SmsFactorConfirmRequest: {
|
|
396
575
|
code: string;
|
|
397
576
|
};
|
|
577
|
+
SsoAttributeMapping: {
|
|
578
|
+
idp?: "okta" | "entra" | "google_workspace" | "jumpcloud" | "onelogin" | "ping" | "generic";
|
|
579
|
+
email?: string;
|
|
580
|
+
firstName?: string;
|
|
581
|
+
lastName?: string;
|
|
582
|
+
groups?: string;
|
|
583
|
+
};
|
|
584
|
+
SsoConnection: {
|
|
585
|
+
id: string;
|
|
586
|
+
organizationId: string;
|
|
587
|
+
protocol: "oidc" | "saml";
|
|
588
|
+
name: string;
|
|
589
|
+
status: "draft" | "active" | "disabled";
|
|
590
|
+
issuer: string;
|
|
591
|
+
clientId: string;
|
|
592
|
+
clientSecretSet: boolean;
|
|
593
|
+
saml: Schemas["SamlConnection"] | null;
|
|
594
|
+
redirectUri: string | null;
|
|
595
|
+
attributeMapping: Schemas["SsoAttributeMapping"] | null;
|
|
596
|
+
defaultRole: string;
|
|
597
|
+
enforced: boolean;
|
|
598
|
+
breakGlassRole: string | null;
|
|
599
|
+
trustIdpMfa: boolean;
|
|
600
|
+
domains: string[];
|
|
601
|
+
tested: boolean;
|
|
602
|
+
createdAt: string;
|
|
603
|
+
updatedAt: string;
|
|
604
|
+
};
|
|
605
|
+
SsoConnectionList: {
|
|
606
|
+
connections: Schemas["SsoConnection"][];
|
|
607
|
+
};
|
|
608
|
+
SsoGroupRoles: {
|
|
609
|
+
mappings: {
|
|
610
|
+
group: string;
|
|
611
|
+
role: Schemas["OrganizationRoleKey"];
|
|
612
|
+
}[];
|
|
613
|
+
};
|
|
614
|
+
SsoStartRequest: {
|
|
615
|
+
redirectUrl: string;
|
|
616
|
+
};
|
|
617
|
+
SsoTestResult: {
|
|
618
|
+
testId: string;
|
|
619
|
+
status: "pending" | "passed" | "failed";
|
|
620
|
+
reason: "wrong_audience" | "wrong_issuer" | "wrong_recipient" | "unsigned_assertion" | "signature_invalid" | "signature_algorithm" | "certificate_not_trusted" | "certificate_expired" | "assertion_expired" | "clock_skew" | "response_not_to_this_request" | "replayed" | "idp_refused" | "encrypted_assertion" | "malformed_response" | "discovery_failed" | "token_exchange_failed" | "no_id_token" | "id_token_invalid" | "email_missing" | "email_outside_domains" | null;
|
|
621
|
+
message: string | null;
|
|
622
|
+
attributes: {
|
|
623
|
+
name: string;
|
|
624
|
+
values: string[];
|
|
625
|
+
}[];
|
|
626
|
+
groups: string[];
|
|
627
|
+
mapped: {
|
|
628
|
+
email: string | null;
|
|
629
|
+
givenName: string | null;
|
|
630
|
+
familyName: string | null;
|
|
631
|
+
emailOnVerifiedDomain: boolean;
|
|
632
|
+
} | null;
|
|
633
|
+
};
|
|
634
|
+
SsoTestStart: {
|
|
635
|
+
testId: string;
|
|
636
|
+
authorizationUrl: string;
|
|
637
|
+
};
|
|
638
|
+
SsoTestStartRequest: {
|
|
639
|
+
redirectUrl: string;
|
|
640
|
+
};
|
|
641
|
+
StartOrganizationDomainRequest: {
|
|
642
|
+
domain: Schemas["OrganizationDomainName"];
|
|
643
|
+
email: string;
|
|
644
|
+
mode: Schemas["OrganizationDomainMode"];
|
|
645
|
+
};
|
|
398
646
|
StepUpEmailCode: {
|
|
399
647
|
method: "email_code";
|
|
400
648
|
destination: string;
|
|
@@ -426,9 +674,49 @@ interface Schemas {
|
|
|
426
674
|
secret: string;
|
|
427
675
|
uri: string;
|
|
428
676
|
};
|
|
677
|
+
UpdateOrganizationDomainRequest: {
|
|
678
|
+
mode: Schemas["OrganizationDomainMode"];
|
|
679
|
+
};
|
|
680
|
+
UpdateOrganizationMemberRequest: {
|
|
681
|
+
role: Schemas["OrganizationRoleKey"];
|
|
682
|
+
};
|
|
683
|
+
UpdateOrganizationRequest: {
|
|
684
|
+
name?: string;
|
|
685
|
+
slug?: Schemas["OrganizationSlug"];
|
|
686
|
+
};
|
|
687
|
+
UpdateSsoConnectionRequest: {
|
|
688
|
+
name?: string;
|
|
689
|
+
issuer?: string;
|
|
690
|
+
clientId?: string;
|
|
691
|
+
clientSecret?: string;
|
|
692
|
+
saml?: Schemas["SamlSettingsInput"];
|
|
693
|
+
attributeMapping?: Schemas["SsoAttributeMapping"];
|
|
694
|
+
defaultRole?: Schemas["OrganizationRoleKey"];
|
|
695
|
+
enforced?: boolean;
|
|
696
|
+
breakGlassRole?: Schemas["OrganizationRoleKey"] | null;
|
|
697
|
+
trustIdpMfa?: boolean;
|
|
698
|
+
domains?: Schemas["OrganizationDomainName"][];
|
|
699
|
+
status?: "draft" | "active" | "disabled";
|
|
700
|
+
};
|
|
701
|
+
UserOrganization: {
|
|
702
|
+
id: string;
|
|
703
|
+
name: string;
|
|
704
|
+
slug: string;
|
|
705
|
+
role: string;
|
|
706
|
+
permissions: string[];
|
|
707
|
+
createdAt: string;
|
|
708
|
+
};
|
|
709
|
+
UserOrganizationList: {
|
|
710
|
+
activeOrganizationId: string | null;
|
|
711
|
+
meta: Schemas["PaginationMeta"];
|
|
712
|
+
data: Schemas["UserOrganization"][];
|
|
713
|
+
};
|
|
429
714
|
VerifyEmailRequest: {
|
|
430
715
|
code: string;
|
|
431
716
|
};
|
|
717
|
+
VerifyOrganizationDomainRequest: {
|
|
718
|
+
code: string;
|
|
719
|
+
};
|
|
432
720
|
}
|
|
433
721
|
/**
|
|
434
722
|
* The next step of a sign-up, sign-in or password reset, decided by the server and
|
|
@@ -528,7 +816,11 @@ type ClientKind = Schemas["SessionClient"];
|
|
|
528
816
|
* - `loading`: not known yet. Call `load()` (or `session.getToken()`) to find out.
|
|
529
817
|
* - `signed-out`: nobody is signed in.
|
|
530
818
|
* - `signed-in`: a session exists. `user` is `null` only until it has been fetched, or if
|
|
531
|
-
* fetching it failed; `user.get()` fetches it again.
|
|
819
|
+
* fetching it failed; `user.get()` fetches it again. `organizationId` is the organization
|
|
820
|
+
* the session acts in, `null` for the personal account. For a session with an
|
|
821
|
+
* access token it is read from the token's `org_id` claim (unverified: for showing, never
|
|
822
|
+
* for authorizing) and so follows every refresh; a browser's `stateful` session has no
|
|
823
|
+
* token, so it is known after `organizations.list()` or `organizations.setActive()`.
|
|
532
824
|
*
|
|
533
825
|
* @example
|
|
534
826
|
* ```ts
|
|
@@ -547,6 +839,7 @@ type AuthState = {
|
|
|
547
839
|
readonly status: "signed-in";
|
|
548
840
|
readonly sessionId: string;
|
|
549
841
|
readonly user: User | null;
|
|
842
|
+
readonly organizationId: string | null;
|
|
550
843
|
};
|
|
551
844
|
/**
|
|
552
845
|
* A `fetch` the client sends every request through. The global `fetch` fits; so does a
|
|
@@ -700,6 +993,106 @@ type EmailCodeSent2 = Schemas["EmailCodeSent"];
|
|
|
700
993
|
*/
|
|
701
994
|
type StepUpMethod = StepUpProof["method"];
|
|
702
995
|
/**
|
|
996
|
+
* An organization the signed-in user belongs to, with their role in it and its permission
|
|
997
|
+
* keys.
|
|
998
|
+
*
|
|
999
|
+
* @example
|
|
1000
|
+
* ```ts
|
|
1001
|
+
* const { data } = await tula.organizations.list()
|
|
1002
|
+
* const admin = data.find((org) => org.role === 'admin')
|
|
1003
|
+
* ```
|
|
1004
|
+
*/
|
|
1005
|
+
type UserOrganization2 = Schemas["UserOrganization"];
|
|
1006
|
+
/** A page of the user's organizations, with the session's active organization's id. */
|
|
1007
|
+
type UserOrganizationList2 = Schemas["UserOrganizationList"];
|
|
1008
|
+
/** An organization the user may join because of a verified address (`organizations.suggestions()`). */
|
|
1009
|
+
type OrganizationSuggestion2 = Schemas["OrganizationSuggestion"];
|
|
1010
|
+
/** What `organizations.suggestions()` answers: the organizations the user is offered. */
|
|
1011
|
+
type OrganizationSuggestionList2 = Schemas["OrganizationSuggestionList"];
|
|
1012
|
+
/**
|
|
1013
|
+
* An invitation to an organization as the inviting side sees it. The token the emailed link
|
|
1014
|
+
* carries is never part of it.
|
|
1015
|
+
*
|
|
1016
|
+
* @example
|
|
1017
|
+
* ```ts
|
|
1018
|
+
* const { data } = await tula.organizations.invitations.list(org.id)
|
|
1019
|
+
* const open = data.filter((invitation) => invitation.status === 'pending')
|
|
1020
|
+
* ```
|
|
1021
|
+
*/
|
|
1022
|
+
type OrganizationInvitation2 = Schemas["OrganizationInvitation"];
|
|
1023
|
+
/** A page of an organization's invitations. */
|
|
1024
|
+
type OrganizationInvitationList2 = Schemas["OrganizationInvitationList"];
|
|
1025
|
+
/**
|
|
1026
|
+
* An invitation addressed to the signed-in user, as `organizations.invitations.mine()` lists it:
|
|
1027
|
+
* its `id`, the organization's name, the role's key and the expiry; never a token.
|
|
1028
|
+
*
|
|
1029
|
+
* @example
|
|
1030
|
+
* ```ts
|
|
1031
|
+
* const { data } = await tula.organizations.invitations.mine()
|
|
1032
|
+
* await tula.organizations.invitations.acceptMine(data[0].id)
|
|
1033
|
+
* ```
|
|
1034
|
+
*/
|
|
1035
|
+
type MyOrganizationInvitation2 = Schemas["MyOrganizationInvitation"];
|
|
1036
|
+
/** A page of the invitations addressed to the signed-in user. */
|
|
1037
|
+
type MyOrganizationInvitationList2 = Schemas["MyOrganizationInvitationList"];
|
|
1038
|
+
/** The body of `organizations.invitations.invite()`: the address, a role's key and the page the link leads to. */
|
|
1039
|
+
type CreateOrganizationInvitationInput = Schemas["CreateOrganizationInvitationRequest"];
|
|
1040
|
+
/** What the holder of an invitation's token may see before signing in. */
|
|
1041
|
+
type InvitationPreview2 = Schemas["InvitationPreview"];
|
|
1042
|
+
/** What accepting an invitation answers: the organization joined, with the role and its permissions. */
|
|
1043
|
+
type AcceptedInvitation2 = Schemas["AcceptedInvitation"];
|
|
1044
|
+
/**
|
|
1045
|
+
* A member of an organization as another member sees them: the user's id, name and address
|
|
1046
|
+
* (each `null` when they have none) and the key of their role.
|
|
1047
|
+
*
|
|
1048
|
+
* @example
|
|
1049
|
+
* ```ts
|
|
1050
|
+
* const { data } = await tula.organizations.members.list(org.id)
|
|
1051
|
+
* const admins = data.filter((member) => member.role === 'admin')
|
|
1052
|
+
* ```
|
|
1053
|
+
*/
|
|
1054
|
+
type OrganizationMember2 = Schemas["OrganizationMember"];
|
|
1055
|
+
/** A page of an organization's members. */
|
|
1056
|
+
type OrganizationMemberList2 = Schemas["OrganizationMemberList"];
|
|
1057
|
+
/** A role the signed-in member may give: its key and its name. */
|
|
1058
|
+
type AssignableRole2 = Schemas["AssignableRole"];
|
|
1059
|
+
/** What `organizations.roles()` answers: the roles the member may offer. */
|
|
1060
|
+
type AssignableRoleList2 = Schemas["AssignableRoleList"];
|
|
1061
|
+
/** The body of `organizations.update()`: a new name, a new slug, or both. */
|
|
1062
|
+
type UpdateOrganizationInput = Schemas["UpdateOrganizationRequest"];
|
|
1063
|
+
/** A domain an organization claimed, pending a code or verified. */
|
|
1064
|
+
type OrganizationDomain2 = Schemas["OrganizationDomain"];
|
|
1065
|
+
/** An organization's domains. */
|
|
1066
|
+
type OrganizationDomainList2 = Schemas["OrganizationDomainList"];
|
|
1067
|
+
/** The body of `organizations.domains.start()`: the domain, an address on it and the mode. */
|
|
1068
|
+
type StartOrganizationDomainInput = Schemas["StartOrganizationDomainRequest"];
|
|
1069
|
+
/** An SSO connection of an organization, as its admins see it: never with the client secret. */
|
|
1070
|
+
type OrganizationSsoConnection = Schemas["SsoConnection"];
|
|
1071
|
+
/** An organization's SSO connections. */
|
|
1072
|
+
type OrganizationSsoConnectionList = Schemas["SsoConnectionList"];
|
|
1073
|
+
/** The body of `organizations.sso.create()`: the organization is the one of the call. */
|
|
1074
|
+
type CreateOrganizationSsoConnectionInput = Schemas["CreateMySsoConnectionRequest"];
|
|
1075
|
+
/** The fields `organizations.sso.update()` changes; an absent one is kept. */
|
|
1076
|
+
type UpdateOrganizationSsoConnectionInput = Schemas["UpdateSsoConnectionRequest"];
|
|
1077
|
+
/** An organization's IdP group to role mapping, in precedence order. */
|
|
1078
|
+
type OrganizationSsoGroupRoles = Schemas["SsoGroupRoles"];
|
|
1079
|
+
/** A started test sign-in: where to send the browser, and the id it returns with. */
|
|
1080
|
+
type OrganizationSsoTestStart = Schemas["SsoTestStart"];
|
|
1081
|
+
/** A test sign-in's result. */
|
|
1082
|
+
type OrganizationSsoTestResult = Schemas["SsoTestResult"];
|
|
1083
|
+
/** An SSO setup link of an organization, as listed (never its token). */
|
|
1084
|
+
type OrganizationSetupLink = Schemas["SetupLink"];
|
|
1085
|
+
/** The setup links of an organization. */
|
|
1086
|
+
type OrganizationSetupLinkList = Schemas["SetupLinkList"];
|
|
1087
|
+
/** A new setup link: the `token` and `url` are shown once. */
|
|
1088
|
+
type CreatedOrganizationSetupLink = Schemas["CreatedSetupLink"];
|
|
1089
|
+
/** The body of `organizations.sso.createSetupLink()`. */
|
|
1090
|
+
type CreateOrganizationSetupLinkInput = Schemas["CreateMySetupLinkRequest"];
|
|
1091
|
+
/** What `organizations.setActive()` answers: the session's active organization now. */
|
|
1092
|
+
type ActiveOrganization2 = Schemas["ActiveOrganization"];
|
|
1093
|
+
/** The body of `organizations.create()`: a name and a slug (lower-case letters, digits, hyphens). */
|
|
1094
|
+
type CreateOrganizationInput = Schemas["CreateOrganizationRequest"];
|
|
1095
|
+
/**
|
|
703
1096
|
* Codes for failures that happen in the client, before or instead of an API answer. They sit
|
|
704
1097
|
* next to the contract's codes so that callers have one thing to catch and one field to switch
|
|
705
1098
|
* on. `status` is `0` for all of them.
|
|
@@ -844,7 +1237,8 @@ interface TulaErrorInit {
|
|
|
844
1237
|
*
|
|
845
1238
|
* `code` is a contract code (`auth.invalid_credentials`, `password.too_short`, `rate_limited`,
|
|
846
1239
|
* …) or one of the client's own (`network.failed`, `network.timeout`, `response.invalid`,
|
|
847
|
-
* `storage.failed`, `flow.busy`). An error the client raised itself has `status: 0`. `message` is
|
|
1240
|
+
* `storage.failed`, `flow.busy`). An error the client raised itself has `status: 0`. `message` is
|
|
1241
|
+
* ready to show, taken from the client's locale table. An error
|
|
848
1242
|
* never contains a token, an attempt's secret or a password.
|
|
849
1243
|
*
|
|
850
1244
|
* @example
|
|
@@ -1026,7 +1420,7 @@ import { DeviceKey } from "@tula-tech/contract/device-binding";
|
|
|
1026
1420
|
/**
|
|
1027
1421
|
* Where a client's device key comes from, for a runtime that cannot hand one over when the
|
|
1028
1422
|
* client is created: a key in a phone's secure hardware is found or made by a native call,
|
|
1029
|
-
* which takes time and can fail
|
|
1423
|
+
* which takes time and can fail. Asked before every request a key proves.
|
|
1030
1424
|
*
|
|
1031
1425
|
* @param operation - The request about to be sent: the operation id of one of the starts,
|
|
1032
1426
|
* or `refreshSession`.
|
|
@@ -1127,7 +1521,7 @@ interface Environment {
|
|
|
1127
1521
|
linkStorage: LinkStorageLike | undefined;
|
|
1128
1522
|
/**
|
|
1129
1523
|
* Storage one tab keeps across a navigation and no other tab can read (`sessionStorage`).
|
|
1130
|
-
* Holds the binding of an OAuth round trip while the tab is at the provider
|
|
1524
|
+
* Holds the binding of an OAuth round trip while the tab is at the provider: not a
|
|
1131
1525
|
* token, and not an attempt's secret.
|
|
1132
1526
|
*/
|
|
1133
1527
|
tabStorage: LinkStorageLike | undefined;
|
|
@@ -1135,7 +1529,7 @@ interface Environment {
|
|
|
1135
1529
|
page: PageLike | undefined;
|
|
1136
1530
|
/**
|
|
1137
1531
|
* Where `navigator.credentials` and `PublicKeyCredential` are looked up when a passkey is
|
|
1138
|
-
* asked for
|
|
1532
|
+
* asked for. Read lazily: a runtime without WebAuthn simply has neither.
|
|
1139
1533
|
*/
|
|
1140
1534
|
passkeys: PasskeyGlobals | undefined;
|
|
1141
1535
|
/**
|
|
@@ -1145,7 +1539,7 @@ interface Environment {
|
|
|
1145
1539
|
passkeyProvider?: PasskeyProvider;
|
|
1146
1540
|
/**
|
|
1147
1541
|
* Where the client's device key comes from, for a runtime that finds or makes it by a call
|
|
1148
|
-
* that takes time (a key in a phone's secure hardware
|
|
1542
|
+
* that takes time (a key in a phone's secure hardware). Asked before every
|
|
1149
1543
|
* request a key proves, unless the client was given a `deviceKey` of its own. Never for a
|
|
1150
1544
|
* `web` client.
|
|
1151
1545
|
*/
|
|
@@ -1196,8 +1590,9 @@ declare function runtimeEnvironment(globals?: RuntimeGlobals): Environment;
|
|
|
1196
1590
|
* The `web` client kind never uses it: there the refresh token lives in an httpOnly cookie that
|
|
1197
1591
|
* JavaScript cannot read. For `ios`, `android` and `server` the token is a long-lived
|
|
1198
1592
|
* credential, so back this with the platform's secure store (Keychain, Keystore, an encrypted
|
|
1199
|
-
* file), never with `localStorage` or a plain file
|
|
1200
|
-
*
|
|
1593
|
+
* file), never with `localStorage` or a plain file: script can read those, so any script on
|
|
1594
|
+
* the page (an XSS, a compromised dependency) could take the refresh token. The default
|
|
1595
|
+
* {@link memoryStorage} is not readable that way.
|
|
1201
1596
|
*
|
|
1202
1597
|
* @example
|
|
1203
1598
|
* ```ts
|
|
@@ -1343,13 +1738,78 @@ interface EmailLinkOutcome {
|
|
|
1343
1738
|
/** What happened. */
|
|
1344
1739
|
readonly status: "none" | "signed_in" | "verified" | "different_browser" | "expired";
|
|
1345
1740
|
}
|
|
1741
|
+
/** A provider `signIn.withOAuth` can be asked for. */
|
|
1742
|
+
type OAuthProvider2 = Schemas["OAuthProvider"];
|
|
1743
|
+
/** A provider account connected to the signed-in user. */
|
|
1744
|
+
type Identity2 = Schemas["Identity"];
|
|
1745
|
+
/**
|
|
1746
|
+
* Whether a failure thrown by `signIn.handleOAuthCallback()` left the round trip in place, so
|
|
1747
|
+
* that calling it again retries the exchange: the request got no answer (`network.failed`,
|
|
1748
|
+
* `network.timeout`) or was rate limited.
|
|
1749
|
+
*
|
|
1750
|
+
* @param error - What `handleOAuthCallback()` threw.
|
|
1751
|
+
* @returns `true` when calling it again can still succeed.
|
|
1752
|
+
*
|
|
1753
|
+
* @example
|
|
1754
|
+
* ```ts
|
|
1755
|
+
* try {
|
|
1756
|
+
* await tula.signIn.handleOAuthCallback()
|
|
1757
|
+
* } catch (error) {
|
|
1758
|
+
* if (isRetryableOAuthError(error)) showTryAgain()
|
|
1759
|
+
* }
|
|
1760
|
+
* ```
|
|
1761
|
+
*/
|
|
1762
|
+
declare function isRetryableOAuthError(error: unknown): boolean;
|
|
1763
|
+
/**
|
|
1764
|
+
* What became of an OAuth round trip, as `signIn.handleOAuthCallback()` reports it.
|
|
1765
|
+
*
|
|
1766
|
+
* - `none`: the address holds no OAuth answer. Nothing was sent.
|
|
1767
|
+
* - `complete`: signed in. `flow.step.status` is `complete`.
|
|
1768
|
+
* - `needs_step`: the provider was accepted as a first factor and something still stands before
|
|
1769
|
+
* the session (`needs_second_factor`, `needs_factor_enrolment`). `flow` is positioned on that
|
|
1770
|
+
* step: `flow.submitSecondFactor(…)` and the enrolment actions work as for any sign-in.
|
|
1771
|
+
* - `linked`: a provider account was connected to the signed-in user (a link started with
|
|
1772
|
+
* `user.identities.link`).
|
|
1773
|
+
* - `different_browser`: this browser did not start the sign-in (or no longer has what it kept).
|
|
1774
|
+
* Nothing was completed. Start again here.
|
|
1775
|
+
* - `error`: it did not go through. `code` is a contract error code: `oauth.access_denied` (the
|
|
1776
|
+
* user cancelled), `oauth.account_exists` (sign in the usual way, then connect the provider
|
|
1777
|
+
* from the profile), `oauth.email_unverified`, `oauth.ticket_invalid`, …; `message` is its text.
|
|
1778
|
+
*
|
|
1779
|
+
* @example
|
|
1780
|
+
* ```ts
|
|
1781
|
+
* const outcome: OAuthCallbackOutcome = await tula.signIn.handleOAuthCallback()
|
|
1782
|
+
* if (outcome.status === 'needs_step') {
|
|
1783
|
+
* await outcome.flow.submitSecondFactor({ method: 'totp', code })
|
|
1784
|
+
* }
|
|
1785
|
+
* ```
|
|
1786
|
+
*/
|
|
1787
|
+
type OAuthCallbackOutcome = {
|
|
1788
|
+
readonly status: "none";
|
|
1789
|
+
} | {
|
|
1790
|
+
readonly status: "complete";
|
|
1791
|
+
readonly flow: SignInFlow;
|
|
1792
|
+
} | {
|
|
1793
|
+
readonly status: "needs_step";
|
|
1794
|
+
readonly flow: SignInFlow;
|
|
1795
|
+
} | {
|
|
1796
|
+
readonly status: "linked";
|
|
1797
|
+
readonly identity: Identity2;
|
|
1798
|
+
} | {
|
|
1799
|
+
readonly status: "different_browser";
|
|
1800
|
+
} | {
|
|
1801
|
+
readonly status: "error";
|
|
1802
|
+
readonly code: string;
|
|
1803
|
+
readonly message: string;
|
|
1804
|
+
};
|
|
1346
1805
|
/**
|
|
1347
1806
|
* What a flow looks like when it is logged or serialised: where it stands, and nothing that
|
|
1348
1807
|
* could continue it. The attempt's secret is never part of it.
|
|
1349
1808
|
*
|
|
1350
1809
|
* @example
|
|
1351
1810
|
* ```ts
|
|
1352
|
-
* JSON.stringify(flow) //
|
|
1811
|
+
* JSON.stringify(flow) //
|
|
1812
|
+
* {"id":"…","kind":"sign_in","step":{"status":"needs_password"},"expiresAt":"…"}
|
|
1353
1813
|
* ```
|
|
1354
1814
|
*/
|
|
1355
1815
|
interface FlowSnapshot<Kind extends FlowKind2 = FlowKind2> {
|
|
@@ -1367,7 +1827,8 @@ interface FlowSnapshot<Kind extends FlowKind2 = FlowKind2> {
|
|
|
1367
1827
|
*
|
|
1368
1828
|
* @example
|
|
1369
1829
|
* ```ts
|
|
1370
|
-
* const { step, backupCodesRemaining } = await flow.submitSecondFactor({ method: 'backup_code', code
|
|
1830
|
+
* const { step, backupCodesRemaining } = await flow.submitSecondFactor({ method: 'backup_code', code
|
|
1831
|
+
* })
|
|
1371
1832
|
* if (backupCodesRemaining !== undefined && backupCodesRemaining < 3) {
|
|
1372
1833
|
* suggestNewBackupCodes()
|
|
1373
1834
|
* }
|
|
@@ -1641,7 +2102,8 @@ interface SignInFlow extends Flow<"sign_in">, FactorEnrolmentActions, SecondFact
|
|
|
1641
2102
|
* With `email_link` the email also carries a link to `redirectUrl`, which must be one of the
|
|
1642
2103
|
* environment's allowed redirect URLs, exactly, **and on the same origin as the page that
|
|
1643
2104
|
* asks** (scheme, host and port): what ties the link to this browser is kept in this origin's
|
|
1644
|
-
* storage, and a page on another origin could not read it. The link works only in this browser:
|
|
2105
|
+
* storage, and a page on another origin could not read it. The link works only in this browser:
|
|
2106
|
+
* the
|
|
1645
2107
|
* flow keeps what ties the two together (in `localStorage`; it is not a token and authorizes
|
|
1646
2108
|
* nothing by itself). Follow it with {@link SignInFlow.waitForEmailLink}.
|
|
1647
2109
|
*
|
|
@@ -1701,6 +2163,28 @@ interface SignInFlow extends Flow<"sign_in">, FactorEnrolmentActions, SecondFact
|
|
|
1701
2163
|
waitForEmailLink(options?: {
|
|
1702
2164
|
signal?: AbortSignal;
|
|
1703
2165
|
}): Promise<FlowStep2>;
|
|
2166
|
+
/**
|
|
2167
|
+
* Continue with single sign-on (step `needs_first_factor` offering `sso`: the address's
|
|
2168
|
+
* domain is bound to an active connection). Keeps the round trip's binding for this tab and
|
|
2169
|
+
* navigates to the identity provider, unless `navigate` is `false`. The provider returns to
|
|
2170
|
+
* `redirectUrl`; call `signIn.handleOAuthCallback()` on that page, as after a provider.
|
|
2171
|
+
*
|
|
2172
|
+
* @param input - The page to come back to (one of the allowed redirect URLs, same origin as
|
|
2173
|
+
* this page), and `navigate: false` to navigate yourself.
|
|
2174
|
+
* @returns The identity provider's URL.
|
|
2175
|
+
* @throws TulaError `request.redirect_not_allowed`, `sso.*` codes, `link.cross_origin` and
|
|
2176
|
+
* `storage.failed` (raised by the client, no request sent).
|
|
2177
|
+
* @example
|
|
2178
|
+
* ```ts
|
|
2179
|
+
* await flow.startSso({ redirectUrl: `${location.origin}/oauth/callback` })
|
|
2180
|
+
* ```
|
|
2181
|
+
*/
|
|
2182
|
+
startSso(input: {
|
|
2183
|
+
redirectUrl: string;
|
|
2184
|
+
navigate?: boolean;
|
|
2185
|
+
}): Promise<{
|
|
2186
|
+
url: string;
|
|
2187
|
+
}>;
|
|
1704
2188
|
}
|
|
1705
2189
|
/**
|
|
1706
2190
|
* A password reset in progress. The emailed code and the new password travel together, so a
|
|
@@ -1773,88 +2257,24 @@ interface IdTokenName {
|
|
|
1773
2257
|
/** The family name, at most 100 characters. */
|
|
1774
2258
|
familyName?: string;
|
|
1775
2259
|
}
|
|
1776
|
-
/** A provider `signIn.withOAuth` can be asked for. */
|
|
1777
|
-
type OAuthProvider2 = Schemas["OAuthProvider"];
|
|
1778
|
-
/** A provider account connected to the signed-in user. */
|
|
1779
|
-
type Identity2 = Schemas["Identity"];
|
|
1780
2260
|
/**
|
|
1781
|
-
*
|
|
1782
|
-
*
|
|
1783
|
-
* `network.timeout`) or was rate limited.
|
|
1784
|
-
*
|
|
1785
|
-
* @param error - What `handleOAuthCallback()` threw.
|
|
1786
|
-
* @returns `true` when calling it again can still succeed.
|
|
2261
|
+
* How long one request may take before it fails with `network.timeout`, unless the client is
|
|
2262
|
+
* created with its own `timeoutMs`.
|
|
1787
2263
|
*
|
|
1788
2264
|
* @example
|
|
1789
2265
|
* ```ts
|
|
1790
|
-
*
|
|
1791
|
-
* await tula.signIn.handleOAuthCallback()
|
|
1792
|
-
* } catch (error) {
|
|
1793
|
-
* if (isRetryableOAuthError(error)) showTryAgain()
|
|
1794
|
-
* }
|
|
2266
|
+
* createTulaClient({ publishableKey, baseUrl, timeoutMs: DEFAULT_TIMEOUT_MS * 2 })
|
|
1795
2267
|
* ```
|
|
1796
2268
|
*/
|
|
1797
|
-
declare
|
|
2269
|
+
declare const DEFAULT_TIMEOUT_MS = 15e3;
|
|
1798
2270
|
/**
|
|
1799
|
-
*
|
|
1800
|
-
*
|
|
1801
|
-
* - `none`: the address holds no OAuth answer. Nothing was sent.
|
|
1802
|
-
* - `complete`: signed in. `flow.step.status` is `complete`.
|
|
1803
|
-
* - `needs_step`: the provider was accepted as a first factor and something still stands before
|
|
1804
|
-
* the session (`needs_second_factor`, `needs_factor_enrolment`). `flow` is positioned on that
|
|
1805
|
-
* step: `flow.submitSecondFactor(…)` and the enrolment actions work as for any sign-in.
|
|
1806
|
-
* - `linked`: a provider account was connected to the signed-in user (a link started with
|
|
1807
|
-
* `user.identities.link`).
|
|
1808
|
-
* - `different_browser`: this browser did not start the sign-in (or no longer has what it kept).
|
|
1809
|
-
* Nothing was completed. Start again here.
|
|
1810
|
-
* - `error`: it did not go through. `code` is a contract error code: `oauth.access_denied` (the
|
|
1811
|
-
* user cancelled), `oauth.account_exists` (sign in the usual way, then connect the provider
|
|
1812
|
-
* from the profile), `oauth.email_unverified`, `oauth.ticket_invalid`, …; `message` is its text.
|
|
2271
|
+
* Options of {@link createTulaClient}.
|
|
1813
2272
|
*
|
|
1814
2273
|
* @example
|
|
1815
2274
|
* ```ts
|
|
1816
|
-
* const
|
|
1817
|
-
*
|
|
1818
|
-
*
|
|
1819
|
-
* }
|
|
1820
|
-
* ```
|
|
1821
|
-
*/
|
|
1822
|
-
type OAuthCallbackOutcome = {
|
|
1823
|
-
readonly status: "none";
|
|
1824
|
-
} | {
|
|
1825
|
-
readonly status: "complete";
|
|
1826
|
-
readonly flow: SignInFlow;
|
|
1827
|
-
} | {
|
|
1828
|
-
readonly status: "needs_step";
|
|
1829
|
-
readonly flow: SignInFlow;
|
|
1830
|
-
} | {
|
|
1831
|
-
readonly status: "linked";
|
|
1832
|
-
readonly identity: Identity2;
|
|
1833
|
-
} | {
|
|
1834
|
-
readonly status: "different_browser";
|
|
1835
|
-
} | {
|
|
1836
|
-
readonly status: "error";
|
|
1837
|
-
readonly code: string;
|
|
1838
|
-
readonly message: string;
|
|
1839
|
-
};
|
|
1840
|
-
/**
|
|
1841
|
-
* How long one request may take before it fails with `network.timeout`, unless the client is
|
|
1842
|
-
* created with its own `timeoutMs`.
|
|
1843
|
-
*
|
|
1844
|
-
* @example
|
|
1845
|
-
* ```ts
|
|
1846
|
-
* createTulaClient({ publishableKey, baseUrl, timeoutMs: DEFAULT_TIMEOUT_MS * 2 })
|
|
1847
|
-
* ```
|
|
1848
|
-
*/
|
|
1849
|
-
declare const DEFAULT_TIMEOUT_MS = 15e3;
|
|
1850
|
-
/**
|
|
1851
|
-
* Options of {@link createTulaClient}.
|
|
1852
|
-
*
|
|
1853
|
-
* @example
|
|
1854
|
-
* ```ts
|
|
1855
|
-
* const options: TulaClientOptions = {
|
|
1856
|
-
* publishableKey: 'tula_pk_dev_…',
|
|
1857
|
-
* baseUrl: 'https://auth.example.com',
|
|
2275
|
+
* const options: TulaClientOptions = {
|
|
2276
|
+
* publishableKey: 'tula_pk_dev_…',
|
|
2277
|
+
* baseUrl: 'https://auth.example.com',
|
|
1858
2278
|
* }
|
|
1859
2279
|
* ```
|
|
1860
2280
|
*/
|
|
@@ -1864,6 +2284,12 @@ interface TulaClientOptions {
|
|
|
1864
2284
|
/** Where the Tula API is served, e.g. `https://auth.example.com`. */
|
|
1865
2285
|
baseUrl: string;
|
|
1866
2286
|
/**
|
|
2287
|
+
* Allow a plain `http:` `baseUrl` to a host that is not this machine. Off by default: the
|
|
2288
|
+
* publishable key and the bearer tokens would cross the network readable. Only for a private
|
|
2289
|
+
* network you trust.
|
|
2290
|
+
*/
|
|
2291
|
+
allowInsecureHttp?: boolean;
|
|
2292
|
+
/**
|
|
1867
2293
|
* The kind of client, which decides where the refresh token lives. `web` (the default in a
|
|
1868
2294
|
* browser): an httpOnly cookie set by the API, which this SDK never sees. `ios`, `android`,
|
|
1869
2295
|
* `server` (the default elsewhere): the `storage` adapter.
|
|
@@ -1875,7 +2301,7 @@ interface TulaClientOptions {
|
|
|
1875
2301
|
*/
|
|
1876
2302
|
storage?: TokenStorage;
|
|
1877
2303
|
/**
|
|
1878
|
-
* The session profile to ask for, by name
|
|
2304
|
+
* The session profile to ask for, by name. The session gets it only where the
|
|
1879
2305
|
* environment marks that profile `clientSelectable`; any other name is ignored by the API
|
|
1880
2306
|
* and the session gets the profile of its client kind (`web`, or `mobile` for the others).
|
|
1881
2307
|
* Leave it out to take that default. A name is lowercase letters, digits and single hyphens,
|
|
@@ -1888,7 +2314,7 @@ interface TulaClientOptions {
|
|
|
1888
2314
|
*/
|
|
1889
2315
|
sessionProfile?: string;
|
|
1890
2316
|
/**
|
|
1891
|
-
* A key to bind this client's sessions to
|
|
2317
|
+
* A key to bind this client's sessions to. With one, every sign-in, sign-up and
|
|
1892
2318
|
* password reset this client starts asks for a **device-bound** session, and every refresh
|
|
1893
2319
|
* proves the key: a refresh token copied off the device is then of no use without it. The
|
|
1894
2320
|
* proofs (`DPoP` headers) and the server's nonce are handled by the client.
|
|
@@ -1937,7 +2363,8 @@ interface TulaClient {
|
|
|
1937
2363
|
readonly state: AuthState;
|
|
1938
2364
|
/**
|
|
1939
2365
|
* What a server rendered for this client, when a framework integration knows it
|
|
1940
|
-
* (`@tula-tech/nextjs` sets it from the request's session). `@tula-tech/react` uses it as the
|
|
2366
|
+
* (`@tula-tech/nextjs` sets it from the request's session). `@tula-tech/react` uses it as the
|
|
2367
|
+
* state
|
|
1941
2368
|
* during server rendering and hydration instead of `loading`. `createTulaClient` never sets
|
|
1942
2369
|
* it.
|
|
1943
2370
|
*/
|
|
@@ -2124,7 +2551,8 @@ interface TulaClient {
|
|
|
2124
2551
|
provider: IdTokenProvider2;
|
|
2125
2552
|
}): Promise<IdTokenSignIn>;
|
|
2126
2553
|
/**
|
|
2127
|
-
* "Continue with Google, GitHub, Apple, Microsoft, Discord, LinkedIn, X or Facebook": a sign-in
|
|
2554
|
+
* "Continue with Google, GitHub, Apple, Microsoft, Discord, LinkedIn, X or Facebook": a sign-in
|
|
2555
|
+
* that creates the account when the
|
|
2128
2556
|
* provider's verified address has none.
|
|
2129
2557
|
*
|
|
2130
2558
|
* Asks the API for the provider's URL, keeps the round trip's binding for this tab
|
|
@@ -2212,7 +2640,7 @@ interface TulaClient {
|
|
|
2212
2640
|
* An access token to send to your own backend, refreshed first when it is missing or about
|
|
2213
2641
|
* to expire. Any number of concurrent calls share one refresh.
|
|
2214
2642
|
*
|
|
2215
|
-
* **`null` while signed in on a `stateful` session profile
|
|
2643
|
+
* **`null` while signed in on a `stateful` session profile**. Such a session is
|
|
2216
2644
|
* an httpOnly cookie the browser holds and this client never sees: there is no token, so
|
|
2217
2645
|
* there is nothing to return and nothing is asked of the API. Use `state.status` to know
|
|
2218
2646
|
* whether the user is signed in; a backend on the API's own host receives the cookie and
|
|
@@ -2337,6 +2765,591 @@ interface TulaClient {
|
|
|
2337
2765
|
method: "email_code" | "sms_code";
|
|
2338
2766
|
}): Promise<StepUpPrepared>;
|
|
2339
2767
|
};
|
|
2768
|
+
/**
|
|
2769
|
+
* The signed-in user's organizations and the one the session acts in. While the
|
|
2770
|
+
* environment's `organizations.enabled` setting is off, each call answers
|
|
2771
|
+
* `organization.disabled`.
|
|
2772
|
+
*/
|
|
2773
|
+
readonly organizations: {
|
|
2774
|
+
/**
|
|
2775
|
+
* The organizations the user belongs to, with their role and its permission keys in each,
|
|
2776
|
+
* and the session's active organization, one page at a time (the first, 20 of them, without
|
|
2777
|
+
* a query). `meta.totalPages` says whether there is a next page.
|
|
2778
|
+
*
|
|
2779
|
+
* @param query - The page to read (1-based, default 1) and its `size` (1 to 100, default 20).
|
|
2780
|
+
* @returns The page; `activeOrganizationId` is `null` for the personal account.
|
|
2781
|
+
* @throws TulaError `auth.unauthenticated` when signed out, `organization.disabled`.
|
|
2782
|
+
* @example
|
|
2783
|
+
* ```ts
|
|
2784
|
+
* const { data, meta, activeOrganizationId } = await tula.organizations.list({ page: 2 })
|
|
2785
|
+
* ```
|
|
2786
|
+
*/
|
|
2787
|
+
list(query?: {
|
|
2788
|
+
page?: number;
|
|
2789
|
+
size?: number;
|
|
2790
|
+
}): Promise<UserOrganizationList2>;
|
|
2791
|
+
/**
|
|
2792
|
+
* Create an organization the user owns (it holds the environment's `creatorRole`). The
|
|
2793
|
+
* session does not switch to it: call `setActive`.
|
|
2794
|
+
*
|
|
2795
|
+
* @param input - The name and the slug.
|
|
2796
|
+
* @returns The organization.
|
|
2797
|
+
* @throws TulaError `organization.creation_disabled`, `organization.limit_reached`,
|
|
2798
|
+
* `organization.slug_taken`.
|
|
2799
|
+
* @example
|
|
2800
|
+
* ```ts
|
|
2801
|
+
* const org = await tula.organizations.create({ name: 'Acme', slug: 'acme' })
|
|
2802
|
+
* await tula.organizations.setActive(org.id)
|
|
2803
|
+
* ```
|
|
2804
|
+
*/
|
|
2805
|
+
create(input: CreateOrganizationInput): Promise<UserOrganization2>;
|
|
2806
|
+
/**
|
|
2807
|
+
* Make an organization the one the session acts in (or `null`, the personal account). The
|
|
2808
|
+
* access token is replaced with one that carries `org_id`, `org_role` and `org_perms`;
|
|
2809
|
+
* `state.organizationId` follows.
|
|
2810
|
+
*
|
|
2811
|
+
* @param organizationId - The organization, or `null`.
|
|
2812
|
+
* @returns The API's answer.
|
|
2813
|
+
* @throws TulaError `organization.not_a_member`, `organization.personal_account_disabled`.
|
|
2814
|
+
* @example
|
|
2815
|
+
* ```ts
|
|
2816
|
+
* await tula.organizations.setActive(org.id)
|
|
2817
|
+
* ```
|
|
2818
|
+
*/
|
|
2819
|
+
setActive(organizationId: string | null): Promise<ActiveOrganization2>;
|
|
2820
|
+
/**
|
|
2821
|
+
* The organizations the user may join because their **verified** email address is on a
|
|
2822
|
+
* domain the organization verified: its id, name and slug,
|
|
2823
|
+
* nothing of its members. Empty for a user with no verified address, for one already in
|
|
2824
|
+
* the organization and for a domain that is not exactly the address's.
|
|
2825
|
+
*
|
|
2826
|
+
* @returns The suggestions.
|
|
2827
|
+
* @throws TulaError `auth.unauthenticated` when signed out, `organization.disabled`.
|
|
2828
|
+
* @example
|
|
2829
|
+
* ```ts
|
|
2830
|
+
* const { data } = await tula.organizations.suggestions()
|
|
2831
|
+
* ```
|
|
2832
|
+
*/
|
|
2833
|
+
suggestions(): Promise<OrganizationSuggestionList2>;
|
|
2834
|
+
/**
|
|
2835
|
+
* Join a suggested organization with the environment's default role. The server decides
|
|
2836
|
+
* again, so a suggestion that is gone (the domain was removed, the address changed) is
|
|
2837
|
+
* refused. The session does not switch to it: call `setActive`.
|
|
2838
|
+
*
|
|
2839
|
+
* @param organizationId - The organization, from {@link suggestions}.
|
|
2840
|
+
* @returns The organization, with the user's role and its permission keys.
|
|
2841
|
+
* @throws TulaError `organization.suggestion_unavailable`, `organization.member_exists`,
|
|
2842
|
+
* `organization.disabled`.
|
|
2843
|
+
* @example
|
|
2844
|
+
* ```ts
|
|
2845
|
+
* const [first] = (await tula.organizations.suggestions()).data
|
|
2846
|
+
* if (first) {
|
|
2847
|
+
* await tula.organizations.join(first.id)
|
|
2848
|
+
* }
|
|
2849
|
+
* ```
|
|
2850
|
+
*/
|
|
2851
|
+
join(organizationId: string): Promise<UserOrganization2>;
|
|
2852
|
+
/**
|
|
2853
|
+
* Rename an organization, or change its slug. Needs `org:sys:organization:manage`, which
|
|
2854
|
+
* the API reads from the user's membership on every call.
|
|
2855
|
+
*
|
|
2856
|
+
* @param organizationId - The organization.
|
|
2857
|
+
* @param input - A new `name`, a new `slug`, or both.
|
|
2858
|
+
* @returns The organization with the user's role, as it is now.
|
|
2859
|
+
* @throws TulaError `organization.not_a_member`, `organization.permission_required`,
|
|
2860
|
+
* `organization.slug_taken`, `organization.disabled`.
|
|
2861
|
+
* @example
|
|
2862
|
+
* ```ts
|
|
2863
|
+
* await tula.organizations.update(org.id, { name: 'Acme Inc' })
|
|
2864
|
+
* ```
|
|
2865
|
+
*/
|
|
2866
|
+
update(organizationId: string, input: UpdateOrganizationInput): Promise<UserOrganization2>;
|
|
2867
|
+
/**
|
|
2868
|
+
* Delete an organization for good, with its memberships, invitations and domains. Needs
|
|
2869
|
+
* `org:sys:organization:delete`. Members' sessions leave it at their next refresh; if it
|
|
2870
|
+
* was this session's active organization, call `setActive` for another one.
|
|
2871
|
+
*
|
|
2872
|
+
* @param organizationId - The organization.
|
|
2873
|
+
* @throws TulaError `organization.not_a_member`, `organization.permission_required`,
|
|
2874
|
+
* `organization.disabled`.
|
|
2875
|
+
* @example
|
|
2876
|
+
* ```ts
|
|
2877
|
+
* await tula.organizations.remove(org.id)
|
|
2878
|
+
* await tula.organizations.setActive(null)
|
|
2879
|
+
* ```
|
|
2880
|
+
*/
|
|
2881
|
+
remove(organizationId: string): Promise<void>;
|
|
2882
|
+
/**
|
|
2883
|
+
* Leave an organization: remove the signed-in user's own membership, which needs no
|
|
2884
|
+
* permission. The last member who can manage members cannot leave.
|
|
2885
|
+
*
|
|
2886
|
+
* @param organizationId - The organization.
|
|
2887
|
+
* @throws TulaError `organization.not_a_member`, `organization.last_manager`,
|
|
2888
|
+
* `organization.disabled`.
|
|
2889
|
+
* @example
|
|
2890
|
+
* ```ts
|
|
2891
|
+
* await tula.organizations.leave(org.id)
|
|
2892
|
+
* ```
|
|
2893
|
+
*/
|
|
2894
|
+
leave(organizationId: string): Promise<void>;
|
|
2895
|
+
/**
|
|
2896
|
+
* The roles the user may give to an invitation or a member: those whose permissions they
|
|
2897
|
+
* hold themselves. Needs `org:sys:invitations:manage` or `org:sys:memberships:manage`.
|
|
2898
|
+
*
|
|
2899
|
+
* @param organizationId - The organization.
|
|
2900
|
+
* @returns The roles' keys and names.
|
|
2901
|
+
* @throws TulaError `organization.not_a_member`, `organization.permission_required`,
|
|
2902
|
+
* `organization.disabled`.
|
|
2903
|
+
* @example
|
|
2904
|
+
* ```ts
|
|
2905
|
+
* const { data } = await tula.organizations.roles(org.id)
|
|
2906
|
+
* ```
|
|
2907
|
+
*/
|
|
2908
|
+
roles(organizationId: string): Promise<AssignableRoleList2>;
|
|
2909
|
+
/**
|
|
2910
|
+
* An organization's members. Reading needs `org:sys:memberships:read` or `:manage`;
|
|
2911
|
+
* changing needs `org:sys:memberships:manage`, which the API reads from the user's
|
|
2912
|
+
* membership on every call.
|
|
2913
|
+
*/
|
|
2914
|
+
readonly members: {
|
|
2915
|
+
/**
|
|
2916
|
+
* The organization's members, oldest first, with each one's name, address and role key.
|
|
2917
|
+
* Only the first page: the client sends no paging query yet.
|
|
2918
|
+
*
|
|
2919
|
+
* @param organizationId - The organization.
|
|
2920
|
+
* @returns The page.
|
|
2921
|
+
* @throws TulaError `organization.not_a_member`, `organization.permission_required`,
|
|
2922
|
+
* `organization.disabled`.
|
|
2923
|
+
* @example
|
|
2924
|
+
* ```ts
|
|
2925
|
+
* const { data } = await tula.organizations.members.list(org.id)
|
|
2926
|
+
* ```
|
|
2927
|
+
*/
|
|
2928
|
+
list(organizationId: string): Promise<OrganizationMemberList2>;
|
|
2929
|
+
/**
|
|
2930
|
+
* Give a member another role, one whose permissions the user holds themselves. The
|
|
2931
|
+
* member's sessions carry it from their next refresh.
|
|
2932
|
+
*
|
|
2933
|
+
* @param organizationId - The organization.
|
|
2934
|
+
* @param userId - The member.
|
|
2935
|
+
* @param role - The key of the new role.
|
|
2936
|
+
* @returns The member, as they are now.
|
|
2937
|
+
* @throws TulaError `organization.permission_required`, `organization.role_unknown`,
|
|
2938
|
+
* `organization.role_not_assignable`, `organization.last_manager`.
|
|
2939
|
+
* @example
|
|
2940
|
+
* ```ts
|
|
2941
|
+
* await tula.organizations.members.changeRole(org.id, member.userId, 'admin')
|
|
2942
|
+
* ```
|
|
2943
|
+
*/
|
|
2944
|
+
changeRole(organizationId: string, userId: string, role: string): Promise<OrganizationMember2>;
|
|
2945
|
+
/**
|
|
2946
|
+
* Remove a member. The user keeps their account; to remove yourself use `leave`.
|
|
2947
|
+
*
|
|
2948
|
+
* @param organizationId - The organization.
|
|
2949
|
+
* @param userId - The member.
|
|
2950
|
+
* @throws TulaError `organization.permission_required`, `organization.last_manager`.
|
|
2951
|
+
* @example
|
|
2952
|
+
* ```ts
|
|
2953
|
+
* await tula.organizations.members.remove(org.id, member.userId)
|
|
2954
|
+
* ```
|
|
2955
|
+
*/
|
|
2956
|
+
remove(organizationId: string, userId: string): Promise<void>;
|
|
2957
|
+
};
|
|
2958
|
+
/**
|
|
2959
|
+
* An organization's domains: the organization claims one by
|
|
2960
|
+
* a code emailed to an address on it, and a verified one suggests or joins the people who
|
|
2961
|
+
* sign up with a verified address on it. Needs `org:sys:domains:manage`, which the API
|
|
2962
|
+
* reads from the user's membership on every call.
|
|
2963
|
+
*/
|
|
2964
|
+
readonly domains: {
|
|
2965
|
+
/**
|
|
2966
|
+
* The organization's domains, oldest first: claims waiting for a code and verified ones.
|
|
2967
|
+
*
|
|
2968
|
+
* @param organizationId - The organization.
|
|
2969
|
+
* @returns The domains.
|
|
2970
|
+
* @throws TulaError `organization.not_a_member`, `auth.forbidden`, `organization.disabled`.
|
|
2971
|
+
* @example
|
|
2972
|
+
* ```ts
|
|
2973
|
+
* const { data } = await tula.organizations.domains.list(org.id)
|
|
2974
|
+
* ```
|
|
2975
|
+
*/
|
|
2976
|
+
list(organizationId: string): Promise<OrganizationDomainList2>;
|
|
2977
|
+
/**
|
|
2978
|
+
* Claim a domain: email a code to an address on it. Sent again for a pending claim it
|
|
2979
|
+
* emails a new code.
|
|
2980
|
+
*
|
|
2981
|
+
* @param organizationId - The organization.
|
|
2982
|
+
* @param input - The domain, an address on it and what a verified domain does.
|
|
2983
|
+
* @returns The pending claim.
|
|
2984
|
+
* @throws TulaError `organization.domain_public`, `organization.domain_taken`,
|
|
2985
|
+
* `organization.domain_address_mismatch`, `organization.domain_limit`, `rate_limited`.
|
|
2986
|
+
* @example
|
|
2987
|
+
* ```ts
|
|
2988
|
+
* await tula.organizations.domains.start(org.id, {
|
|
2989
|
+
* domain: 'acme.com',
|
|
2990
|
+
* email: 'ada@acme.com',
|
|
2991
|
+
* mode: 'suggest',
|
|
2992
|
+
* })
|
|
2993
|
+
* ```
|
|
2994
|
+
*/
|
|
2995
|
+
start(organizationId: string, input: StartOrganizationDomainInput): Promise<OrganizationDomain2>;
|
|
2996
|
+
/**
|
|
2997
|
+
* Enter the emailed code. Five wrong guesses use the code up.
|
|
2998
|
+
*
|
|
2999
|
+
* @param organizationId - The organization.
|
|
3000
|
+
* @param domainId - The claim.
|
|
3001
|
+
* @param code - The six digits.
|
|
3002
|
+
* @returns The verified domain.
|
|
3003
|
+
* @throws TulaError `verification.invalid_code` and its siblings, `organization.domain_taken`.
|
|
3004
|
+
* @example
|
|
3005
|
+
* ```ts
|
|
3006
|
+
* await tula.organizations.domains.verify(org.id, domain.id, '123456')
|
|
3007
|
+
* ```
|
|
3008
|
+
*/
|
|
3009
|
+
verify(organizationId: string, domainId: string, code: string): Promise<OrganizationDomain2>;
|
|
3010
|
+
/**
|
|
3011
|
+
* Change what a domain does.
|
|
3012
|
+
*
|
|
3013
|
+
* @param organizationId - The organization.
|
|
3014
|
+
* @param domainId - The domain.
|
|
3015
|
+
* @param mode - `suggest` or `auto_join`.
|
|
3016
|
+
* @returns The domain.
|
|
3017
|
+
* @example
|
|
3018
|
+
* ```ts
|
|
3019
|
+
* await tula.organizations.domains.update(org.id, domain.id, 'auto_join')
|
|
3020
|
+
* ```
|
|
3021
|
+
*/
|
|
3022
|
+
update(organizationId: string, domainId: string, mode: OrganizationDomain2["mode"]): Promise<OrganizationDomain2>;
|
|
3023
|
+
/**
|
|
3024
|
+
* Remove a domain. Later sign-ups are neither offered nor joined to the organization;
|
|
3025
|
+
* the members it brought stay.
|
|
3026
|
+
*
|
|
3027
|
+
* @param organizationId - The organization.
|
|
3028
|
+
* @param domainId - The domain.
|
|
3029
|
+
* @example
|
|
3030
|
+
* ```ts
|
|
3031
|
+
* await tula.organizations.domains.remove(org.id, domain.id)
|
|
3032
|
+
* ```
|
|
3033
|
+
*/
|
|
3034
|
+
remove(organizationId: string, domainId: string): Promise<void>;
|
|
3035
|
+
};
|
|
3036
|
+
/**
|
|
3037
|
+
* An organization's single sign-on, for a member whose role holds
|
|
3038
|
+
* `org:sys:sso:manage`, which the API reads from the membership on every call. The client
|
|
3039
|
+
* secret is write-only: no answer returns it. Switching enforcement off, trusting the
|
|
3040
|
+
* identity provider for MFA and naming a break-glass role need a recent sign-in
|
|
3041
|
+
* (`auth.step_up_required`: step up, then repeat the call).
|
|
3042
|
+
*/
|
|
3043
|
+
readonly sso: {
|
|
3044
|
+
/**
|
|
3045
|
+
* The organization's connections, with the service provider values to give the IdP.
|
|
3046
|
+
*
|
|
3047
|
+
* @param organizationId - The organization.
|
|
3048
|
+
* @returns The connections.
|
|
3049
|
+
* @throws TulaError `organization.not_a_member`, `auth.forbidden`, `sso.disabled`.
|
|
3050
|
+
* @example
|
|
3051
|
+
* ```ts
|
|
3052
|
+
* const { connections } = await tula.organizations.sso.list(org.id)
|
|
3053
|
+
* ```
|
|
3054
|
+
*/
|
|
3055
|
+
list(organizationId: string): Promise<OrganizationSsoConnectionList>;
|
|
3056
|
+
/**
|
|
3057
|
+
* One connection.
|
|
3058
|
+
*
|
|
3059
|
+
* @param organizationId - The organization.
|
|
3060
|
+
* @param id - The connection.
|
|
3061
|
+
* @returns The connection.
|
|
3062
|
+
* @example
|
|
3063
|
+
* ```ts
|
|
3064
|
+
* const connection = await tula.organizations.sso.get(org.id, id)
|
|
3065
|
+
* ```
|
|
3066
|
+
*/
|
|
3067
|
+
get(organizationId: string, id: string): Promise<OrganizationSsoConnection>;
|
|
3068
|
+
/**
|
|
3069
|
+
* Create a draft connection; a draft signs nobody in.
|
|
3070
|
+
*
|
|
3071
|
+
* @param organizationId - The organization.
|
|
3072
|
+
* @param input - The connection.
|
|
3073
|
+
* @returns The connection.
|
|
3074
|
+
* @example
|
|
3075
|
+
* ```ts
|
|
3076
|
+
* await tula.organizations.sso.create(org.id, { name: 'Okta', issuer, clientId, clientSecret
|
|
3077
|
+
* })
|
|
3078
|
+
* ```
|
|
3079
|
+
*/
|
|
3080
|
+
create(organizationId: string, input: CreateOrganizationSsoConnectionInput): Promise<OrganizationSsoConnection>;
|
|
3081
|
+
/**
|
|
3082
|
+
* Change a connection; fields left out are kept.
|
|
3083
|
+
*
|
|
3084
|
+
* @param organizationId - The organization.
|
|
3085
|
+
* @param id - The connection.
|
|
3086
|
+
* @param input - The fields to change.
|
|
3087
|
+
* @returns The connection as it is now.
|
|
3088
|
+
* @throws TulaError `auth.step_up_required` for a weakening on a stale session.
|
|
3089
|
+
* @example
|
|
3090
|
+
* ```ts
|
|
3091
|
+
* await tula.organizations.sso.update(org.id, id, { status: 'active' })
|
|
3092
|
+
* ```
|
|
3093
|
+
*/
|
|
3094
|
+
update(organizationId: string, id: string, input: UpdateOrganizationSsoConnectionInput): Promise<OrganizationSsoConnection>;
|
|
3095
|
+
/**
|
|
3096
|
+
* Read a SAML connection's metadata address again (a rotated certificate).
|
|
3097
|
+
*
|
|
3098
|
+
* @param organizationId - The organization.
|
|
3099
|
+
* @param id - The connection.
|
|
3100
|
+
* @returns The connection.
|
|
3101
|
+
* @example
|
|
3102
|
+
* ```ts
|
|
3103
|
+
* await tula.organizations.sso.refreshMetadata(org.id, id)
|
|
3104
|
+
* ```
|
|
3105
|
+
*/
|
|
3106
|
+
refreshMetadata(organizationId: string, id: string): Promise<OrganizationSsoConnection>;
|
|
3107
|
+
/**
|
|
3108
|
+
* Delete a connection that is not active (`sso.connection_in_use` otherwise); its users keep
|
|
3109
|
+
* their accounts.
|
|
3110
|
+
*
|
|
3111
|
+
* @param organizationId - The organization.
|
|
3112
|
+
* @param id - The connection.
|
|
3113
|
+
* @example
|
|
3114
|
+
* ```ts
|
|
3115
|
+
* await tula.organizations.sso.remove(org.id, id)
|
|
3116
|
+
* ```
|
|
3117
|
+
*/
|
|
3118
|
+
remove(organizationId: string, id: string): Promise<void>;
|
|
3119
|
+
/**
|
|
3120
|
+
* The IdP group to role mapping, in precedence order.
|
|
3121
|
+
*
|
|
3122
|
+
* @param organizationId - The organization.
|
|
3123
|
+
* @param id - A connection of the organization.
|
|
3124
|
+
* @returns The mapping.
|
|
3125
|
+
* @example
|
|
3126
|
+
* ```ts
|
|
3127
|
+
* const { mappings } = await tula.organizations.sso.groupRoles(org.id, id)
|
|
3128
|
+
* ```
|
|
3129
|
+
*/
|
|
3130
|
+
groupRoles(organizationId: string, id: string): Promise<OrganizationSsoGroupRoles>;
|
|
3131
|
+
/**
|
|
3132
|
+
* Replace the whole mapping.
|
|
3133
|
+
*
|
|
3134
|
+
* @param organizationId - The organization.
|
|
3135
|
+
* @param id - A connection of the organization.
|
|
3136
|
+
* @param mapping - The new mapping.
|
|
3137
|
+
* @returns The mapping as saved.
|
|
3138
|
+
* @example
|
|
3139
|
+
* ```ts
|
|
3140
|
+
* await tula.organizations.sso.setGroupRoles(org.id, id, { mappings: [{ group: 'eng', role:
|
|
3141
|
+
* 'admin' }] })
|
|
3142
|
+
* ```
|
|
3143
|
+
*/
|
|
3144
|
+
setGroupRoles(organizationId: string, id: string, mapping: OrganizationSsoGroupRoles): Promise<OrganizationSsoGroupRoles>;
|
|
3145
|
+
/**
|
|
3146
|
+
* Start a test sign-in of a connection. A passing test of its current settings is what
|
|
3147
|
+
* turns it on (`sso.test_required`). Send the browser to `authorizationUrl`; it returns to
|
|
3148
|
+
* `redirectUrl` with `#tula_test=<testId>`.
|
|
3149
|
+
*
|
|
3150
|
+
* @param organizationId - The organization.
|
|
3151
|
+
* @param id - A connection of the organization.
|
|
3152
|
+
* @param redirectUrl - The page to return to; the environment must allow it.
|
|
3153
|
+
* @returns The test's id and where to send the browser.
|
|
3154
|
+
* @throws TulaError `request.redirect_not_allowed`, and those of {@link get}.
|
|
3155
|
+
* @example
|
|
3156
|
+
* ```ts
|
|
3157
|
+
* const { authorizationUrl } = await tula.organizations.sso.startTest(org.id, id,
|
|
3158
|
+
* location.href)
|
|
3159
|
+
* ```
|
|
3160
|
+
*/
|
|
3161
|
+
startTest(organizationId: string, id: string, redirectUrl: string): Promise<OrganizationSsoTestStart>;
|
|
3162
|
+
/**
|
|
3163
|
+
* Read a test's result: what arrived and how it mapped, or why it failed.
|
|
3164
|
+
*
|
|
3165
|
+
* @param organizationId - The organization.
|
|
3166
|
+
* @param id - The connection.
|
|
3167
|
+
* @param testId - The id the browser came back with.
|
|
3168
|
+
* @returns The result; `pending` until the browser has come back.
|
|
3169
|
+
* @throws TulaError `sso.test_not_found`, and those of {@link get}.
|
|
3170
|
+
* @example
|
|
3171
|
+
* ```ts
|
|
3172
|
+
* const result = await tula.organizations.sso.testResult(org.id, id, testId)
|
|
3173
|
+
* ```
|
|
3174
|
+
*/
|
|
3175
|
+
testResult(organizationId: string, id: string, testId: string): Promise<OrganizationSsoTestResult>;
|
|
3176
|
+
/**
|
|
3177
|
+
* The organization's SSO setup links, newest first; never their tokens. A link lets an
|
|
3178
|
+
* IT administrator without an account set up an OpenID Connect connection (not SAML).
|
|
3179
|
+
*
|
|
3180
|
+
* @param organizationId - The organization.
|
|
3181
|
+
* @returns The links.
|
|
3182
|
+
* @throws TulaError `organization.not_a_member`, `organization.permission_required`,
|
|
3183
|
+
* `sso.disabled`.
|
|
3184
|
+
* @example
|
|
3185
|
+
* ```ts
|
|
3186
|
+
* const { links } = await tula.organizations.sso.setupLinks(org.id)
|
|
3187
|
+
* ```
|
|
3188
|
+
*/
|
|
3189
|
+
setupLinks(organizationId: string): Promise<OrganizationSetupLinkList>;
|
|
3190
|
+
/**
|
|
3191
|
+
* Make a setup link. The answer holds the link's `url` once; it is not stored.
|
|
3192
|
+
*
|
|
3193
|
+
* @param organizationId - The organization.
|
|
3194
|
+
* @param input - The link's name and life in days.
|
|
3195
|
+
* @returns The link, with its token and address.
|
|
3196
|
+
* @throws TulaError those of {@link setupLinks}.
|
|
3197
|
+
* @example
|
|
3198
|
+
* ```ts
|
|
3199
|
+
* const { url } = await tula.organizations.sso.createSetupLink(org.id, { name: 'Acme IT' })
|
|
3200
|
+
* ```
|
|
3201
|
+
*/
|
|
3202
|
+
createSetupLink(organizationId: string, input?: CreateOrganizationSetupLinkInput): Promise<CreatedOrganizationSetupLink>;
|
|
3203
|
+
/**
|
|
3204
|
+
* End a setup link now.
|
|
3205
|
+
*
|
|
3206
|
+
* @param organizationId - The organization.
|
|
3207
|
+
* @param linkId - The link.
|
|
3208
|
+
* @throws TulaError those of {@link setupLinks}.
|
|
3209
|
+
* @example
|
|
3210
|
+
* ```ts
|
|
3211
|
+
* await tula.organizations.sso.revokeSetupLink(org.id, link.id)
|
|
3212
|
+
* ```
|
|
3213
|
+
*/
|
|
3214
|
+
revokeSetupLink(organizationId: string, linkId: string): Promise<void>;
|
|
3215
|
+
};
|
|
3216
|
+
/**
|
|
3217
|
+
* Invitations by email. The inviting calls need the permission
|
|
3218
|
+
* `org:sys:invitations:manage`, which the API reads from the user's membership on every
|
|
3219
|
+
* call. Answering needs the invited account: signed in, with the invited address, verified.
|
|
3220
|
+
*/
|
|
3221
|
+
readonly invitations: {
|
|
3222
|
+
/**
|
|
3223
|
+
* An organization's pending invitations, newest first. Only the first page: the client
|
|
3224
|
+
* sends no paging or state query yet.
|
|
3225
|
+
*
|
|
3226
|
+
* @param organizationId - The organization.
|
|
3227
|
+
* @returns The page.
|
|
3228
|
+
* @throws TulaError `organization.not_a_member`, `organization.permission_required`,
|
|
3229
|
+
* `organization.disabled`.
|
|
3230
|
+
* @example
|
|
3231
|
+
* ```ts
|
|
3232
|
+
* const { data } = await tula.organizations.invitations.list(org.id)
|
|
3233
|
+
* ```
|
|
3234
|
+
*/
|
|
3235
|
+
list(organizationId: string): Promise<OrganizationInvitationList2>;
|
|
3236
|
+
/**
|
|
3237
|
+
* Email an invitation. The link leads to `input.redirectUrl` (one of the environment's
|
|
3238
|
+
* allowed redirect URLs) with the token in its fragment; read it there with
|
|
3239
|
+
* `readInvitationLink`. The role must be within the permissions of the inviter's own.
|
|
3240
|
+
*
|
|
3241
|
+
* @param organizationId - The organization.
|
|
3242
|
+
* @param input - The address, the role's key and the redirect URL.
|
|
3243
|
+
* @returns The invitation; the token is only in the email.
|
|
3244
|
+
* @throws TulaError `organization.not_a_member`, `organization.permission_required`,
|
|
3245
|
+
* `organization.role_not_assignable`, `organization.role_unknown`,
|
|
3246
|
+
* `organization.member_exists`, `organization.invitation_exists`,
|
|
3247
|
+
* `request.redirect_not_allowed`, `rate_limited`.
|
|
3248
|
+
* @example
|
|
3249
|
+
* ```ts
|
|
3250
|
+
* await tula.organizations.invitations.invite(org.id, {
|
|
3251
|
+
* email: 'ada@example.com',
|
|
3252
|
+
* role: 'member',
|
|
3253
|
+
* redirectUrl: 'https://app.example.com/join',
|
|
3254
|
+
* })
|
|
3255
|
+
* ```
|
|
3256
|
+
*/
|
|
3257
|
+
invite(organizationId: string, input: CreateOrganizationInvitationInput): Promise<OrganizationInvitation2>;
|
|
3258
|
+
/**
|
|
3259
|
+
* Withdraw a pending invitation: its link stops working.
|
|
3260
|
+
*
|
|
3261
|
+
* @param organizationId - The organization.
|
|
3262
|
+
* @param invitationId - The invitation.
|
|
3263
|
+
* @throws TulaError `organization.invitation_used`, `organization.invitation_revoked`,
|
|
3264
|
+
* `organization.invitation_expired` (410) for one that is no longer pending, and the
|
|
3265
|
+
* errors of `list`.
|
|
3266
|
+
* @example
|
|
3267
|
+
* ```ts
|
|
3268
|
+
* await tula.organizations.invitations.revoke(org.id, invitation.id)
|
|
3269
|
+
* ```
|
|
3270
|
+
*/
|
|
3271
|
+
revoke(organizationId: string, invitationId: string): Promise<void>;
|
|
3272
|
+
/**
|
|
3273
|
+
* What an invitation's token shows before anyone has signed in: the organization's
|
|
3274
|
+
* name, the role's key and the address invited, to prefill a sign-up. Needs no session.
|
|
3275
|
+
*
|
|
3276
|
+
* @param token - The token from the link's fragment.
|
|
3277
|
+
* @returns The preview.
|
|
3278
|
+
* @throws TulaError `organization.invitation_not_found`, `organization.invitation_expired`,
|
|
3279
|
+
* `organization.invitation_revoked`, `organization.invitation_used`.
|
|
3280
|
+
* @example
|
|
3281
|
+
* ```ts
|
|
3282
|
+
* const { organizationName, email } = await tula.organizations.invitations.preview(token)
|
|
3283
|
+
* ```
|
|
3284
|
+
*/
|
|
3285
|
+
preview(token: string): Promise<InvitationPreview2>;
|
|
3286
|
+
/**
|
|
3287
|
+
* Join the organization the token invites to, with the invitation's role. Only the
|
|
3288
|
+
* account the invitation was sent to may, and only with a verified address.
|
|
3289
|
+
*
|
|
3290
|
+
* @param token - The token from the link's fragment.
|
|
3291
|
+
* @returns The organization joined, with the role and its permission keys.
|
|
3292
|
+
* @throws TulaError `organization.invitation_wrong_account`,
|
|
3293
|
+
* `organization.invitation_email_unverified`, `organization.invitation_role_gone`,
|
|
3294
|
+
* `organization.member_exists`, and the errors of `preview`.
|
|
3295
|
+
* @example
|
|
3296
|
+
* ```ts
|
|
3297
|
+
* const org = await tula.organizations.invitations.accept(token)
|
|
3298
|
+
* await tula.organizations.setActive(org.id)
|
|
3299
|
+
* ```
|
|
3300
|
+
*/
|
|
3301
|
+
accept(token: string): Promise<AcceptedInvitation2>;
|
|
3302
|
+
/**
|
|
3303
|
+
* Turn an invitation down: it is used up and nobody joins.
|
|
3304
|
+
*
|
|
3305
|
+
* @param token - The token from the link's fragment.
|
|
3306
|
+
* @throws TulaError As `accept`, but a deleted role does not matter.
|
|
3307
|
+
* @example
|
|
3308
|
+
* ```ts
|
|
3309
|
+
* await tula.organizations.invitations.decline(token)
|
|
3310
|
+
* ```
|
|
3311
|
+
*/
|
|
3312
|
+
decline(token: string): Promise<void>;
|
|
3313
|
+
/**
|
|
3314
|
+
* The pending invitations addressed to the signed-in user's own verified address, newest
|
|
3315
|
+
* first: an `id`, the organization's name, the role's key and the expiry, never a token.
|
|
3316
|
+
* Only the first page: the client sends no paging query yet. An unverified address
|
|
3317
|
+
* has none.
|
|
3318
|
+
*
|
|
3319
|
+
* @returns The page.
|
|
3320
|
+
* @throws TulaError `organization.disabled`, `auth.unauthenticated`.
|
|
3321
|
+
* @example
|
|
3322
|
+
* ```ts
|
|
3323
|
+
* const { data } = await tula.organizations.invitations.mine()
|
|
3324
|
+
* ```
|
|
3325
|
+
*/
|
|
3326
|
+
mine(): Promise<MyOrganizationInvitationList2>;
|
|
3327
|
+
/**
|
|
3328
|
+
* Join the organization of an invitation listed by `mine()`, by its id. The same checks as
|
|
3329
|
+
* `accept`: an id that is not the user's own answers `organization.invitation_not_found`.
|
|
3330
|
+
*
|
|
3331
|
+
* @param invitationId - The `id` from `mine()`.
|
|
3332
|
+
* @returns The organization joined, with the role and its permission keys.
|
|
3333
|
+
* @throws TulaError As `accept`.
|
|
3334
|
+
* @example
|
|
3335
|
+
* ```ts
|
|
3336
|
+
* const org = await tula.organizations.invitations.acceptMine(invitation.id)
|
|
3337
|
+
* ```
|
|
3338
|
+
*/
|
|
3339
|
+
acceptMine(invitationId: string): Promise<AcceptedInvitation2>;
|
|
3340
|
+
/**
|
|
3341
|
+
* Turn down an invitation listed by `mine()`, by its id.
|
|
3342
|
+
*
|
|
3343
|
+
* @param invitationId - The `id` from `mine()`.
|
|
3344
|
+
* @throws TulaError As `decline`.
|
|
3345
|
+
* @example
|
|
3346
|
+
* ```ts
|
|
3347
|
+
* await tula.organizations.invitations.declineMine(invitation.id)
|
|
3348
|
+
* ```
|
|
3349
|
+
*/
|
|
3350
|
+
declineMine(invitationId: string): Promise<void>;
|
|
3351
|
+
};
|
|
3352
|
+
};
|
|
2340
3353
|
/** The signed-in user. */
|
|
2341
3354
|
readonly user: {
|
|
2342
3355
|
/**
|
|
@@ -2360,7 +3373,7 @@ interface TulaClient {
|
|
|
2360
3373
|
newPassword: string;
|
|
2361
3374
|
}): Promise<void>;
|
|
2362
3375
|
/**
|
|
2363
|
-
* The signed-in user's passkeys
|
|
3376
|
+
* The signed-in user's passkeys. Adding, renaming and removing one may answer
|
|
2364
3377
|
* `auth.step_up_required`; see `session.stepUp`.
|
|
2365
3378
|
*/
|
|
2366
3379
|
readonly passkeys: {
|
|
@@ -2756,4 +3769,31 @@ declare function createClient(options: TulaClientOptions, environment: Environme
|
|
|
2756
3769
|
* ```
|
|
2757
3770
|
*/
|
|
2758
3771
|
declare function createTulaClient(options: TulaClientOptions): TulaClient;
|
|
2759
|
-
|
|
3772
|
+
/** An invitation's token as read from the URL of an emailed link. */
|
|
3773
|
+
interface InvitationLink {
|
|
3774
|
+
/** The token to pass to `organizations.invitations.preview`, `accept` or `decline`. */
|
|
3775
|
+
token: string;
|
|
3776
|
+
/** The URL without the token, to put back in the address bar so the token is not kept. */
|
|
3777
|
+
cleanUrl: string;
|
|
3778
|
+
}
|
|
3779
|
+
/**
|
|
3780
|
+
* Read the invitation token from the URL an emailed invitation link leads to.
|
|
3781
|
+
*
|
|
3782
|
+
* The token travels in the URL fragment (`#tula_invitation=…`), which a browser never sends to
|
|
3783
|
+
* a server, so it is in no log and in no `Referer`. Read it, then replace the address bar with
|
|
3784
|
+
* `cleanUrl` (`history.replaceState`) so that the token is not left in the history.
|
|
3785
|
+
*
|
|
3786
|
+
* @param url - The page's URL, e.g. `window.location.href`.
|
|
3787
|
+
* @returns The token and the URL without it, or `null` when the URL carries no token.
|
|
3788
|
+
*
|
|
3789
|
+
* @example
|
|
3790
|
+
* ```ts
|
|
3791
|
+
* const link = readInvitationLink(window.location.href)
|
|
3792
|
+
* if (link) {
|
|
3793
|
+
* history.replaceState(null, '', link.cleanUrl)
|
|
3794
|
+
* const { organizationName } = await tula.organizations.invitations.preview(link.token)
|
|
3795
|
+
* }
|
|
3796
|
+
* ```
|
|
3797
|
+
*/
|
|
3798
|
+
declare function readInvitationLink(url: string): InvitationLink | null;
|
|
3799
|
+
export { ACCESS_TOKEN_EXPIRY_SKEW_MS, AcceptedInvitation2 as AcceptedInvitation, ActiveOrganization2 as ActiveOrganization, AssignableRole2 as AssignableRole, AssignableRoleList2 as AssignableRoleList, AuthState, BackupCodes2 as BackupCodes, ChannelLike, ClientConfig2 as ClientConfig, ClientErrorCode, ClientKind, CreateOrganizationInput, CreateOrganizationInvitationInput, CreateOrganizationSetupLinkInput, CreateOrganizationSsoConnectionInput, CreatedOrganizationSetupLink, DEFAULT_TIMEOUT_MS, DeviceKey3 as DeviceKey, DeviceKeySource, DevicePublicJwk, EMAIL_LINK_POLL_INTERVAL_MS, EMAIL_LINK_SESSION_WAIT_MS, EN_MESSAGES, EmailCodeSent2 as EmailCodeSent, EmailLinkOutcome, Environment, ErrorParams2 as ErrorParams, FactorEnrolmentMethod2 as FactorEnrolmentMethod, FactorEnrolmentResult, Factors2 as Factors, FetchLike, FirstFactorStrategy2 as FirstFactorStrategy, FlowKind2 as FlowKind, FlowSnapshot, FlowStep2 as FlowStep, IdTokenName, IdTokenProvider2 as IdTokenProvider, IdTokenSignIn, Identity2 as Identity, InvitationLink, InvitationPreview2 as InvitationPreview, LinkStorageLike, LockManagerLike, MAX_REFRESH_BACKOFF_MS, Messages, MfaPolicy2 as MfaPolicy, MyOrganizationInvitation2 as MyOrganizationInvitation, MyOrganizationInvitationList2 as MyOrganizationInvitationList, OAuthCallbackOutcome, OAuthProvider2 as OAuthProvider, OrganizationDomain2 as OrganizationDomain, OrganizationDomainList2 as OrganizationDomainList, OrganizationInvitation2 as OrganizationInvitation, OrganizationInvitationList2 as OrganizationInvitationList, OrganizationMember2 as OrganizationMember, OrganizationMemberList2 as OrganizationMemberList, OrganizationSetupLink, OrganizationSetupLinkList, OrganizationSsoConnection, OrganizationSsoConnectionList, OrganizationSsoGroupRoles, OrganizationSsoTestResult, OrganizationSsoTestStart, OrganizationSuggestion2 as OrganizationSuggestion, OrganizationSuggestionList2 as OrganizationSuggestionList, PageLike, Passkey2 as Passkey, PasskeyCreationOptions2 as PasskeyCreationOptions, PasskeyGlobals, PasskeyProvider, PasskeyRequest, PasskeyRequestOptions2 as PasskeyRequestOptions, PasswordCheck, PasswordEvaluation, PasswordPolicy2 as PasswordPolicy, PasswordResetFlow, PasswordRule, PasswordUserInfo, PhoneCodeSent2 as PhoneCodeSent, REFRESH_RETRY_WINDOW_MS, REFRESH_TIMEOUT_MS, SecondFactorMethod2 as SecondFactorMethod, SecondFactorProof, SecondFactorResult, Session2 as Session, SignInFlow, SignUpFlow, SmsFactorCode2 as SmsFactorCode, StartOrganizationDomainInput, StepUpMethod, StepUpPrepared, StepUpProof, TokenStorage, TotpEnrolment2 as TotpEnrolment, TulaClient, TulaClientOptions, TulaError, TulaErrorCode, TulaErrorInit, TulaFieldError, UpdateOrganizationInput, UpdateOrganizationSsoConnectionInput, User, UserOrganization2 as UserOrganization, UserOrganizationList2 as UserOrganizationList, createTulaClient, createClient as createTulaClientWithEnvironment, evaluatePassword, formatMessage, generateSoftwareDeviceKey, isRetryableOAuthError, isStepUpRequired, isTulaError, memoryStorage, readInvitationLink, runtimeEnvironment, stepUpMethods };
|