@tula-tech/contract 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,4 +35,109 @@ const step = FlowStepSchema.parse(await response.json())
35
35
 
36
36
  The reference of every export is [docs/reference/contract.md](../../docs/reference/contract.md).
37
37
  Under a strict Content-Security-Policy (no `'unsafe-eval'`), see
38
- [docs/releasing.md](../../docs/releasing.md#tula-techcontract-under-a-strict-content-security-policy).
38
+ [docs/internal/releasing.md](../../docs/internal/releasing.md#tula-techcontract-under-a-strict-content-security-policy).
39
+
40
+ ## What it holds
41
+
42
+ | Area | What is in it |
43
+ | --- | --- |
44
+ | Flow protocol | `FlowStepSchema` and the schemas of the steps a server answers a sign-up, a sign-in or a reset with (`needs_password`, `needs_first_factor`, `needs_email_verification`, `needs_new_password`, `needs_second_factor`, `needs_factor_enrolment`, `complete`). The API never says which screen to draw; a client reads the step. |
45
+ | Errors | `ERROR_CODES`, `ERROR_DEFINITIONS` and `errorDefinition(code)`: every stable, dot-namespaced code (`password.too_short`) with its status. The envelope an error is answered with is a schema too. |
46
+ | Passwords | `evaluatePassword(policy, password, userInfo)` and the policy presets: the same rules the server applies, so a form can show them before a request is made. |
47
+ | Sessions and tokens | The session profile, the token claims, `environmentIssuer(apiUrl, environmentId)` and `jwksUrl(issuer)`, which tell a verifier where an environment's keys are published. |
48
+ | Settings | The schema of an environment's settings, OAuth providers, hooks, native apps, JWT templates, email and SMS templates and organization roles. `@tula-tech/config` validates a config file with it. |
49
+ | Events | `ACTIVITY_TYPES` and the webhook signature constants (the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers, `WEBHOOK_TOLERANCE_SECONDS`), for a receiver that checks a delivery. |
50
+ | Headers | `PUBLISHABLE_KEY_HEADER` (`x-tula-publishable-key`), `CLIENT_HEADER` (`x-tula-client`) and the attempt header a flow call carries. |
51
+ | Redirect URLs | `isRedirectUrl`, `redirectUrlKind` and the rules for a custom-scheme redirect, shared by the server and the SDKs. |
52
+ | Theme | The default theme tokens the React SDK's stylesheet and the native SDKs are generated from (`@tula-tech/contract/theme`). |
53
+
54
+ ## Examples
55
+
56
+ Check a password against a policy before a form is submitted:
57
+
58
+ ```ts
59
+ import { PASSWORD_POLICY_PRESETS } from '@tula-tech/contract'
60
+ import { evaluatePassword } from '@tula-tech/contract/password-rules'
61
+
62
+ const { ok, checks } = evaluatePassword(PASSWORD_POLICY_PRESETS.recommended, 'correct horse')
63
+ if (!ok) {
64
+ for (const check of checks.filter((c) => !c.passed)) {
65
+ console.log(check.rule)
66
+ }
67
+ }
68
+ ```
69
+
70
+ Find where an environment publishes its signing keys, to verify an access token offline:
71
+
72
+ ```ts
73
+ import { environmentIssuer, jwksUrl } from '@tula-tech/contract/issuer'
74
+
75
+ const issuer = environmentIssuer('https://auth.example.com', environmentId)
76
+ const keys = jwksUrl(issuer) // <issuer>/.well-known/jwks.json
77
+ ```
78
+
79
+ Look up what an error code means without importing Zod:
80
+
81
+ ```ts
82
+ import { ERROR_CODES, errorDefinition } from '@tula-tech/contract/error-codes'
83
+
84
+ if ((ERROR_CODES as readonly string[]).includes(body.code)) {
85
+ const { status } = errorDefinition(body.code)
86
+ }
87
+ ```
88
+
89
+ ## Using the OpenAPI document
90
+
91
+ `@tula-tech/contract/openapi.json` is the document the API publishes at `/v1/openapi.json`,
92
+ committed with every release. It is what `@tula-tech/core` and `@tula-tech/admin` generate
93
+ their types from, so a generator of your own (another language, a test double) can start from
94
+ the same file:
95
+
96
+ ```ts
97
+ import openapi from '@tula-tech/contract/openapi.json' with { type: 'json' }
98
+
99
+ console.log(Object.keys(openapi.paths).length)
100
+ ```
101
+
102
+ ## Compatibility
103
+
104
+ - **ESM only**, with type declarations. The package has no side effects, so a bundler can drop
105
+ what you do not import.
106
+ - It runs in browsers, Node, Bun and edge runtimes: it uses no Node-only API.
107
+ - The root entry point depends on **Zod 4**. The subpath entry points listed above import no
108
+ Zod, so a browser bundle that needs only a constant or a pure function does not carry it.
109
+ - Zod's JIT code generation uses `new Function`. Where a strict Content-Security-Policy
110
+ forbids `'unsafe-eval'`, follow
111
+ [the note in docs/internal/releasing.md](../../docs/internal/releasing.md#tula-techcontract-under-a-strict-content-security-policy).
112
+
113
+ ## Stability and versions
114
+
115
+ - Every `@tula-tech/*` package of one release shares a version. Install this package at the
116
+ same version as the SDK that uses it (`@tula-tech/core`, `@tula-tech/react`,
117
+ `@tula-tech/nextjs`), or let that SDK bring it.
118
+ - A change to a route, a response or an error code is a change to this package, and the
119
+ OpenAPI document in it is regenerated with the API. While the version is `0.x`, read the
120
+ [changelog](https://github.com/Tula-Solutions/tula-auth-and-user-management/releases)
121
+ before you upgrade.
122
+ - Match on an error's `code`, not on its `detail` sentence, which is for people.
123
+
124
+ ## Security notes
125
+
126
+ - The schemas describe what a server and a client may send; they do not authenticate anything.
127
+ Validating a payload with them is not a substitute for verifying a token or a webhook
128
+ signature.
129
+ - Nothing in this package holds a secret. Secret keys (`tula_sk_…`) belong to the server
130
+ side only and are the concern of `@tula-tech/admin`.
131
+
132
+ ## Related packages
133
+
134
+ | Package | What |
135
+ | --- | --- |
136
+ | [`@tula-tech/core`](../core/README.md) | The headless client: flows, the session, single-flight refresh. |
137
+ | [`@tula-tech/react`](../react/README.md) | Provider, hooks and prebuilt components. |
138
+ | [`@tula-tech/nextjs`](../nextjs/README.md) | The Next.js App Router SDK. |
139
+ | [`@tula-tech/admin`](../admin/README.md) | The typed client for `/v1/admin/*`. Server-side only. |
140
+ | [`@tula-tech/config`](../config/README.md) | `defineConfig()` for `tula.config.ts`. |
141
+
142
+ The flow protocol is explained in [ADR 0019](../../docs/adr/0019-flow-engine-v2.md); the decisions
143
+ behind the rest are indexed in the [ADR README](../../docs/adr/README.md). Licensed under Apache-2.0.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The one top-level claim every custom claim is nested under (ADR 0036).
2
+ * The one top-level claim every custom claim is nested under.
3
3
  *
4
4
  * An operator's claims never sit beside Tula's own, so a claim Tula adds later cannot collide
5
5
  * with a customer's, and a template cannot set a claim Tula's servers or SDKs act on. `ext`
@@ -12,6 +12,17 @@
12
12
  * ```
13
13
  */
14
14
  declare const CUSTOM_CLAIMS_CLAIM = "ext";
15
+ /** The access token's claim naming the active organization. */
16
+ declare const ORGANIZATION_ID_CLAIM = "org_id";
17
+ /** The access token's claim naming the SSO connection a session was signed in through. */
18
+ declare const SSO_CONNECTION_CLAIM = "sso_conn";
19
+ /** The access token's claim holding the key of the member's role in the active organization. */
20
+ declare const ORGANIZATION_ROLE_CLAIM = "org_role";
21
+ /**
22
+ * The access token's claim holding the permission keys of that role. A list of strings,
23
+ * present only beside the other two.
24
+ */
25
+ declare const ORGANIZATION_PERMISSIONS_CLAIM = "org_perms";
15
26
  /**
16
27
  * Claim names a custom claim's key may never be: every claim Tula's tokens carry, the
17
28
  * registered claims a verifier acts on, `cnf` (reserved for device binding) and the namespace
@@ -25,7 +36,7 @@ declare const CUSTOM_CLAIMS_CLAIM = "ext";
25
36
  * RESERVED_CLAIM_NAMES.includes('sub') // true
26
37
  * ```
27
38
  */
28
- declare const RESERVED_CLAIM_NAMES: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti", "sid", "pid", "eid", "v", "auth_time", "amr", "sp", "cnf", "ext"];
39
+ declare const RESERVED_CLAIM_NAMES: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti", "sid", "pid", "eid", "v", "auth_time", "amr", "sp", "cnf", "org_id", "org_role", "org_perms", "sso_conn", "ext"];
29
40
  /**
30
41
  * The most bytes the namespace claim's value may take as JSON (UTF-8), whatever puts claims
31
42
  * in it.
@@ -36,6 +47,110 @@ declare const RESERVED_CLAIM_NAMES: readonly ["iss", "sub", "aud", "exp", "nbf",
36
47
  * room for a long issuer URL.
37
48
  */
38
49
  declare const MAX_CUSTOM_CLAIMS_BYTES = 1024;
50
+ /**
51
+ * The most bytes the three organization claims may take together, as JSON (UTF-8): their own
52
+ * cap, beside {@link MAX_CUSTOM_CLAIMS_BYTES} and never taken from it.
53
+ *
54
+ * It is the true upper bound of what the grammars allow: an organization id (a UUID, 36
55
+ * characters), a role key of 32 characters and 32 permissions of the longest key
56
+ * (`org:sys:` + 32 + `:` + 32 = 73 characters) take 2,541 bytes; the cap leaves a little
57
+ * room. A role is bounded by the contract and the database, so a token never reaches it
58
+ * unless a row was written by hand: the server then issues the token **without** the
59
+ * organization claims (no claim is "no permission"), never with a cut list.
60
+ */
61
+ declare const MAX_ORGANIZATION_CLAIMS_BYTES = 2560;
62
+ /** Most permissions an organization role (and so the `org_perms` claim) holds. */
63
+ declare const MAX_ORGANIZATION_PERMISSIONS_CLAIM = 32;
64
+ /** The organization claims of a verified session: who it acts as, in which organization. */
65
+ interface OrganizationClaims {
66
+ /** The active organization's id. */
67
+ readonly orgId: string;
68
+ /** The key of the member's role in it. */
69
+ readonly orgRole: string;
70
+ /** The permission keys of that role. */
71
+ readonly orgPermissions: readonly string[];
72
+ }
73
+ /**
74
+ * Whether permission keys and an organization id and role can ride in a token: the UTF-8 length
75
+ * of the JSON of the three claims, which {@link MAX_ORGANIZATION_CLAIMS_BYTES} caps.
76
+ *
77
+ * @param claims - The three claims.
78
+ * @returns The byte count.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * organizationClaimsBytes({ orgId: 'o1', orgRole: 'member', orgPermissions: [] }) // 52
83
+ * ```
84
+ */
85
+ declare function organizationClaimsBytes(claims: OrganizationClaims): number;
86
+ /**
87
+ * Read the organization claims out of a session's claims, for an SDK or an application.
88
+ *
89
+ * Call it only with claims that were **verified**: this checks a shape, not where the claims
90
+ * came from. The three are returned together or not at all. A token that carries one without
91
+ * the others, a value of another type, an id or a role key outside their grammar, more than
92
+ * {@link MAX_ORGANIZATION_PERMISSIONS_CLAIM} permissions, a permission outside the permission
93
+ * grammar (`PERMISSION_KEY_PATTERN`) or claims over {@link MAX_ORGANIZATION_CLAIMS_BYTES} has
94
+ * **no** active organization, whole: never repaired and never partly believed. Treat `null`
95
+ * as "no organization, no permission".
96
+ *
97
+ * @param claims - A session's verified claims.
98
+ * @returns A frozen copy, or `null` when no organization is active (or the claims are not
99
+ * what a Tula server issues).
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * readOrganizationClaims({ org_id: 'o1', org_role: 'admin', org_perms: ['org:sys:memberships:read']
104
+ * })
105
+ * // { orgId: 'o1', orgRole: 'admin', orgPermissions: ['org:sys:memberships:read'] }
106
+ * readOrganizationClaims({ org_id: 'o1' }) // null
107
+ * ```
108
+ */
109
+ declare function readOrganizationClaims(claims: unknown): OrganizationClaims | null;
110
+ /**
111
+ * What {@link hasOrganizationAccess} asks: one permission key, or one role key. Exactly one
112
+ * of the two.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * const byPermission: OrganizationCheck = { permission: 'org:billing:read' }
117
+ * const byRole: OrganizationCheck = { role: 'admin' }
118
+ * ```
119
+ */
120
+ type OrganizationCheck = {
121
+ readonly permission: string;
122
+ readonly role?: never;
123
+ } | {
124
+ readonly role: string;
125
+ readonly permission?: never;
126
+ };
127
+ /**
128
+ * Whether the active organization grants a permission or a role: the one rule behind
129
+ * `has()` in `@tula-tech/nextjs` and `@tula-tech/react`.
130
+ *
131
+ * It is exact. A permission is held when the claims list that very key; there is no wildcard
132
+ * (`org:billing:*` matches nothing) and no implication between keys (`manage` does not
133
+ * include `read`). A role is held when it is the member's role key. It is **false** with no
134
+ * active organization, for a check that names neither or both, and for anything that is not a
135
+ * non-empty string: a check that cannot be understood never grants.
136
+ *
137
+ * This reads claims, so it is as old as the access token (the server decides afresh at every
138
+ * refresh, within the token's life). Use it to decide what to show and what to let through
139
+ * quickly; a request that changes data is authorized by the server that changes it.
140
+ *
141
+ * @param claims - What {@link readOrganizationClaims} returned, or `null`.
142
+ * @param check - The permission or the role asked for.
143
+ * @returns Whether the organization grants it.
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * const claims = readOrganizationClaims(payload)
148
+ * hasOrganizationAccess(claims, { permission: 'org:billing:read' })
149
+ * hasOrganizationAccess(claims, { role: 'admin' })
150
+ * hasOrganizationAccess(null, { role: 'admin' }) // false: no organization is active
151
+ * ```
152
+ */
153
+ declare function hasOrganizationAccess(claims: OrganizationClaims | null | undefined, check: OrganizationCheck): boolean;
39
154
  /** Most JWT templates an environment may define. */
40
155
  declare const MAX_JWT_TEMPLATES = 10;
41
156
  /** Most claims one JWT template may define. */
@@ -158,4 +273,4 @@ declare function checkCustomClaims(value: unknown): CustomClaimsCheck;
158
273
  * ```
159
274
  */
160
275
  declare function readCustomClaims(claims: unknown): CustomClaims | null;
161
- export { CUSTOM_CLAIMS_CLAIM, CustomClaimValue, CustomClaims, CustomClaimsCheck, MAX_CUSTOM_CLAIMS_BYTES, MAX_CUSTOM_CLAIM_CONSTANT_LENGTH, MAX_CUSTOM_CLAIM_KEY_LENGTH, MAX_JWT_TEMPLATES, MAX_JWT_TEMPLATE_CLAIMS, RESERVED_CLAIM_NAMES, checkCustomClaims, customClaimsBytes, isCustomClaimKey, isCustomClaimValue, readCustomClaims };
276
+ export { CUSTOM_CLAIMS_CLAIM, CustomClaimValue, CustomClaims, CustomClaimsCheck, MAX_CUSTOM_CLAIMS_BYTES, MAX_CUSTOM_CLAIM_CONSTANT_LENGTH, MAX_CUSTOM_CLAIM_KEY_LENGTH, MAX_JWT_TEMPLATES, MAX_JWT_TEMPLATE_CLAIMS, MAX_ORGANIZATION_CLAIMS_BYTES, MAX_ORGANIZATION_PERMISSIONS_CLAIM, ORGANIZATION_ID_CLAIM, ORGANIZATION_PERMISSIONS_CLAIM, ORGANIZATION_ROLE_CLAIM, OrganizationCheck, OrganizationClaims, RESERVED_CLAIM_NAMES, SSO_CONNECTION_CLAIM, checkCustomClaims, customClaimsBytes, hasOrganizationAccess, isCustomClaimKey, isCustomClaimValue, organizationClaimsBytes, readCustomClaims, readOrganizationClaims };
@@ -1,7 +1,16 @@
1
1
  import {
2
2
  CUSTOM_CLAIMS_CLAIM2,
3
+ ORGANIZATION_ID_CLAIM2,
4
+ SSO_CONNECTION_CLAIM2,
5
+ ORGANIZATION_ROLE_CLAIM2,
6
+ ORGANIZATION_PERMISSIONS_CLAIM2,
3
7
  RESERVED_CLAIM_NAMES2,
4
8
  MAX_CUSTOM_CLAIMS_BYTES2,
9
+ MAX_ORGANIZATION_CLAIMS_BYTES2,
10
+ MAX_ORGANIZATION_PERMISSIONS_CLAIM2,
11
+ organizationClaimsBytes2,
12
+ readOrganizationClaims2,
13
+ hasOrganizationAccess2,
5
14
  MAX_JWT_TEMPLATES2,
6
15
  MAX_JWT_TEMPLATE_CLAIMS2,
7
16
  MAX_CUSTOM_CLAIM_KEY_LENGTH2,
@@ -11,7 +20,8 @@ import {
11
20
  customClaimsBytes2,
12
21
  checkCustomClaims2,
13
22
  readCustomClaims2
14
- } from "./shared/chunk-4rb5jsfz.js";
23
+ } from "./shared/chunk-fkx6fc8e.js";
24
+ import"./shared/chunk-yzgakhtb.js";
15
25
  export {
16
26
  CUSTOM_CLAIMS_CLAIM2 as CUSTOM_CLAIMS_CLAIM,
17
27
  MAX_CUSTOM_CLAIMS_BYTES2 as MAX_CUSTOM_CLAIMS_BYTES,
@@ -19,10 +29,19 @@ export {
19
29
  MAX_CUSTOM_CLAIM_KEY_LENGTH2 as MAX_CUSTOM_CLAIM_KEY_LENGTH,
20
30
  MAX_JWT_TEMPLATES2 as MAX_JWT_TEMPLATES,
21
31
  MAX_JWT_TEMPLATE_CLAIMS2 as MAX_JWT_TEMPLATE_CLAIMS,
32
+ MAX_ORGANIZATION_CLAIMS_BYTES2 as MAX_ORGANIZATION_CLAIMS_BYTES,
33
+ MAX_ORGANIZATION_PERMISSIONS_CLAIM2 as MAX_ORGANIZATION_PERMISSIONS_CLAIM,
34
+ ORGANIZATION_ID_CLAIM2 as ORGANIZATION_ID_CLAIM,
35
+ ORGANIZATION_PERMISSIONS_CLAIM2 as ORGANIZATION_PERMISSIONS_CLAIM,
36
+ ORGANIZATION_ROLE_CLAIM2 as ORGANIZATION_ROLE_CLAIM,
22
37
  RESERVED_CLAIM_NAMES2 as RESERVED_CLAIM_NAMES,
38
+ SSO_CONNECTION_CLAIM2 as SSO_CONNECTION_CLAIM,
23
39
  checkCustomClaims2 as checkCustomClaims,
24
40
  customClaimsBytes2 as customClaimsBytes,
41
+ hasOrganizationAccess2 as hasOrganizationAccess,
25
42
  isCustomClaimKey2 as isCustomClaimKey,
26
43
  isCustomClaimValue2 as isCustomClaimValue,
27
- readCustomClaims2 as readCustomClaims
44
+ organizationClaimsBytes2 as organizationClaimsBytes,
45
+ readCustomClaims2 as readCustomClaims,
46
+ readOrganizationClaims2 as readOrganizationClaims
28
47
  };
@@ -122,6 +122,22 @@ declare const ERROR_DEFINITIONS: {
122
122
  readonly status: 409;
123
123
  readonly message: "This account has no password yet. Use \"forgot password\" to set one.";
124
124
  };
125
+ readonly "import.unsupported_algorithm": {
126
+ readonly status: 422;
127
+ readonly message: "That password hash algorithm is not supported.";
128
+ };
129
+ readonly "import.hash_malformed": {
130
+ readonly status: 422;
131
+ readonly message: "That password hash is malformed.";
132
+ };
133
+ readonly "import.hash_parameters_too_weak": {
134
+ readonly status: 422;
135
+ readonly message: "That password hash is too weak to import.";
136
+ };
137
+ readonly "import.hash_parameters_too_costly": {
138
+ readonly status: 422;
139
+ readonly message: "That password hash is too costly to verify.";
140
+ };
125
141
  readonly "verification.invalid_code": {
126
142
  readonly status: 422;
127
143
  readonly message: "That code is incorrect.";
@@ -314,6 +330,194 @@ declare const ERROR_DEFINITIONS: {
314
330
  readonly status: 400;
315
331
  readonly message: "Signing in here needs a device key.";
316
332
  };
333
+ readonly "user.last_organization_manager": {
334
+ readonly status: 409;
335
+ readonly message: "This user is the only manager of an organization. Add another manager or delete the organization first.";
336
+ };
337
+ readonly "user.managed": {
338
+ readonly status: 403;
339
+ readonly message: "This account is managed by your organization. Ask your administrator to change it.";
340
+ };
341
+ readonly "organization.disabled": {
342
+ readonly status: 403;
343
+ readonly message: "Organizations are not enabled for this environment.";
344
+ };
345
+ readonly "organization.slug_taken": {
346
+ readonly status: 409;
347
+ readonly message: "An organization with that slug already exists.";
348
+ };
349
+ readonly "organization.member_exists": {
350
+ readonly status: 409;
351
+ readonly message: "That user is already a member of this organization.";
352
+ };
353
+ readonly "organization.last_manager": {
354
+ readonly status: 409;
355
+ readonly message: "An organization must keep at least one member who can manage its members.";
356
+ };
357
+ readonly "organization.role_unknown": {
358
+ readonly status: 422;
359
+ readonly message: "That role does not exist in this environment.";
360
+ };
361
+ readonly "organization.not_a_member": {
362
+ readonly status: 403;
363
+ readonly message: "You are not a member of that organization.";
364
+ };
365
+ readonly "organization.creation_disabled": {
366
+ readonly status: 403;
367
+ readonly message: "Creating an organization is not allowed in this environment.";
368
+ };
369
+ readonly "organization.limit_reached": {
370
+ readonly status: 403;
371
+ readonly message: "You have reached the number of organizations you can create.";
372
+ };
373
+ readonly "organization.personal_account_disabled": {
374
+ readonly status: 409;
375
+ readonly message: "An organization must be active in this environment.";
376
+ };
377
+ readonly "organization.role_exists": {
378
+ readonly status: 409;
379
+ readonly message: "A role with that key already exists in this environment.";
380
+ };
381
+ readonly "organization.role_in_use": {
382
+ readonly status: 409;
383
+ readonly message: "Members still hold this role. Give them another role first.";
384
+ };
385
+ readonly "organization.role_built_in": {
386
+ readonly status: 409;
387
+ readonly message: "A built-in role cannot be changed or deleted.";
388
+ };
389
+ readonly "organization.role_limit": {
390
+ readonly status: 409;
391
+ readonly message: "This environment has the most custom roles it can have.";
392
+ };
393
+ readonly "organization.permission_required": {
394
+ readonly status: 403;
395
+ readonly message: "Your role does not allow that.";
396
+ };
397
+ readonly "organization.role_not_assignable": {
398
+ readonly status: 403;
399
+ readonly message: "You can only invite to a role no stronger than yours.";
400
+ };
401
+ readonly "organization.invitation_exists": {
402
+ readonly status: 409;
403
+ readonly message: "That address already has a pending invitation.";
404
+ };
405
+ readonly "organization.invitation_not_found": {
406
+ readonly status: 404;
407
+ readonly message: "This invitation does not exist.";
408
+ };
409
+ readonly "organization.invitation_expired": {
410
+ readonly status: 410;
411
+ readonly message: "This invitation has expired.";
412
+ };
413
+ readonly "organization.invitation_revoked": {
414
+ readonly status: 410;
415
+ readonly message: "This invitation was withdrawn.";
416
+ };
417
+ readonly "organization.invitation_used": {
418
+ readonly status: 410;
419
+ readonly message: "This invitation was already used.";
420
+ };
421
+ readonly "organization.invitation_wrong_account": {
422
+ readonly status: 403;
423
+ readonly message: "This invitation was sent to another email address.";
424
+ };
425
+ readonly "organization.invitation_email_unverified": {
426
+ readonly status: 403;
427
+ readonly message: "Verify your email address to accept this invitation.";
428
+ };
429
+ readonly "organization.invitation_role_gone": {
430
+ readonly status: 409;
431
+ readonly message: "The role this invitation offers no longer exists.";
432
+ };
433
+ readonly "organization.domain_public": {
434
+ readonly status: 422;
435
+ readonly message: "A public email domain cannot be claimed by an organization.";
436
+ };
437
+ readonly "organization.domain_taken": {
438
+ readonly status: 409;
439
+ readonly message: "That domain is verified for an organization already.";
440
+ };
441
+ readonly "organization.domain_address_mismatch": {
442
+ readonly status: 422;
443
+ readonly message: "That address is not on the domain.";
444
+ };
445
+ readonly "organization.domain_limit": {
446
+ readonly status: 409;
447
+ readonly message: "This organization has the most domains it can have.";
448
+ };
449
+ readonly "organization.suggestion_unavailable": {
450
+ readonly status: 403;
451
+ readonly message: "You cannot join that organization.";
452
+ };
453
+ readonly "sso.disabled": {
454
+ readonly status: 403;
455
+ readonly message: "Single sign-on is not enabled for this environment.";
456
+ };
457
+ readonly "sso.connection_not_found": {
458
+ readonly status: 404;
459
+ readonly message: "No such single sign-on connection.";
460
+ };
461
+ readonly "sso.name_taken": {
462
+ readonly status: 409;
463
+ readonly message: "The organization already has a connection with that name.";
464
+ };
465
+ readonly "sso.domain_taken": {
466
+ readonly status: 409;
467
+ readonly message: "Another active connection already serves one of those domains.";
468
+ };
469
+ readonly "sso.domain_not_verified": {
470
+ readonly status: 422;
471
+ readonly message: "Every domain must be one of the organization's verified domains.";
472
+ };
473
+ readonly "sso.issuer_not_allowed": {
474
+ readonly status: 422;
475
+ readonly message: "The issuer is not an address the server may call.";
476
+ };
477
+ readonly "sso.saml_invalid": {
478
+ readonly status: 422;
479
+ readonly message: "The SAML settings could not be read or are incomplete.";
480
+ };
481
+ readonly "sso.connection_in_use": {
482
+ readonly status: 409;
483
+ readonly message: "The connection is active; disable it before deleting it.";
484
+ };
485
+ readonly "sso.invalid_transition": {
486
+ readonly status: 409;
487
+ readonly message: "A connection cannot move to that status from its current one.";
488
+ };
489
+ readonly "sso.url_not_https": {
490
+ readonly status: 422;
491
+ readonly message: "The identity provider’s sign-in address must start with https.";
492
+ };
493
+ readonly "sso.test_required": {
494
+ readonly status: 409;
495
+ readonly message: "Run a passing test sign-in of the connection’s current settings before activating it.";
496
+ };
497
+ readonly "sso.test_not_found": {
498
+ readonly status: 404;
499
+ readonly message: "No such test sign-in.";
500
+ };
501
+ readonly "sso.role_not_allowed": {
502
+ readonly status: 403;
503
+ readonly message: "A setup link cannot map a group to a role that holds system permissions.";
504
+ };
505
+ readonly "sso.unavailable": {
506
+ readonly status: 400;
507
+ readonly message: "Single sign-on is not available for that address.";
508
+ };
509
+ readonly "sso.provider_error": {
510
+ readonly status: 401;
511
+ readonly message: "The identity provider did not sign you in.";
512
+ };
513
+ readonly "sso.user_not_provisioned": {
514
+ readonly status: 403;
515
+ readonly message: "Your account has not been set up for this organization. Ask its administrator.";
516
+ };
517
+ readonly "sso.email_domain_mismatch": {
518
+ readonly status: 403;
519
+ readonly message: "Your email address is not on this connection's domains.";
520
+ };
317
521
  readonly rate_limited: {
318
522
  readonly status: 429;
319
523
  readonly message: "Too many requests. Try again shortly.";
@@ -2,7 +2,7 @@ import {
2
2
  ERROR_DEFINITIONS2,
3
3
  ERROR_CODES2,
4
4
  errorDefinition2
5
- } from "./shared/chunk-cce3bhet.js";
5
+ } from "./shared/chunk-5r2ka03q.js";
6
6
  export {
7
7
  ERROR_CODES2 as ERROR_CODES,
8
8
  ERROR_DEFINITIONS2 as ERROR_DEFINITIONS,
@@ -19,7 +19,7 @@
19
19
  * }
20
20
  * ```
21
21
  */
22
- declare const ACTIVITY_TYPES: readonly ["user.created", "user.email_verified", "user.banned", "user.unbanned", "user.deleted", "user.password_changed", "user.mfa_enabled", "user.mfa_disabled", "user.backup_codes_regenerated", "user.backup_code_used", "user.identity_linked", "user.identity_unlinked", "user.email_added", "user.passkey_added", "user.passkey_renamed", "user.passkey_removed", "user.passkey_counter_regressed", "user.phone_number_added", "user.phone_number_removed", "user.sms_factor_enabled", "user.sms_factor_removed", "session.created", "session.revoked", "session.reuse_detected", "session.stepped_up", "session.refresh_proof_refused", "api_key.created", "api_key.revoked", "signing_key.rotated", "environment.settings_updated", "oauth_provider.updated", "oauth_provider.deleted", "webhook_endpoint.created", "webhook_endpoint.updated", "webhook_endpoint.deleted", "webhook_endpoint.disabled", "webhook_endpoint.secret_rotated", "webhook_endpoint.previous_secret_revoked", "hook.created", "hook.updated", "hook.deleted", "native_app.created", "native_app.updated", "native_app.deleted", "proposal.created", "proposal.approved", "proposal.executed", "proposal.failed", "sign_in_test.started", "sign_in_test.finished"];
22
+ declare const ACTIVITY_TYPES: readonly ["user.created", "user.imported", "user.email_verified", "user.banned", "user.unbanned", "user.deleted", "user.password_changed", "user.mfa_enabled", "user.mfa_disabled", "user.backup_codes_regenerated", "user.backup_code_used", "user.identity_linked", "user.identity_unlinked", "user.sso_linked", "user.email_added", "user.passkey_added", "user.passkey_renamed", "user.passkey_removed", "user.passkey_counter_regressed", "user.phone_number_added", "user.phone_number_removed", "user.sms_factor_enabled", "user.sms_factor_removed", "session.created", "session.revoked", "session.reuse_detected", "session.stepped_up", "session.refresh_proof_refused", "api_key.created", "api_key.revoked", "signing_key.rotated", "environment.settings_updated", "oauth_provider.updated", "oauth_provider.deleted", "webhook_endpoint.created", "webhook_endpoint.updated", "webhook_endpoint.deleted", "webhook_endpoint.disabled", "webhook_endpoint.secret_rotated", "webhook_endpoint.previous_secret_revoked", "hook.created", "hook.updated", "hook.deleted", "native_app.created", "native_app.updated", "native_app.deleted", "sso_connection.created", "sso_connection.updated", "sso_connection.deleted", "scim_token.created", "scim_token.revoked", "setup_link.created", "setup_link.revoked", "user.scim_provisioned", "user.scim_updated", "scim_group.created", "scim_group.updated", "scim_group.deleted", "organization.created", "organization.updated", "organization.deleted", "organization_membership.added", "organization_membership.role_changed", "organization_membership.removed", "organization_role.created", "organization_role.updated", "organization_role.deleted", "organization_domain.claimed", "organization_domain.verified", "organization_domain.updated", "organization_domain.removed", "organization_invitation.created", "organization_invitation.accepted", "organization_invitation.declined", "organization_invitation.revoked", "proposal.created", "proposal.approved", "proposal.rejected", "proposal.executed", "proposal.failed", "audit.exported", "sign_in_test.started", "sign_in_test.finished"];
23
23
  /** A recorded action type: one of {@link ACTIVITY_TYPES}. */
24
24
  type ActivityType = (typeof ACTIVITY_TYPES)[number];
25
25
  /**
@@ -52,6 +52,7 @@ declare const EVENT_SCHEMA_VERSION = 1;
52
52
  */
53
53
  declare const EVENT_TARGET_TYPES: {
54
54
  readonly "user.created": "user";
55
+ readonly "user.imported": "user";
55
56
  readonly "user.email_verified": "user";
56
57
  readonly "user.banned": "user";
57
58
  readonly "user.unbanned": "user";
@@ -64,6 +65,7 @@ declare const EVENT_TARGET_TYPES: {
64
65
  readonly "user.identity_linked": "user";
65
66
  readonly "user.email_added": "user";
66
67
  readonly "user.identity_unlinked": "user";
68
+ readonly "user.sso_linked": "user";
67
69
  readonly "user.passkey_added": "user";
68
70
  readonly "user.passkey_renamed": "user";
69
71
  readonly "user.passkey_removed": "user";
@@ -95,10 +97,41 @@ declare const EVENT_TARGET_TYPES: {
95
97
  readonly "native_app.created": "native_app";
96
98
  readonly "native_app.updated": "native_app";
97
99
  readonly "native_app.deleted": "native_app";
100
+ readonly "sso_connection.created": "sso_connection";
101
+ readonly "sso_connection.updated": "sso_connection";
102
+ readonly "sso_connection.deleted": "sso_connection";
103
+ readonly "scim_token.created": "scim_token";
104
+ readonly "scim_token.revoked": "scim_token";
105
+ readonly "setup_link.created": "setup_link";
106
+ readonly "setup_link.revoked": "setup_link";
107
+ readonly "user.scim_provisioned": "user";
108
+ readonly "user.scim_updated": "user";
109
+ readonly "scim_group.created": "scim_group";
110
+ readonly "scim_group.updated": "scim_group";
111
+ readonly "scim_group.deleted": "scim_group";
112
+ readonly "organization.created": "organization";
113
+ readonly "organization.updated": "organization";
114
+ readonly "organization.deleted": "organization";
115
+ readonly "organization_membership.added": "organization_membership";
116
+ readonly "organization_membership.role_changed": "organization_membership";
117
+ readonly "organization_membership.removed": "organization_membership";
118
+ readonly "organization_role.created": "organization_role";
119
+ readonly "organization_role.updated": "organization_role";
120
+ readonly "organization_role.deleted": "organization_role";
121
+ readonly "organization_domain.claimed": "organization_domain";
122
+ readonly "organization_domain.verified": "organization_domain";
123
+ readonly "organization_domain.updated": "organization_domain";
124
+ readonly "organization_domain.removed": "organization_domain";
125
+ readonly "organization_invitation.created": "organization_invitation";
126
+ readonly "organization_invitation.accepted": "organization_invitation";
127
+ readonly "organization_invitation.declined": "organization_invitation";
128
+ readonly "organization_invitation.revoked": "organization_invitation";
98
129
  readonly "proposal.created": "proposal";
99
130
  readonly "proposal.approved": "proposal";
131
+ readonly "proposal.rejected": "proposal";
100
132
  readonly "proposal.executed": "proposal";
101
133
  readonly "proposal.failed": "proposal";
134
+ readonly "audit.exported": "environment";
102
135
  readonly "sign_in_test.started": "environment";
103
136
  readonly "sign_in_test.finished": "environment";
104
137
  };
@@ -2,7 +2,7 @@ import {
2
2
  ACTIVITY_TYPES2,
3
3
  EVENT_SCHEMA_VERSION2,
4
4
  EVENT_TARGET_TYPES2
5
- } from "./shared/chunk-7yqzghgm.js";
5
+ } from "./shared/chunk-bsea97tx.js";
6
6
  export {
7
7
  ACTIVITY_TYPES2 as ACTIVITY_TYPES,
8
8
  EVENT_SCHEMA_VERSION2 as EVENT_SCHEMA_VERSION,