@logto/schemas 1.42.0 → 1.44.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 (189) hide show
  1. package/alterations/1.43.0-1785393731-add-oidc-model-instances-account-id-partial-index.ts +33 -0
  2. package/alterations/1.43.0-1785481546-add-tenant-aware-scope-indexes.ts +33 -0
  3. package/alterations/1.43.0-1785488115-add-cimd-permission-ceiling-tables.ts +77 -0
  4. package/alterations/1.43.0-1785722831-add-oidc-session-extensions-account-id-index.ts +27 -0
  5. package/alterations/1.43.0-1785835991-add-cimd-client-identifier-columns.ts +31 -0
  6. package/alterations/1.43.0-1786325989-add-cimd-grant-organizations-table.ts +54 -0
  7. package/alterations/1.43.0-1786333495-add-trusted-devices.ts +57 -0
  8. package/alterations/1.43.0-1786373004-tighten-cimd-grant-organizations-pkey.ts +28 -0
  9. package/alterations/1.43.0-1786414712-add-service-logs-email-indexes.ts +34 -0
  10. package/alterations/1.43.0-1786431364-add-cimd-grant-client-snapshots-table.ts +43 -0
  11. package/alterations/1.44.0-1788946735-add-saml-authn-request-config.ts +18 -0
  12. package/alterations/1.44.0-1789000000-extend-user-id-length.ts +61 -0
  13. package/alterations-js/1.43.0-1785393731-add-oidc-model-instances-account-id-partial-index.js +28 -0
  14. package/alterations-js/1.43.0-1785481546-add-tenant-aware-scope-indexes.js +28 -0
  15. package/alterations-js/1.43.0-1785488115-add-cimd-permission-ceiling-tables.js +69 -0
  16. package/alterations-js/1.43.0-1785722831-add-oidc-session-extensions-account-id-index.js +23 -0
  17. package/alterations-js/1.43.0-1785835991-add-cimd-client-identifier-columns.js +27 -0
  18. package/alterations-js/1.43.0-1786325989-add-cimd-grant-organizations-table.js +49 -0
  19. package/alterations-js/1.43.0-1786333495-add-trusted-devices.js +50 -0
  20. package/alterations-js/1.43.0-1786373004-tighten-cimd-grant-organizations-pkey.js +24 -0
  21. package/alterations-js/1.43.0-1786414712-add-service-logs-email-indexes.js +30 -0
  22. package/alterations-js/1.43.0-1786431364-add-cimd-grant-client-snapshots-table.js +38 -0
  23. package/alterations-js/1.44.0-1788946735-add-saml-authn-request-config.js +14 -0
  24. package/alterations-js/1.44.0-1789000000-extend-user-id-length.js +47 -0
  25. package/lib/consts/experience.d.ts +3 -0
  26. package/lib/consts/experience.js +3 -0
  27. package/lib/consts/index.d.ts +2 -0
  28. package/lib/consts/index.js +2 -0
  29. package/lib/consts/license.d.ts +222 -0
  30. package/lib/consts/license.js +81 -0
  31. package/lib/consts/license.test.d.ts +1 -0
  32. package/lib/consts/license.test.js +96 -0
  33. package/lib/consts/oidc.d.ts +15 -1
  34. package/lib/consts/oidc.js +11 -0
  35. package/lib/consts/oidc.test.d.ts +1 -0
  36. package/lib/consts/oidc.test.js +15 -0
  37. package/lib/consts/product-event.d.ts +5 -1
  38. package/lib/consts/product-event.js +4 -0
  39. package/lib/consts/social-state.d.ts +12 -0
  40. package/lib/consts/social-state.js +12 -0
  41. package/lib/consts/subscriptions.d.ts +13 -1
  42. package/lib/consts/subscriptions.js +12 -0
  43. package/lib/db-entries/aggregated-daily-active-user.js +2 -2
  44. package/lib/db-entries/application-access-control-user-relation.js +2 -2
  45. package/lib/db-entries/application-user-consent-organization.js +2 -2
  46. package/lib/db-entries/cimd-grant-client-snapshot.d.ts +32 -0
  47. package/lib/db-entries/cimd-grant-client-snapshot.js +45 -0
  48. package/lib/db-entries/cimd-grant-organization.d.ts +30 -0
  49. package/lib/db-entries/cimd-grant-organization.js +37 -0
  50. package/lib/db-entries/cimd-organization-resource-scope.d.ts +20 -0
  51. package/lib/db-entries/cimd-organization-resource-scope.js +25 -0
  52. package/lib/db-entries/cimd-organization-scope.d.ts +20 -0
  53. package/lib/db-entries/cimd-organization-scope.js +25 -0
  54. package/lib/db-entries/cimd-resource-scope.d.ts +20 -0
  55. package/lib/db-entries/cimd-resource-scope.js +25 -0
  56. package/lib/db-entries/cimd-user-scope.d.ts +20 -0
  57. package/lib/db-entries/cimd-user-scope.js +25 -0
  58. package/lib/db-entries/daily-active-user.js +2 -2
  59. package/lib/db-entries/index.d.ts +7 -0
  60. package/lib/db-entries/index.js +7 -0
  61. package/lib/db-entries/oidc-session-extension.d.ts +3 -1
  62. package/lib/db-entries/oidc-session-extension.js +6 -2
  63. package/lib/db-entries/organization-invitation.js +4 -4
  64. package/lib/db-entries/organization-role-user-relation.js +2 -2
  65. package/lib/db-entries/organization-user-relation.js +2 -2
  66. package/lib/db-entries/organization.d.ts +5 -1
  67. package/lib/db-entries/organization.js +4 -0
  68. package/lib/db-entries/personal-access-token.js +2 -2
  69. package/lib/db-entries/saml-application-config.d.ts +4 -2
  70. package/lib/db-entries/saml-application-config.js +5 -1
  71. package/lib/db-entries/secret.js +2 -2
  72. package/lib/db-entries/sign-in-experience.d.ts +4 -2
  73. package/lib/db-entries/sign-in-experience.js +5 -1
  74. package/lib/db-entries/subject-token.js +2 -2
  75. package/lib/db-entries/trusted-device.d.ts +36 -0
  76. package/lib/db-entries/trusted-device.js +62 -0
  77. package/lib/db-entries/user-geo-location.js +2 -2
  78. package/lib/db-entries/user-sign-in-country.js +2 -2
  79. package/lib/db-entries/user-sso-identity.js +2 -2
  80. package/lib/db-entries/user.d.ts +3 -1
  81. package/lib/db-entries/user.js +6 -2
  82. package/lib/db-entries/users-role.js +2 -2
  83. package/lib/db-entries/verification-record.js +2 -2
  84. package/lib/db-entries/verification-status.js +2 -2
  85. package/lib/foundations/jsonb-types/account-centers.d.ts +3 -0
  86. package/lib/foundations/jsonb-types/account-centers.js +1 -0
  87. package/lib/foundations/jsonb-types/account-centers.test.d.ts +1 -0
  88. package/lib/foundations/jsonb-types/account-centers.test.js +13 -0
  89. package/lib/foundations/jsonb-types/captcha.d.ts +47 -1
  90. package/lib/foundations/jsonb-types/captcha.js +20 -0
  91. package/lib/foundations/jsonb-types/hooks.d.ts +5 -4
  92. package/lib/foundations/jsonb-types/hooks.js +3 -0
  93. package/lib/foundations/jsonb-types/logs.d.ts +18 -0
  94. package/lib/foundations/jsonb-types/logs.js +6 -0
  95. package/lib/foundations/jsonb-types/saml-application-configs.d.ts +23 -0
  96. package/lib/foundations/jsonb-types/saml-application-configs.js +16 -0
  97. package/lib/foundations/jsonb-types/saml-application-configs.test.js +24 -1
  98. package/lib/foundations/jsonb-types/sign-in-experience.d.ts +23 -3
  99. package/lib/foundations/jsonb-types/sign-in-experience.js +9 -0
  100. package/lib/foundations/jsonb-types/sign-in-experience.test.js +17 -1
  101. package/lib/types/authentication-context.d.ts +224 -0
  102. package/lib/types/authentication-context.js +238 -0
  103. package/lib/types/authentication-context.test.d.ts +1 -0
  104. package/lib/types/authentication-context.test.js +186 -0
  105. package/lib/types/connector.d.ts +8 -0
  106. package/lib/types/consent.d.ts +16 -190
  107. package/lib/types/consent.js +10 -1
  108. package/lib/types/cookie.d.ts +4 -0
  109. package/lib/types/cookie.js +6 -1
  110. package/lib/types/custom-profile-fields.d.ts +1 -0
  111. package/lib/types/hook.d.ts +31 -6
  112. package/lib/types/index.d.ts +2 -0
  113. package/lib/types/index.js +2 -0
  114. package/lib/types/interactions.d.ts +161 -0
  115. package/lib/types/interactions.js +23 -0
  116. package/lib/types/log/index.d.ts +5 -2
  117. package/lib/types/log/index.js +1 -0
  118. package/lib/types/log/interaction.d.ts +15 -2
  119. package/lib/types/log/interaction.js +5 -0
  120. package/lib/types/log/trusted-device.d.ts +7 -0
  121. package/lib/types/log/trusted-device.js +6 -0
  122. package/lib/types/logto-config/action.d.ts +1 -1
  123. package/lib/types/logto-config/action.js +1 -1
  124. package/lib/types/logto-config/index.d.ts +83 -7
  125. package/lib/types/logto-config/index.js +14 -0
  126. package/lib/types/logto-config/index.test.js +23 -0
  127. package/lib/types/logto-config/jwt-customizer.d.ts +123 -10
  128. package/lib/types/logto-config/jwt-customizer.js +1 -1
  129. package/lib/types/logto-config/oidc-provider.d.ts +2 -2
  130. package/lib/types/saml-application.d.ts +55 -1
  131. package/lib/types/saml-application.js +7 -1
  132. package/lib/types/service-log.d.ts +14 -1
  133. package/lib/types/service-log.js +13 -0
  134. package/lib/types/sign-in-experience.d.ts +20 -6
  135. package/lib/types/sign-in-experience.js +1 -0
  136. package/lib/types/ssr.d.ts +2 -0
  137. package/lib/types/system.d.ts +59 -7
  138. package/lib/types/system.js +36 -0
  139. package/lib/types/system.test.d.ts +1 -0
  140. package/lib/types/system.test.js +26 -0
  141. package/lib/types/trusted-device.d.ts +67 -0
  142. package/lib/types/trusted-device.js +16 -0
  143. package/lib/types/user-sessions.d.ts +195 -209
  144. package/lib/types/user-sessions.js +9 -4
  145. package/lib/types/user.d.ts +10 -3
  146. package/lib/types/user.js +1 -0
  147. package/lib/types/verification-records/code-verification.d.ts +17 -0
  148. package/lib/types/verification-records/code-verification.js +1 -0
  149. package/lib/utils/cimd.d.ts +14 -0
  150. package/lib/utils/cimd.js +14 -0
  151. package/lib/utils/cimd.test.d.ts +1 -0
  152. package/lib/utils/cimd.test.js +9 -0
  153. package/lib/utils/index.d.ts +1 -0
  154. package/lib/utils/index.js +1 -0
  155. package/lib/utils/oidc-private-key.test.js +44 -0
  156. package/package.json +9 -9
  157. package/tables/aggregated_daily_active_users.sql +1 -1
  158. package/tables/application_access_control_user_relations.sql +1 -1
  159. package/tables/application_user_consent_organizations.sql +1 -1
  160. package/tables/cimd_grant_client_snapshots.sql +27 -0
  161. package/tables/cimd_grant_organizations.sql +38 -0
  162. package/tables/cimd_organization_resource_scopes.sql +16 -0
  163. package/tables/cimd_organization_scopes.sql +15 -0
  164. package/tables/cimd_resource_scopes.sql +15 -0
  165. package/tables/cimd_user_scopes.sql +13 -0
  166. package/tables/daily_active_users.sql +1 -1
  167. package/tables/oidc_model_instances.sql +5 -0
  168. package/tables/oidc_session_extensions.sql +6 -1
  169. package/tables/organization_invitations.sql +2 -2
  170. package/tables/organization_role_user_relations.sql +1 -1
  171. package/tables/organization_scopes.sql +4 -0
  172. package/tables/organization_user_relations.sql +1 -1
  173. package/tables/organizations.sql +2 -0
  174. package/tables/personal_access_tokens.sql +1 -1
  175. package/tables/saml_application_configs.sql +1 -0
  176. package/tables/scopes.sql +4 -0
  177. package/tables/secrets.sql +1 -1
  178. package/tables/service_logs.sql +14 -0
  179. package/tables/sign_in_experiences.sql +1 -0
  180. package/tables/subject_tokens.sql +1 -1
  181. package/tables/trusted_devices.sql +25 -0
  182. package/tables/user_geo_locations.sql +1 -1
  183. package/tables/user_sign_in_countries.sql +1 -1
  184. package/tables/user_sso_identities.sql +1 -1
  185. package/tables/users.sql +2 -1
  186. package/tables/users_roles.sql +1 -1
  187. package/tables/verification_records.sql +1 -1
  188. package/tables/verification_statuses.sql +1 -1
  189. package/LICENSE +0 -373
@@ -1,5 +1,4 @@
1
1
  import { z } from 'zod';
2
- import { Applications } from '../db-entries/index.js';
3
2
  import { oidcSessionInstancePayloadGuard } from '../foundations/index.js';
4
3
  import { jwtCustomizerUserInteractionContextGuard } from './logto-config/jwt-customizer.js';
5
4
  export const userSessionSignInContextGuard = z
@@ -73,9 +72,15 @@ export const userApplicationGrantGuard = z.object({
73
72
  id: z.string(),
74
73
  payload: userApplicationGrantPayloadGuard,
75
74
  expiresAt: z.number(),
76
- application: Applications.guard.pick({
77
- id: true,
78
- name: true,
75
+ /**
76
+ * A CIMD (client ID metadata document) grant fills this slot with a URL identity that has no
77
+ * `applications` row: the identifier URL lands in `id` and `name` comes from the consent-time
78
+ * snapshot, so neither field can keep the applications table varchar bounds. Consumers tell
79
+ * the kinds apart by the id shape.
80
+ */
81
+ application: z.object({
82
+ id: z.string(),
83
+ name: z.string(),
79
84
  }),
80
85
  });
81
86
  export const getUserApplicationGrantsResponseGuard = z.object({
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { type User } from '../db-entries/index.js';
3
3
  import { MfaFactor } from '../foundations/index.js';
4
- export declare const userInfoSelectFields: readonly ("name" | "id" | "applicationId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended")[];
4
+ export declare const userInfoSelectFields: readonly ("name" | "id" | "applicationId" | "cimdClientId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended")[];
5
5
  export declare const userInfoGuard: z.ZodObject<Pick<{
6
6
  tenantId: z.ZodType<string, z.ZodTypeDef, string>;
7
7
  id: z.ZodType<string, z.ZodTypeDef, string>;
@@ -54,6 +54,7 @@ export declare const userInfoGuard: z.ZodObject<Pick<{
54
54
  }>;
55
55
  }>>;
56
56
  applicationId: z.ZodType<string | null, z.ZodTypeDef, string | null>;
57
+ cimdClientId: z.ZodType<string | null, z.ZodTypeDef, string | null>;
57
58
  identities: z.ZodType<Record<string, {
58
59
  userId: string;
59
60
  details?: Record<string, import("@withtyped/server/lib/types.js").Json> | undefined;
@@ -126,10 +127,11 @@ export declare const userInfoGuard: z.ZodObject<Pick<{
126
127
  passwordUpdatedAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
127
128
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
128
129
  updatedAt: z.ZodType<number, z.ZodTypeDef, number>;
129
- }, "name" | "id" | "applicationId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended">, "strip", z.ZodTypeAny, {
130
+ }, "name" | "id" | "applicationId" | "cimdClientId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended">, "strip", z.ZodTypeAny, {
130
131
  name: string | null;
131
132
  id: string;
132
133
  applicationId: string | null;
134
+ cimdClientId: string | null;
133
135
  username: string | null;
134
136
  createdAt: number;
135
137
  profile: import("../foundations/index.js").UserProfile;
@@ -145,6 +147,7 @@ export declare const userInfoGuard: z.ZodObject<Pick<{
145
147
  name: string | null;
146
148
  id: string;
147
149
  applicationId: string | null;
150
+ cimdClientId: string | null;
148
151
  username: string | null;
149
152
  createdAt: number;
150
153
  profile: import("../foundations/index.js").UserProfile;
@@ -210,6 +213,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
210
213
  }>;
211
214
  }>>;
212
215
  applicationId: z.ZodType<string | null, z.ZodTypeDef, string | null>;
216
+ cimdClientId: z.ZodType<string | null, z.ZodTypeDef, string | null>;
213
217
  identities: z.ZodType<Record<string, {
214
218
  userId: string;
215
219
  details?: Record<string, import("@withtyped/server/lib/types.js").Json> | undefined;
@@ -282,7 +286,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
282
286
  passwordUpdatedAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
283
287
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
284
288
  updatedAt: z.ZodType<number, z.ZodTypeDef, number>;
285
- }, "name" | "id" | "applicationId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended"> & {
289
+ }, "name" | "id" | "applicationId" | "cimdClientId" | "username" | "createdAt" | "profile" | "avatar" | "customData" | "identities" | "updatedAt" | "lastSignInAt" | "primaryEmail" | "primaryPhone" | "isSuspended"> & {
286
290
  hasPassword: z.ZodOptional<z.ZodBoolean>;
287
291
  hasSecurityVerificationMethod: z.ZodOptional<z.ZodBoolean>;
288
292
  ssoIdentities: z.ZodOptional<z.ZodArray<import("../foundations/schemas.js").Guard<import("../db-entries/user-sso-identity.js").UserSsoIdentity>, "many">>;
@@ -290,6 +294,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
290
294
  name: string | null;
291
295
  id: string;
292
296
  applicationId: string | null;
297
+ cimdClientId: string | null;
293
298
  username: string | null;
294
299
  createdAt: number;
295
300
  profile: import("../foundations/index.js").UserProfile;
@@ -308,6 +313,7 @@ export declare const userProfileResponseGuard: z.ZodObject<Pick<{
308
313
  name: string | null;
309
314
  id: string;
310
315
  applicationId: string | null;
316
+ cimdClientId: string | null;
311
317
  username: string | null;
312
318
  createdAt: number;
313
319
  profile: import("../foundations/index.js").UserProfile;
@@ -430,6 +436,7 @@ export declare const featuredUserGuard: z.ZodObject<Pick<{
430
436
  }>;
431
437
  }>>;
432
438
  applicationId: z.ZodType<string | null, z.ZodTypeDef, string | null>;
439
+ cimdClientId: z.ZodType<string | null, z.ZodTypeDef, string | null>;
433
440
  identities: z.ZodType<Record<string, {
434
441
  userId: string;
435
442
  details?: Record<string, import("@withtyped/server/lib/types.js").Json> | undefined;
package/lib/types/user.js CHANGED
@@ -16,6 +16,7 @@ export const userInfoSelectFields = Object.freeze([
16
16
  'updatedAt',
17
17
  'profile',
18
18
  'applicationId',
19
+ 'cimdClientId',
19
20
  'isSuspended',
20
21
  ]);
21
22
  export const userInfoGuard = Users.guard.pick(
@@ -17,11 +17,17 @@ export type CodeVerificationRecordData<T extends CodeVerificationType = CodeVeri
17
17
  identifier: VerificationCodeIdentifierOf<T>;
18
18
  templateType: TemplateType;
19
19
  verified: boolean;
20
+ /**
21
+ * The user the identifier was resolved from, when the record was created for the subject the
22
+ * interaction carries rather than from a client-supplied identifier.
23
+ */
24
+ userId?: string;
20
25
  };
21
26
  export declare const emailCodeVerificationRecordDataGuard: z.ZodObject<{
22
27
  id: z.ZodString;
23
28
  templateType: z.ZodNativeEnum<typeof TemplateType>;
24
29
  verified: z.ZodBoolean;
30
+ userId: z.ZodOptional<z.ZodString>;
25
31
  } & {
26
32
  type: z.ZodLiteral<VerificationType.EmailVerificationCode>;
27
33
  identifier: z.ZodObject<{
@@ -43,6 +49,7 @@ export declare const emailCodeVerificationRecordDataGuard: z.ZodObject<{
43
49
  };
44
50
  templateType: TemplateType;
45
51
  verified: boolean;
52
+ userId?: string | undefined;
46
53
  }, {
47
54
  type: VerificationType.EmailVerificationCode;
48
55
  id: string;
@@ -52,11 +59,13 @@ export declare const emailCodeVerificationRecordDataGuard: z.ZodObject<{
52
59
  };
53
60
  templateType: TemplateType;
54
61
  verified: boolean;
62
+ userId?: string | undefined;
55
63
  }>;
56
64
  export declare const phoneCodeVerificationRecordDataGuard: z.ZodObject<{
57
65
  id: z.ZodString;
58
66
  templateType: z.ZodNativeEnum<typeof TemplateType>;
59
67
  verified: z.ZodBoolean;
68
+ userId: z.ZodOptional<z.ZodString>;
60
69
  } & {
61
70
  type: z.ZodLiteral<VerificationType.PhoneVerificationCode>;
62
71
  identifier: z.ZodObject<{
@@ -78,6 +87,7 @@ export declare const phoneCodeVerificationRecordDataGuard: z.ZodObject<{
78
87
  };
79
88
  templateType: TemplateType;
80
89
  verified: boolean;
90
+ userId?: string | undefined;
81
91
  }, {
82
92
  type: VerificationType.PhoneVerificationCode;
83
93
  id: string;
@@ -87,11 +97,13 @@ export declare const phoneCodeVerificationRecordDataGuard: z.ZodObject<{
87
97
  };
88
98
  templateType: TemplateType;
89
99
  verified: boolean;
100
+ userId?: string | undefined;
90
101
  }>;
91
102
  export declare const mfaEmailCodeVerificationRecordDataGuard: z.ZodObject<{
92
103
  id: z.ZodString;
93
104
  templateType: z.ZodNativeEnum<typeof TemplateType>;
94
105
  verified: z.ZodBoolean;
106
+ userId: z.ZodOptional<z.ZodString>;
95
107
  } & {
96
108
  type: z.ZodLiteral<VerificationType.MfaEmailVerificationCode>;
97
109
  identifier: z.ZodObject<{
@@ -113,6 +125,7 @@ export declare const mfaEmailCodeVerificationRecordDataGuard: z.ZodObject<{
113
125
  };
114
126
  templateType: TemplateType;
115
127
  verified: boolean;
128
+ userId?: string | undefined;
116
129
  }, {
117
130
  type: VerificationType.MfaEmailVerificationCode;
118
131
  id: string;
@@ -122,11 +135,13 @@ export declare const mfaEmailCodeVerificationRecordDataGuard: z.ZodObject<{
122
135
  };
123
136
  templateType: TemplateType;
124
137
  verified: boolean;
138
+ userId?: string | undefined;
125
139
  }>;
126
140
  export declare const mfaPhoneCodeVerificationRecordDataGuard: z.ZodObject<{
127
141
  id: z.ZodString;
128
142
  templateType: z.ZodNativeEnum<typeof TemplateType>;
129
143
  verified: z.ZodBoolean;
144
+ userId: z.ZodOptional<z.ZodString>;
130
145
  } & {
131
146
  type: z.ZodLiteral<VerificationType.MfaPhoneVerificationCode>;
132
147
  identifier: z.ZodObject<{
@@ -148,6 +163,7 @@ export declare const mfaPhoneCodeVerificationRecordDataGuard: z.ZodObject<{
148
163
  };
149
164
  templateType: TemplateType;
150
165
  verified: boolean;
166
+ userId?: string | undefined;
151
167
  }, {
152
168
  type: VerificationType.MfaPhoneVerificationCode;
153
169
  id: string;
@@ -157,5 +173,6 @@ export declare const mfaPhoneCodeVerificationRecordDataGuard: z.ZodObject<{
157
173
  };
158
174
  templateType: TemplateType;
159
175
  verified: boolean;
176
+ userId?: string | undefined;
160
177
  }>;
161
178
  export {};
@@ -5,6 +5,7 @@ const basicCodeVerificationRecordDataGuard = z.object({
5
5
  id: z.string(),
6
6
  templateType: z.nativeEnum(TemplateType),
7
7
  verified: z.boolean(),
8
+ userId: z.string().optional(),
8
9
  });
9
10
  export const emailCodeVerificationRecordDataGuard = basicCodeVerificationRecordDataGuard.extend({
10
11
  type: z.literal(VerificationType.EmailVerificationCode),
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @overview The CIMD (OAuth Client ID Metadata Document) client identifier namespace predicate.
3
+ *
4
+ * Lives in `@logto/schemas` because both runtimes classify the same identifier: core wires the
5
+ * feature configuration and request-time matching, while the experience client recognizes a CIMD
6
+ * identifier carried over from the authorization request (e.g. to accept SSR settings rendered
7
+ * without an `appId`).
8
+ */
9
+ /**
10
+ * Whether the identifier is in the CIMD namespace. Mirrors the scheme test of the fork's
11
+ * `isValidClientIdUrl` (case-insensitive); registered application ids never take the URL shape,
12
+ * so the shape safely routes — the resolved client stays the authority on what a client is.
13
+ */
14
+ export declare const isCimdClientId: (clientId: string) => boolean;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @overview The CIMD (OAuth Client ID Metadata Document) client identifier namespace predicate.
3
+ *
4
+ * Lives in `@logto/schemas` because both runtimes classify the same identifier: core wires the
5
+ * feature configuration and request-time matching, while the experience client recognizes a CIMD
6
+ * identifier carried over from the authorization request (e.g. to accept SSR settings rendered
7
+ * without an `appId`).
8
+ */
9
+ /**
10
+ * Whether the identifier is in the CIMD namespace. Mirrors the scheme test of the fork's
11
+ * `isValidClientIdUrl` (case-insensitive); registered application ids never take the URL shape,
12
+ * so the shape safely routes — the resolved client stays the authority on what a client is.
13
+ */
14
+ export const isCimdClientId = (clientId) => /^https:\/\//iu.test(clientId);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { isCimdClientId } from './cimd.js';
3
+ describe('isCimdClientId', () => {
4
+ it('matches the fork scheme test case-insensitively and never matches registered ids', () => {
5
+ expect(isCimdClientId('https://client.example.com/metadata.json')).toBe(true);
6
+ expect(isCimdClientId('HTTPS://client.example.com/metadata.json')).toBe(true);
7
+ expect(isCimdClientId('registered_client_id')).toBe(false);
8
+ });
9
+ });
@@ -3,3 +3,4 @@ export * from './role.js';
3
3
  export * from './management-api.js';
4
4
  export * from './domain.js';
5
5
  export * from './oidc-private-key.js';
6
+ export * from './cimd.js';
@@ -3,3 +3,4 @@ export * from './role.js';
3
3
  export * from './management-api.js';
4
4
  export * from './domain.js';
5
5
  export * from './oidc-private-key.js';
6
+ export * from './cimd.js';
@@ -14,6 +14,17 @@ describe('OIDC private key helpers', () => {
14
14
  createPrivateKey('previous', 2, OidcSigningKeyStatus.Previous),
15
15
  ]);
16
16
  });
17
+ it('preserves explicit statuses without reordering the input array', () => {
18
+ expect(normalizeOidcPrivateKeys([
19
+ createPrivateKey('previous', 3, OidcSigningKeyStatus.Previous),
20
+ createPrivateKey('current', 2, OidcSigningKeyStatus.Current),
21
+ createPrivateKey('next', 1, OidcSigningKeyStatus.Next),
22
+ ])).toEqual([
23
+ createPrivateKey('previous', 3, OidcSigningKeyStatus.Previous),
24
+ createPrivateKey('current', 2, OidcSigningKeyStatus.Current),
25
+ createPrivateKey('next', 1, OidcSigningKeyStatus.Next),
26
+ ]);
27
+ });
17
28
  it('throws for malformed status configurations', () => {
18
29
  expect(() => normalizeOidcPrivateKeys([
19
30
  createPrivateKey('current-a', 1, OidcSigningKeyStatus.Current),
@@ -81,6 +92,17 @@ describe('OIDC private key helpers', () => {
81
92
  createPrivateKey('previous', 1, OidcSigningKeyStatus.Previous),
82
93
  ]);
83
94
  });
95
+ it('replaces any existing Next key instead of accumulating a fourth private key', () => {
96
+ expect(getStagedRotatedOidcPrivateKeys([
97
+ createPrivateKey('next', 4, OidcSigningKeyStatus.Next),
98
+ createPrivateKey('current', 3, OidcSigningKeyStatus.Current),
99
+ createPrivateKey('previous', 2, OidcSigningKeyStatus.Previous),
100
+ ], createPrivateKey('replacement', 5))).toEqual([
101
+ createPrivateKey('replacement', 5, OidcSigningKeyStatus.Next),
102
+ createPrivateKey('current', 3, OidcSigningKeyStatus.Current),
103
+ createPrivateKey('previous', 2, OidcSigningKeyStatus.Previous),
104
+ ]);
105
+ });
84
106
  it('promotes Next to Current during activation', () => {
85
107
  expect(rotateOidcPrivateKeyStatuses([
86
108
  createPrivateKey('next', 3, OidcSigningKeyStatus.Next),
@@ -91,6 +113,28 @@ describe('OIDC private key helpers', () => {
91
113
  createPrivateKey('current', 2, OidcSigningKeyStatus.Previous),
92
114
  ]);
93
115
  });
116
+ it('returns the original keys when explicit-status keys have no staged Next key', () => {
117
+ const privateKeys = [
118
+ createPrivateKey('current', 2, OidcSigningKeyStatus.Current),
119
+ createPrivateKey('previous', 1, OidcSigningKeyStatus.Previous),
120
+ ];
121
+ expect(rotateOidcPrivateKeyStatuses(privateKeys)).toBe(privateKeys);
122
+ });
123
+ it('returns normalized keys when legacy keys have no staged Next key', () => {
124
+ const privateKeys = [createPrivateKey('current', 2), createPrivateKey('previous', 1)];
125
+ const result = rotateOidcPrivateKeyStatuses(privateKeys);
126
+ expect(result).not.toBe(privateKeys);
127
+ expect(result).toEqual([
128
+ createPrivateKey('current', 2, OidcSigningKeyStatus.Current),
129
+ createPrivateKey('previous', 1, OidcSigningKeyStatus.Previous),
130
+ ]);
131
+ });
132
+ it('keeps only Current when deleting Previous from a two-key set', () => {
133
+ expect(getOidcPrivateKeysAfterDeletion([
134
+ createPrivateKey('current', 2, OidcSigningKeyStatus.Current),
135
+ createPrivateKey('previous', 1, OidcSigningKeyStatus.Previous),
136
+ ], 'previous')).toEqual([createPrivateKey('current', 2, OidcSigningKeyStatus.Current)]);
137
+ });
94
138
  it('preserves status order when deleting Previous', () => {
95
139
  expect(getOidcPrivateKeysAfterDeletion([
96
140
  createPrivateKey('next', 3, OidcSigningKeyStatus.Next),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logto/schemas",
3
- "version": "1.42.0",
3
+ "version": "1.44.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": "^4.1.8",
34
+ "@vitest/coverage-v8": "^4.1.11",
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": "^4.1.8"
43
+ "vitest": "^4.1.11"
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.1.0",
69
- "@logto/language-kit": "^1.3.0",
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"
68
+ "@logto/connector-kit": "^5.1.2",
69
+ "@logto/phrases": "^1.32.0",
70
+ "@logto/language-kit": "^1.4.0",
71
+ "@logto/phrases-experience": "^1.15.0",
72
+ "@logto/shared": "^3.4.3",
73
+ "@logto/core-kit": "^2.13.0"
74
74
  },
75
75
  "peerDependencies": {
76
76
  "zod": "3.24.3"
@@ -2,7 +2,7 @@
2
2
  create table aggregated_daily_active_users (
3
3
  tenant_id varchar(21) not null,
4
4
  activity_date date not null,
5
- user_id varchar(21) not null,
5
+ user_id varchar(128) not null,
6
6
  activity_count integer not null,
7
7
  primary key (tenant_id, activity_date, user_id)
8
8
  );
@@ -6,7 +6,7 @@ create table application_access_control_user_relations (
6
6
  references tenants (id) on update cascade on delete cascade,
7
7
  application_id varchar(21) not null
8
8
  references applications (id) on update cascade on delete cascade,
9
- user_id varchar(21) not null
9
+ user_id varchar(128) not null
10
10
  references users (id) on update cascade on delete cascade,
11
11
  primary key (tenant_id, application_id, user_id)
12
12
  );
@@ -7,7 +7,7 @@ create table application_user_consent_organizations (
7
7
  application_id varchar(21) not null
8
8
  references applications (id) on update cascade on delete cascade,
9
9
  organization_id varchar(21) not null,
10
- user_id varchar(21) not null,
10
+ user_id varchar(128) not null,
11
11
  primary key (tenant_id, application_id, organization_id, user_id),
12
12
  /** User's consent to an application should be synchronized with the user's membership in the organization. */
13
13
  foreign key (tenant_id, organization_id, user_id)
@@ -0,0 +1,27 @@
1
+ /* init_order = 2 */
2
+
3
+ /**
4
+ The client identity a user approved at consent time for a client ID metadata document (CIMD)
5
+ client, captured per Grant. CIMD clients are unregistered URL identities without an
6
+ `applications` row, and an unvetted client can rewrite its hosted document at any time — so the
7
+ grant list renders this snapshot instead of refetching the document.
8
+ */
9
+ create table cimd_grant_client_snapshots (
10
+ tenant_id varchar(21) not null
11
+ references tenants (id) on update cascade on delete cascade,
12
+ /** The ID of the Grant row in `oidc_model_instances`. */
13
+ grant_id varchar(128) not null,
14
+ /** Fixed discriminator so the composite foreign key can target Grant rows in the polymorphic `oidc_model_instances` table. */
15
+ grant_model_name varchar(64) not null default 'Grant',
16
+ client_id varchar(2048) not null,
17
+ name varchar(256),
18
+ logo_uri varchar(2048),
19
+ created_at timestamptz not null default(now()),
20
+ primary key (tenant_id, grant_id),
21
+ constraint cimd_grant_client_snapshots__grant_model_name
22
+ check (grant_model_name = 'Grant'),
23
+ /** Revoking the grant hard-deletes the Grant row, which erases the snapshot with it. */
24
+ foreign key (tenant_id, grant_model_name, grant_id)
25
+ references oidc_model_instances (tenant_id, model_name, id)
26
+ on update cascade on delete cascade
27
+ );
@@ -0,0 +1,38 @@
1
+ /* init_order = 3 */
2
+
3
+ /**
4
+ The organization authorized on a single OIDC Grant for a client ID metadata document (CIMD) client.
5
+ CIMD clients are unregistered URL identities with no deletion lifecycle and transferable ownership,
6
+ so organization access follows the single authorization instead of a long-lived cross-grant
7
+ relation: rows cascade away with the Grant row and with the user's organization membership.
8
+ */
9
+ create table cimd_grant_organizations (
10
+ tenant_id varchar(21) not null
11
+ references tenants (id) on update cascade on delete cascade,
12
+ /** The ID of the Grant row in `oidc_model_instances`. */
13
+ grant_id varchar(128) not null,
14
+ /** Fixed discriminator so the composite foreign key can target Grant rows in the polymorphic `oidc_model_instances` table. */
15
+ grant_model_name varchar(64) not null default 'Grant',
16
+ organization_id varchar(21) not null,
17
+ /** The user the grant was issued to and the membership FK's target. Must match the Grant payload's `accountId` (unreachable by FK) — the consent write enforces the pairing. */
18
+ user_id varchar(128) not null,
19
+ primary key (tenant_id, grant_id),
20
+ constraint cimd_grant_organizations__grant_model_name
21
+ check (grant_model_name = 'Grant'),
22
+ /** Revoking the grant hard-deletes the Grant row, which erases the organization authorization with it. */
23
+ foreign key (tenant_id, grant_model_name, grant_id)
24
+ references oidc_model_instances (tenant_id, model_name, id)
25
+ on update cascade on delete cascade,
26
+ /** Leaving the organization revokes the authorization. */
27
+ foreign key (tenant_id, organization_id, user_id)
28
+ references organization_user_relations (tenant_id, organization_id, user_id)
29
+ on update cascade on delete cascade
30
+ );
31
+
32
+ /**
33
+ Backs the membership FK's cascade lookup: rows live as long as the Grant row (not the grant's
34
+ validity), so membership deletions would otherwise scan the tenant's whole row set per deleted
35
+ membership, amplified by member count on organization deletion.
36
+ */
37
+ create index cimd_grant_organizations__organization_id_user_id
38
+ on cimd_grant_organizations (tenant_id, organization_id, user_id);
@@ -0,0 +1,16 @@
1
+ /* init_order = 3 */
2
+
3
+ /**
4
+ The organization API resource scopes (permissions) that client ID metadata document (CIMD) clients of
5
+ the tenant can request. The scopes are granted to users through organization roles.
6
+ Rows are an allowlist: an empty table allows nothing (deny-all), and an unrestricted state is not expressible.
7
+ */
8
+ create table cimd_organization_resource_scopes (
9
+ tenant_id varchar(21) not null
10
+ references tenants (id) on update cascade on delete cascade,
11
+ /** The globally unique identifier of the API resource scope. */
12
+ scope_id varchar(21) not null,
13
+ primary key (tenant_id, scope_id),
14
+ foreign key (tenant_id, scope_id)
15
+ references scopes (tenant_id, id) on update cascade on delete cascade
16
+ );
@@ -0,0 +1,15 @@
1
+ /* init_order = 2 */
2
+
3
+ /**
4
+ The organization scopes (permissions) that client ID metadata document (CIMD) clients of the tenant can request.
5
+ Rows are an allowlist: an empty table allows nothing (deny-all), and an unrestricted state is not expressible.
6
+ */
7
+ create table cimd_organization_scopes (
8
+ tenant_id varchar(21) not null
9
+ references tenants (id) on update cascade on delete cascade,
10
+ /** The globally unique identifier of the organization scope. */
11
+ organization_scope_id varchar(21) not null,
12
+ primary key (tenant_id, organization_scope_id),
13
+ foreign key (tenant_id, organization_scope_id)
14
+ references organization_scopes (tenant_id, id) on update cascade on delete cascade
15
+ );
@@ -0,0 +1,15 @@
1
+ /* init_order = 3 */
2
+
3
+ /**
4
+ The API resource scopes (permissions) that client ID metadata document (CIMD) clients of the tenant can request.
5
+ Rows are an allowlist: an empty table allows nothing (deny-all), and an unrestricted state is not expressible.
6
+ */
7
+ create table cimd_resource_scopes (
8
+ tenant_id varchar(21) not null
9
+ references tenants (id) on update cascade on delete cascade,
10
+ /** The globally unique identifier of the API resource scope. */
11
+ scope_id varchar(21) not null,
12
+ primary key (tenant_id, scope_id),
13
+ foreign key (tenant_id, scope_id)
14
+ references scopes (tenant_id, id) on update cascade on delete cascade
15
+ );
@@ -0,0 +1,13 @@
1
+ /* init_order = 2 */
2
+
3
+ /**
4
+ The user scopes (permissions) that client ID metadata document (CIMD) clients of the tenant can request.
5
+ Rows are an allowlist: an empty table allows nothing (deny-all), and an unrestricted state is not expressible.
6
+ */
7
+ create table cimd_user_scopes (
8
+ tenant_id varchar(21) not null
9
+ references tenants (id) on update cascade on delete cascade,
10
+ /** The unique UserScope enum value @see (@logto/core-kit/open-id.js) for more details */
11
+ user_scope varchar(64) not null,
12
+ primary key (tenant_id, user_scope)
13
+ );
@@ -1,7 +1,7 @@
1
1
  create table daily_active_users (
2
2
  id varchar(21) not null,
3
3
  tenant_id varchar(21) not null,
4
- user_id varchar(21) not null,
4
+ user_id varchar(128) not null,
5
5
  date timestamptz not null default (now()),
6
6
  primary key (id),
7
7
  constraint daily_active_users__user_id_date
@@ -42,6 +42,11 @@ create index oidc_model_instances__grant_payload_account_id_expires_at
42
42
  on oidc_model_instances (tenant_id, (payload->>'accountId'), expires_at)
43
43
  WHERE model_name = 'Grant';
44
44
 
45
+ /* Partial on payload key existence so rows without accountId (e.g. client credentials tokens) stay out of the index. The parameter-free predicate stays provable under generic query plans, but matching queries must include the payload ? 'accountId' clause. */
46
+ create index oidc_model_instances__model_name_payload_account_id_partial
47
+ on oidc_model_instances (tenant_id, model_name, (payload->>'accountId'))
48
+ where payload ? 'accountId';
49
+
45
50
  alter table oidc_model_instances set (
46
51
  autovacuum_vacuum_scale_factor = 0.05,
47
52
  autovacuum_analyze_scale_factor = 0.02,
@@ -4,15 +4,20 @@ create table oidc_session_extensions (
4
4
  tenant_id varchar(21) not null
5
5
  references tenants (id) on update cascade on delete cascade,
6
6
  session_uid varchar(128) not null,
7
- account_id varchar(12) not null
7
+ account_id varchar(128) not null
8
8
  references users (id) on update cascade on delete cascade,
9
9
  last_submission jsonb /* @use JsonObject */ not null default '{}'::jsonb,
10
10
  client_id varchar(21) null,
11
+ cimd_client_id varchar(2048) null,
11
12
  created_at timestamptz not null default(now()),
12
13
  updated_at timestamptz not null default(now()),
13
14
  primary key (tenant_id, session_uid)
14
15
  );
15
16
 
17
+ /* Leads with account_id instead of tenant_id so the cascades from the users table can use it (users.id is globally unique, so a tenant_id prefix adds no selectivity). */
18
+ create index oidc_session_extensions__account_id
19
+ on oidc_session_extensions (account_id);
20
+
16
21
  create trigger set_updated_at
17
22
  before update on oidc_session_extensions
18
23
  for each row
@@ -9,12 +9,12 @@ create table organization_invitations (
9
9
  /** The unique identifier of the invitation. */
10
10
  id varchar(21) not null,
11
11
  /** The user ID who sent the invitation. */
12
- inviter_id varchar(21)
12
+ inviter_id varchar(128)
13
13
  references users (id) on update cascade on delete cascade,
14
14
  /** The email address or other identifier of the invitee. */
15
15
  invitee varchar(256) not null,
16
16
  /** The user ID of who accepted the invitation. */
17
- accepted_user_id varchar(21)
17
+ accepted_user_id varchar(128)
18
18
  references users (id) on update cascade on delete cascade,
19
19
  /** The ID of the organization to which the invitee is invited. */
20
20
  organization_id varchar(21) not null
@@ -7,7 +7,7 @@ create table organization_role_user_relations (
7
7
  organization_id varchar(21) not null,
8
8
  organization_role_id varchar(21) not null
9
9
  references organization_roles (id) on update cascade on delete cascade,
10
- user_id varchar(21) not null,
10
+ user_id varchar(128) not null,
11
11
  primary key (tenant_id, organization_id, organization_role_id, user_id),
12
12
  /** User's roles in an organization should be synchronized with the user's membership in the organization. */
13
13
  foreign key (tenant_id, organization_id, user_id)
@@ -17,3 +17,7 @@ create table organization_scopes (
17
17
 
18
18
  create index organization_scopes__id
19
19
  on organization_scopes (tenant_id, id);
20
+
21
+ /** Supports tenant-aware foreign keys from tenant-owned organization scope relations. */
22
+ create unique index organization_scopes__tenant_id_id
23
+ on organization_scopes (tenant_id, id);
@@ -6,7 +6,7 @@ create table organization_user_relations (
6
6
  references tenants (id) on update cascade on delete cascade,
7
7
  organization_id varchar(21) not null
8
8
  references organizations (id) on update cascade on delete cascade,
9
- user_id varchar(21) not null
9
+ user_id varchar(128) not null
10
10
  references users (id) on update cascade on delete cascade,
11
11
  primary key (tenant_id, organization_id, user_id),
12
12
  constraint organization_user_relations__user_id__fk