@logto/schemas 1.40.1 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/alterations/1.41.0-1779864280-add-password-expiration-policy.ts +23 -0
  2. package/alterations/1.41.0-1779864281-add-is-password-expired-to-users.ts +18 -0
  3. package/alterations/1.41.0-1780358400-drop-oidc-model-instances-legacy-grant-id-index.ts +25 -0
  4. package/alterations/1.41.0-1780381219-add-username-policy.ts +41 -0
  5. package/alterations/1.41.0-1780643665-set-sign-up-profile-fields-default.ts +20 -0
  6. package/alterations/1.41.0-1780906060-add-verification-code-policy.ts +19 -0
  7. package/alterations/1.41.0-1781689400-add-sentinel-activities-created-at-index.ts +25 -0
  8. package/alterations/1.41.0-1782354362-set-admin-account-center-profile-fields.ts +28 -0
  9. package/alterations/1.41.0-1782375106-cover-service-logs-tenant-type-index-with-created-at.ts +36 -0
  10. package/alterations/1.42.0-1783916980-add-domain-verification-files.ts +20 -0
  11. package/alterations/1.42.0-1784619793-add-service-logs-created-at-index.ts +33 -0
  12. package/alterations/1.42.0-1784620000-add-saml-sso-connector-signing-keys-table.ts +38 -0
  13. package/alterations/utils/1704934999-tables.ts +22 -1
  14. package/alterations-js/1.41.0-1779864280-add-password-expiration-policy.js +19 -0
  15. package/alterations-js/1.41.0-1779864281-add-is-password-expired-to-users.js +14 -0
  16. package/alterations-js/1.41.0-1780358400-drop-oidc-model-instances-legacy-grant-id-index.js +21 -0
  17. package/alterations-js/1.41.0-1780381219-add-username-policy.js +37 -0
  18. package/alterations-js/1.41.0-1780643665-set-sign-up-profile-fields-default.js +16 -0
  19. package/alterations-js/1.41.0-1780906060-add-verification-code-policy.js +15 -0
  20. package/alterations-js/1.41.0-1781689400-add-sentinel-activities-created-at-index.js +21 -0
  21. package/alterations-js/1.41.0-1782354362-set-admin-account-center-profile-fields.js +23 -0
  22. package/alterations-js/1.41.0-1782375106-cover-service-logs-tenant-type-index-with-created-at.js +32 -0
  23. package/alterations-js/1.42.0-1783916980-add-domain-verification-files.js +16 -0
  24. package/alterations-js/1.42.0-1784619793-add-service-logs-created-at-index.js +29 -0
  25. package/alterations-js/1.42.0-1784620000-add-saml-sso-connector-signing-keys-table.js +33 -0
  26. package/alterations-js/utils/1704934999-tables.js +19 -1
  27. package/lib/consts/experience.d.ts +3 -0
  28. package/lib/consts/experience.js +3 -0
  29. package/lib/consts/index.d.ts +2 -0
  30. package/lib/consts/index.js +2 -0
  31. package/lib/consts/message-rate-limit.d.ts +65 -0
  32. package/lib/consts/message-rate-limit.js +29 -0
  33. package/lib/consts/message-rate-limit.test.d.ts +1 -0
  34. package/lib/consts/message-rate-limit.test.js +20 -0
  35. package/lib/consts/verification-code.d.ts +10 -0
  36. package/lib/consts/verification-code.js +10 -0
  37. package/lib/db-entries/domain.d.ts +4 -2
  38. package/lib/db-entries/domain.js +5 -1
  39. package/lib/db-entries/index.d.ts +1 -0
  40. package/lib/db-entries/index.js +1 -0
  41. package/lib/db-entries/saml-sso-connector-signing-key.d.ts +32 -0
  42. package/lib/db-entries/saml-sso-connector-signing-key.js +49 -0
  43. package/lib/db-entries/sign-in-experience.d.ts +10 -4
  44. package/lib/db-entries/sign-in-experience.js +13 -1
  45. package/lib/db-entries/user.d.ts +5 -1
  46. package/lib/db-entries/user.js +8 -0
  47. package/lib/foundations/jsonb-types/account-centers.d.ts +3 -0
  48. package/lib/foundations/jsonb-types/account-centers.js +1 -0
  49. package/lib/foundations/jsonb-types/custom-domain.d.ts +57 -0
  50. package/lib/foundations/jsonb-types/custom-domain.js +51 -0
  51. package/lib/foundations/jsonb-types/custom-domain.test.d.ts +1 -0
  52. package/lib/foundations/jsonb-types/custom-domain.test.js +38 -0
  53. package/lib/foundations/jsonb-types/hooks.d.ts +4 -4
  54. package/lib/foundations/jsonb-types/hooks.js +2 -0
  55. package/lib/foundations/jsonb-types/one-time-tokens.d.ts +5 -0
  56. package/lib/foundations/jsonb-types/one-time-tokens.js +2 -0
  57. package/lib/foundations/jsonb-types/sentinel.d.ts +16 -1
  58. package/lib/foundations/jsonb-types/sentinel.js +15 -0
  59. package/lib/foundations/jsonb-types/sign-in-experience.d.ts +90 -3
  60. package/lib/foundations/jsonb-types/sign-in-experience.js +20 -0
  61. package/lib/foundations/jsonb-types/sign-in-experience.test.js +49 -1
  62. package/lib/foundations/jsonb-types/users.d.ts +9 -0
  63. package/lib/foundations/jsonb-types/users.js +1 -0
  64. package/lib/seeds/account-center.js +1 -0
  65. package/lib/seeds/sign-in-experience.js +1 -0
  66. package/lib/seeds/sign-in-experience.test.js +5 -1
  67. package/lib/types/application.d.ts +131 -1
  68. package/lib/types/application.js +8 -0
  69. package/lib/types/consent.d.ts +8 -0
  70. package/lib/types/custom-profile-fields.d.ts +5 -1
  71. package/lib/types/domain.d.ts +9 -0
  72. package/lib/types/hook.d.ts +9 -2
  73. package/lib/types/interaction-event.d.ts +11 -0
  74. package/lib/types/interaction-event.js +12 -0
  75. package/lib/types/interactions.d.ts +2 -11
  76. package/lib/types/interactions.js +5 -12
  77. package/lib/types/log/action.d.ts +7 -0
  78. package/lib/types/log/action.js +6 -0
  79. package/lib/types/log/index.d.ts +5 -2
  80. package/lib/types/log/index.js +1 -0
  81. package/lib/types/logto-config/action.d.ts +963 -0
  82. package/lib/types/logto-config/action.js +77 -0
  83. package/lib/types/logto-config/index.d.ts +91 -13
  84. package/lib/types/logto-config/index.js +12 -0
  85. package/lib/types/logto-config/index.test.js +25 -1
  86. package/lib/types/logto-config/jwt-customizer.d.ts +162 -1
  87. package/lib/types/logto-config/jwt-customizer.js +14 -0
  88. package/lib/types/organization.d.ts +136 -1
  89. package/lib/types/organization.js +3 -2
  90. package/lib/types/saml-application.d.ts +3 -0
  91. package/lib/types/saml-application.js +3 -0
  92. package/lib/types/sign-in-experience.d.ts +11 -4
  93. package/lib/types/sign-in-experience.js +1 -1
  94. package/lib/types/sso-connector.d.ts +58 -0
  95. package/lib/types/sso-connector.js +12 -0
  96. package/lib/types/ssr.d.ts +11 -0
  97. package/lib/types/user-assets.d.ts +10 -0
  98. package/lib/types/user-assets.js +17 -0
  99. package/lib/types/user-sessions.d.ts +309 -34
  100. package/lib/types/user-sessions.js +5 -0
  101. package/lib/types/user.d.ts +15 -0
  102. package/lib/types/user.js +1 -0
  103. package/lib/types/verification-records/one-time-token-verification.d.ts +5 -0
  104. package/package.json +8 -8
  105. package/tables/domains.sql +1 -0
  106. package/tables/oidc_model_instances.sql +0 -8
  107. package/tables/saml_sso_connector_signing_keys.sql +21 -0
  108. package/tables/sentinel_activities.sql +4 -0
  109. package/tables/service_logs.sql +7 -2
  110. package/tables/sign_in_experiences.sql +15 -2
  111. package/tables/users.sql +7 -0
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { Applications } from '../db-entries/index.js';
2
3
  import { oidcSessionInstancePayloadGuard } from '../foundations/index.js';
3
4
  import { jwtCustomizerUserInteractionContextGuard } from './logto-config/jwt-customizer.js';
4
5
  export const userSessionSignInContextGuard = z
@@ -72,6 +73,10 @@ export const userApplicationGrantGuard = z.object({
72
73
  id: z.string(),
73
74
  payload: userApplicationGrantPayloadGuard,
74
75
  expiresAt: z.number(),
76
+ application: Applications.guard.pick({
77
+ id: true,
78
+ name: true,
79
+ }),
75
80
  });
76
81
  export const getUserApplicationGrantsResponseGuard = z.object({
77
82
  grants: z.array(userApplicationGrantGuard),
@@ -68,6 +68,7 @@ export declare const userInfoGuard: z.ZodObject<Pick<{
68
68
  id: string;
69
69
  key: string;
70
70
  createdAt: string;
71
+ lastUsedTimeStep?: number | undefined;
71
72
  lastUsedAt?: string | undefined;
72
73
  } | {
73
74
  type: MfaFactor.WebAuthn;
@@ -95,6 +96,7 @@ export declare const userInfoGuard: z.ZodObject<Pick<{
95
96
  id: string;
96
97
  key: string;
97
98
  createdAt: string;
99
+ lastUsedTimeStep?: number | undefined;
98
100
  lastUsedAt?: string | undefined;
99
101
  } | {
100
102
  type: MfaFactor.WebAuthn;
@@ -119,7 +121,9 @@ export declare const userInfoGuard: z.ZodObject<Pick<{
119
121
  lastUsedAt?: string | undefined;
120
122
  })[]>;
121
123
  isSuspended: z.ZodType<boolean, z.ZodTypeDef, boolean>;
124
+ isPasswordExpired: z.ZodType<boolean, z.ZodTypeDef, boolean>;
122
125
  lastSignInAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
126
+ passwordUpdatedAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
123
127
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
124
128
  updatedAt: z.ZodType<number, z.ZodTypeDef, number>;
125
129
  }, "name" | "id" | "applicationId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended">, "strip", z.ZodTypeAny, {
@@ -220,6 +224,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
220
224
  id: string;
221
225
  key: string;
222
226
  createdAt: string;
227
+ lastUsedTimeStep?: number | undefined;
223
228
  lastUsedAt?: string | undefined;
224
229
  } | {
225
230
  type: MfaFactor.WebAuthn;
@@ -247,6 +252,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
247
252
  id: string;
248
253
  key: string;
249
254
  createdAt: string;
255
+ lastUsedTimeStep?: number | undefined;
250
256
  lastUsedAt?: string | undefined;
251
257
  } | {
252
258
  type: MfaFactor.WebAuthn;
@@ -271,11 +277,14 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
271
277
  lastUsedAt?: string | undefined;
272
278
  })[]>;
273
279
  isSuspended: z.ZodType<boolean, z.ZodTypeDef, boolean>;
280
+ isPasswordExpired: z.ZodType<boolean, z.ZodTypeDef, boolean>;
274
281
  lastSignInAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
282
+ passwordUpdatedAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
275
283
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
276
284
  updatedAt: z.ZodType<number, z.ZodTypeDef, number>;
277
285
  }, "name" | "id" | "applicationId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended"> & {
278
286
  hasPassword: z.ZodOptional<z.ZodBoolean>;
287
+ hasSecurityVerificationMethod: z.ZodOptional<z.ZodBoolean>;
279
288
  ssoIdentities: z.ZodOptional<z.ZodArray<import("../foundations/schemas.js").Guard<import("../db-entries/user-sso-identity.js").UserSsoIdentity>, "many">>;
280
289
  }, "strip", z.ZodTypeAny, {
281
290
  name: string | null;
@@ -293,6 +302,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
293
302
  primaryPhone: string | null;
294
303
  isSuspended: boolean;
295
304
  hasPassword?: boolean | undefined;
305
+ hasSecurityVerificationMethod?: boolean | undefined;
296
306
  ssoIdentities?: import("../db-entries/user-sso-identity.js").UserSsoIdentity[] | undefined;
297
307
  }, {
298
308
  name: string | null;
@@ -310,6 +320,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
310
320
  primaryPhone: string | null;
311
321
  isSuspended: boolean;
312
322
  hasPassword?: boolean | undefined;
323
+ hasSecurityVerificationMethod?: boolean | undefined;
313
324
  ssoIdentities?: import("../db-entries/user-sso-identity.js").UserSsoIdentity[] | undefined;
314
325
  }>;
315
326
  export type UserProfileResponse = z.infer<typeof userProfileResponseGuard>;
@@ -433,6 +444,7 @@ export declare const featuredUserGuard: z.ZodObject<Pick<{
433
444
  id: string;
434
445
  key: string;
435
446
  createdAt: string;
447
+ lastUsedTimeStep?: number | undefined;
436
448
  lastUsedAt?: string | undefined;
437
449
  } | {
438
450
  type: MfaFactor.WebAuthn;
@@ -460,6 +472,7 @@ export declare const featuredUserGuard: z.ZodObject<Pick<{
460
472
  id: string;
461
473
  key: string;
462
474
  createdAt: string;
475
+ lastUsedTimeStep?: number | undefined;
463
476
  lastUsedAt?: string | undefined;
464
477
  } | {
465
478
  type: MfaFactor.WebAuthn;
@@ -484,7 +497,9 @@ export declare const featuredUserGuard: z.ZodObject<Pick<{
484
497
  lastUsedAt?: string | undefined;
485
498
  })[]>;
486
499
  isSuspended: z.ZodType<boolean, z.ZodTypeDef, boolean>;
500
+ isPasswordExpired: z.ZodType<boolean, z.ZodTypeDef, boolean>;
487
501
  lastSignInAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
502
+ passwordUpdatedAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
488
503
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
489
504
  updatedAt: z.ZodType<number, z.ZodTypeDef, number>;
490
505
  }, "name" | "id" | "avatar">, "strip", z.ZodTypeAny, {
package/lib/types/user.js CHANGED
@@ -23,6 +23,7 @@ export const userInfoGuard = Users.guard.pick(
23
23
  Object.fromEntries(userInfoSelectFields.map((field) => [field, true])));
24
24
  export const userProfileResponseGuard = userInfoGuard.extend({
25
25
  hasPassword: z.boolean().optional(),
26
+ hasSecurityVerificationMethod: z.boolean().optional(),
26
27
  ssoIdentities: z.array(UserSsoIdentities.guard).optional(),
27
28
  });
28
29
  export const userMfaVerificationResponseGuard = z
@@ -25,10 +25,13 @@ export declare const oneTimeTokenVerificationRecordDataGuard: z.ZodObject<{
25
25
  }>;
26
26
  oneTimeTokenContext: z.ZodOptional<z.ZodObject<{
27
27
  jitOrganizationIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
28
+ interactionEvent: z.ZodOptional<z.ZodNativeEnum<typeof import("../interaction-event.js").InteractionEvent>>;
28
29
  }, "strip", z.ZodTypeAny, {
29
30
  jitOrganizationIds?: string[] | undefined;
31
+ interactionEvent?: import("../interaction-event.js").InteractionEvent | undefined;
30
32
  }, {
31
33
  jitOrganizationIds?: string[] | undefined;
34
+ interactionEvent?: import("../interaction-event.js").InteractionEvent | undefined;
32
35
  }>>;
33
36
  }, "strip", z.ZodTypeAny, {
34
37
  type: VerificationType.OneTimeToken;
@@ -40,6 +43,7 @@ export declare const oneTimeTokenVerificationRecordDataGuard: z.ZodObject<{
40
43
  verified: boolean;
41
44
  oneTimeTokenContext?: {
42
45
  jitOrganizationIds?: string[] | undefined;
46
+ interactionEvent?: import("../interaction-event.js").InteractionEvent | undefined;
43
47
  } | undefined;
44
48
  }, {
45
49
  type: VerificationType.OneTimeToken;
@@ -51,5 +55,6 @@ export declare const oneTimeTokenVerificationRecordDataGuard: z.ZodObject<{
51
55
  verified: boolean;
52
56
  oneTimeTokenContext?: {
53
57
  jitOrganizationIds?: string[] | undefined;
58
+ interactionEvent?: import("../interaction-event.js").InteractionEvent | undefined;
54
59
  } | undefined;
55
60
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logto/schemas",
3
- "version": "1.40.1",
3
+ "version": "1.42.0",
4
4
  "author": "Silverhand Inc. <contact@silverhand.io>",
5
5
  "license": "MPL-2.0",
6
6
  "type": "module",
@@ -31,7 +31,7 @@
31
31
  "@types/inquirer": "^9.0.0",
32
32
  "@types/node": "^22.14.0",
33
33
  "@types/pluralize": "^0.0.33",
34
- "@vitest/coverage-v8": "^3.1.1",
34
+ "@vitest/coverage-v8": "^4.1.8",
35
35
  "camelcase": "^8.0.0",
36
36
  "chalk": "^5.3.0",
37
37
  "eslint": "^8.56.0",
@@ -40,7 +40,7 @@
40
40
  "prettier": "^3.5.3",
41
41
  "roarr": "^7.11.0",
42
42
  "typescript": "^5.5.3",
43
- "vitest": "^3.1.1"
43
+ "vitest": "^4.1.8"
44
44
  },
45
45
  "eslintConfig": {
46
46
  "extends": "@silverhand",
@@ -65,12 +65,12 @@
65
65
  "dependencies": {
66
66
  "@withtyped/server": "^0.14.0",
67
67
  "nanoid": "^5.0.9",
68
- "@logto/connector-kit": "^5.0.1",
69
- "@logto/core-kit": "^2.10.0",
70
- "@logto/phrases": "^1.28.0",
68
+ "@logto/connector-kit": "^5.1.0",
71
69
  "@logto/language-kit": "^1.3.0",
72
- "@logto/shared": "^3.4.0",
73
- "@logto/phrases-experience": "^1.13.3"
70
+ "@logto/phrases": "^1.30.0",
71
+ "@logto/core-kit": "^2.12.0",
72
+ "@logto/shared": "^3.4.2",
73
+ "@logto/phrases-experience": "^1.14.1"
74
74
  },
75
75
  "peerDependencies": {
76
76
  "zod": "3.24.3"
@@ -6,6 +6,7 @@ create table domains (
6
6
  status varchar(32) /* @use DomainStatus */ not null default('PendingVerification'),
7
7
  error_message varchar(1024),
8
8
  dns_records jsonb /* @use DomainDnsRecords */ not null default '[]'::jsonb,
9
+ verification_files jsonb /* @use DomainVerificationFiles */ not null default '[]'::jsonb,
9
10
  cloudflare_data jsonb /* @use CloudflareData */,
10
11
  updated_at timestamptz not null default(now()),
11
12
  created_at timestamptz not null default(now()),
@@ -27,14 +27,6 @@ create index oidc_model_instances__model_name_payload_uid
27
27
  (payload->>'uid')
28
28
  );
29
29
 
30
- /* TODO: Consider dropping this full data index if the partial index proves to be effective and safe. */
31
- create index oidc_model_instances__model_name_payload_grant_id
32
- on oidc_model_instances (
33
- tenant_id,
34
- model_name,
35
- (payload->>'grantId')
36
- );
37
-
38
30
  create index oidc_model_instances__model_name_payload_grant_id_partial
39
31
  on oidc_model_instances (tenant_id, model_name, (payload->>'grantId'))
40
32
  where payload ? 'grantId';
@@ -0,0 +1,21 @@
1
+ /* init_order = 2 */
2
+
3
+ create table saml_sso_connector_signing_keys (
4
+ id varchar(21) not null,
5
+ tenant_id varchar(21) not null
6
+ references tenants (id) on update cascade on delete cascade,
7
+ sso_connector_id varchar(128) not null
8
+ references sso_connectors (id) on update cascade on delete cascade,
9
+ /** The SP private key (plaintext PEM) used to sign the SAML AuthnRequest. Tenant-isolated by RLS and never returned by the API. */
10
+ private_key text not null,
11
+ /** The PEM-encoded self-signed SP certificate matching the private key. Public and safe to expose. */
12
+ certificate text not null,
13
+ created_at timestamptz not null default now(),
14
+ expires_at timestamptz not null,
15
+ active boolean not null,
16
+ primary key (tenant_id, sso_connector_id, id)
17
+ );
18
+
19
+ create unique index saml_sso_connector_signing_keys__unique_active
20
+ on saml_sso_connector_signing_keys (tenant_id, sso_connector_id, active)
21
+ where active;
@@ -33,3 +33,7 @@ create index sentinel_activities__target_type_target_hash
33
33
 
34
34
  create index sentinel_activities__target_type_target_hash_action_action_result_decision
35
35
  on sentinel_activities (tenant_id, target_type, target_hash, action, action_result, decision);
36
+
37
+ /** Supports the cross-tenant retention prune of stale activity rows by age. */
38
+ create index sentinel_activities__created_at
39
+ on sentinel_activities (created_at);
@@ -10,7 +10,12 @@ create table service_logs (
10
10
  create index service_logs__id
11
11
  on service_logs (id);
12
12
 
13
- create index service_logs__tenant_id__type
14
- on service_logs (tenant_id, type);
13
+ create index service_logs__tenant_id__type__created_at
14
+ on service_logs (tenant_id, type, created_at);
15
+
16
+ /* Global oldest-first scan for the age-based retention prune (the composite index above leads with
17
+ `tenant_id`, so it can't drive a tenant-agnostic `created_at` range scan). */
18
+ create index service_logs__created_at
19
+ on service_logs (created_at);
15
20
 
16
21
  /* no_after_each */
@@ -32,9 +32,22 @@ create table sign_in_experiences (
32
32
  captcha_policy jsonb /* @use CaptchaPolicy */ not null default '{}'::jsonb,
33
33
  sentinel_policy jsonb /* @use SentinelPolicy */ not null default '{}'::jsonb,
34
34
  email_blocklist_policy jsonb /* @use EmailBlocklistPolicy */ not null default '{}'::jsonb,
35
+ verification_code_policy jsonb /* @use VerificationCodePolicy */ not null default '{}'::jsonb,
35
36
  forgot_password_methods jsonb /* @use ForgotPasswordMethods */ default '[]'::jsonb,
36
37
  passkey_sign_in jsonb /* @use PasskeySignIn */ not null default '{}'::jsonb,
37
- /** Nullable by design: null keeps legacy full-catalog behavior and [] collects no custom profile fields. */
38
- sign_up_profile_fields jsonb /* @use SignUpProfileFields */,
38
+ /** Nullable by design: null keeps legacy full-catalog behavior, and new rows default to [] to collect no custom profile fields. */
39
+ sign_up_profile_fields jsonb /* @use SignUpProfileFields */ default '[]'::jsonb,
40
+ password_expiration jsonb /* @use PasswordExpirationPolicy */ not null default '{}'::jsonb,
41
+ username_policy jsonb /* @use UsernamePolicy */ not null default ('{
42
+ "caseSensitive": true,
43
+ "minLength": 1,
44
+ "maxLength": 128,
45
+ "allowedChars": {
46
+ "lowercase": true,
47
+ "uppercase": true,
48
+ "numbers": true,
49
+ "underscore": true
50
+ }
51
+ }'::jsonb),
39
52
  primary key (tenant_id, id)
40
53
  );
package/tables/users.sql CHANGED
@@ -22,7 +22,9 @@ create table users (
22
22
  logto_config jsonb /* @use JsonObject */ not null default '{}'::jsonb,
23
23
  mfa_verifications jsonb /* @use MfaVerifications */ not null default '[]'::jsonb,
24
24
  is_suspended boolean not null default false,
25
+ is_password_expired boolean not null default false,
25
26
  last_sign_in_at timestamptz,
27
+ password_updated_at timestamptz,
26
28
  created_at timestamptz not null default (now()),
27
29
  updated_at timestamptz not null default (now()),
28
30
  primary key (id),
@@ -44,6 +46,11 @@ create index users__name
44
46
  create index users_mfa_verifications_gin
45
47
  on users using gin (mfa_verifications jsonb_path_ops);
46
48
 
49
+ /* Supports case-insensitive username lookups and case-flip conflict detection. */
50
+ create index users__tenant_lower_username
51
+ on users (tenant_id, lower(username))
52
+ where username is not null;
53
+
47
54
  create trigger set_updated_at
48
55
  before update on users
49
56
  for each row