@logto/schemas 1.38.0 → 1.40.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 (94) hide show
  1. package/alterations/1.39.0-1774752400-add-delete-account-url.ts +20 -0
  2. package/alterations/1.39.0-1774770686-add-account-center-custom-css.ts +20 -0
  3. package/alterations/1.39.0-1776502301-add-sign-up-profile-fields.ts +20 -0
  4. package/alterations/1.40.0-1776516232-add-account-center-profile-fields.ts +20 -0
  5. package/alterations/1.40.0-1778318116-add-custom-ui-csp-to-sie.ts +20 -0
  6. package/alterations/1.40.0-1778500000-add-organization-user-relations-user-id-index.ts +41 -0
  7. package/alterations/1.40.0-1778500001-add-organization-role-user-relations-org-user-index.ts +43 -0
  8. package/alterations/1.40.0-1779421396-add-application-access-control-schema.ts +90 -0
  9. package/alterations-js/1.39.0-1774752400-add-delete-account-url.js +16 -0
  10. package/alterations-js/1.39.0-1774770686-add-account-center-custom-css.js +16 -0
  11. package/alterations-js/1.39.0-1776502301-add-sign-up-profile-fields.js +16 -0
  12. package/alterations-js/1.40.0-1776516232-add-account-center-profile-fields.js +16 -0
  13. package/alterations-js/1.40.0-1778318116-add-custom-ui-csp-to-sie.js +16 -0
  14. package/alterations-js/1.40.0-1778500000-add-organization-user-relations-user-id-index.js +37 -0
  15. package/alterations-js/1.40.0-1778500001-add-organization-role-user-relations-org-user-index.js +39 -0
  16. package/alterations-js/1.40.0-1779421396-add-application-access-control-schema.js +82 -0
  17. package/lib/consts/application.d.ts +1 -0
  18. package/lib/consts/application.js +1 -0
  19. package/lib/consts/index.d.ts +1 -0
  20. package/lib/consts/index.js +1 -0
  21. package/lib/db-entries/account-center.d.ts +14 -2
  22. package/lib/db-entries/account-center.js +13 -1
  23. package/lib/db-entries/application-access-control-org-role-relation.d.ts +22 -0
  24. package/lib/db-entries/application-access-control-org-role-relation.js +33 -0
  25. package/lib/db-entries/application-access-control-organization-relation.d.ts +20 -0
  26. package/lib/db-entries/application-access-control-organization-relation.js +29 -0
  27. package/lib/db-entries/application-access-control-user-relation.d.ts +20 -0
  28. package/lib/db-entries/application-access-control-user-relation.js +29 -0
  29. package/lib/db-entries/application-access-control-user-role-relation.d.ts +20 -0
  30. package/lib/db-entries/application-access-control-user-role-relation.js +29 -0
  31. package/lib/db-entries/application.d.ts +3 -1
  32. package/lib/db-entries/application.js +4 -0
  33. package/lib/db-entries/index.d.ts +4 -0
  34. package/lib/db-entries/index.js +4 -0
  35. package/lib/db-entries/sign-in-experience.d.ts +8 -2
  36. package/lib/db-entries/sign-in-experience.js +9 -1
  37. package/lib/foundations/jsonb-types/account-centers.d.ts +27 -0
  38. package/lib/foundations/jsonb-types/account-centers.js +12 -0
  39. package/lib/foundations/jsonb-types/applications.d.ts +3 -0
  40. package/lib/foundations/jsonb-types/applications.js +4 -0
  41. package/lib/foundations/jsonb-types/applications.test.d.ts +1 -0
  42. package/lib/foundations/jsonb-types/applications.test.js +23 -0
  43. package/lib/foundations/jsonb-types/sign-in-experience.d.ts +27 -1
  44. package/lib/foundations/jsonb-types/sign-in-experience.js +5 -0
  45. package/lib/foundations/jsonb-types/sign-in-experience.test.d.ts +1 -0
  46. package/lib/foundations/jsonb-types/sign-in-experience.test.js +18 -0
  47. package/lib/seeds/application.js +2 -0
  48. package/lib/seeds/sign-in-experience.d.ts +13 -1
  49. package/lib/seeds/sign-in-experience.js +10 -1
  50. package/lib/seeds/sign-in-experience.test.d.ts +1 -0
  51. package/lib/seeds/sign-in-experience.test.js +27 -0
  52. package/lib/types/alteration.d.ts +5 -0
  53. package/lib/types/application.d.ts +101 -2
  54. package/lib/types/application.js +55 -0
  55. package/lib/types/application.test.d.ts +1 -0
  56. package/lib/types/application.test.js +120 -0
  57. package/lib/types/consent.d.ts +6 -0
  58. package/lib/types/custom-profile-fields.d.ts +7 -13
  59. package/lib/types/custom-profile-fields.js +6 -13
  60. package/lib/types/logto-config/index.d.ts +93 -2
  61. package/lib/types/logto-config/index.js +22 -4
  62. package/lib/types/logto-config/index.test.d.ts +1 -0
  63. package/lib/types/logto-config/index.test.js +29 -0
  64. package/lib/types/logto-config/jwt-customizer.d.ts +74 -0
  65. package/lib/types/logto-config/jwt-customizer.js +1 -0
  66. package/lib/types/logto-config/jwt-customizer.test.js +14 -2
  67. package/lib/types/onboarding.d.ts +93 -1
  68. package/lib/types/onboarding.js +22 -1
  69. package/lib/types/saml-application.d.ts +3 -0
  70. package/lib/types/sign-in-experience.d.ts +23 -2
  71. package/lib/types/sign-in-experience.js +1 -0
  72. package/lib/types/system.d.ts +46 -7
  73. package/lib/types/system.js +9 -0
  74. package/lib/types/user-assets.d.ts +1 -1
  75. package/lib/types/user-logto-config.d.ts +11 -0
  76. package/lib/types/user-logto-config.js +6 -0
  77. package/lib/types/user-sessions.d.ts +2516 -0
  78. package/lib/types/user-sessions.js +21 -0
  79. package/lib/utils/index.d.ts +1 -0
  80. package/lib/utils/index.js +1 -0
  81. package/lib/utils/oidc-private-key.d.ts +88 -0
  82. package/lib/utils/oidc-private-key.js +163 -0
  83. package/lib/utils/oidc-private-key.test.d.ts +1 -0
  84. package/lib/utils/oidc-private-key.test.js +128 -0
  85. package/package.json +6 -6
  86. package/tables/account_centers.sql +6 -0
  87. package/tables/application_access_control_org_role_relations.sql +16 -0
  88. package/tables/application_access_control_organization_relations.sql +12 -0
  89. package/tables/application_access_control_user_relations.sql +12 -0
  90. package/tables/application_access_control_user_role_relations.sql +14 -0
  91. package/tables/applications.sql +1 -0
  92. package/tables/organization_role_user_relations.sql +3 -0
  93. package/tables/organization_user_relations.sql +3 -0
  94. package/tables/sign_in_experiences.sql +3 -0
@@ -0,0 +1,27 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createAdminTenantSignInExperience, createDefaultSignInExperience, } from './sign-in-experience.js';
3
+ import { adminTenantId } from './tenant.js';
4
+ describe('createAdminTenantSignInExperience', () => {
5
+ it('seeds an empty passwordPolicy by default', () => {
6
+ const row = createAdminTenantSignInExperience();
7
+ expect(row.passwordPolicy).toEqual({});
8
+ });
9
+ it('seeds an empty passwordPolicy when option is explicitly false', () => {
10
+ const row = createAdminTenantSignInExperience({ disablePwnedPasswordCheck: false });
11
+ expect(row.passwordPolicy).toEqual({});
12
+ });
13
+ it('seeds rejects.pwned=false when disablePwnedPasswordCheck is true', () => {
14
+ const row = createAdminTenantSignInExperience({ disablePwnedPasswordCheck: true });
15
+ expect(row.passwordPolicy).toEqual({ rejects: { pwned: false } });
16
+ });
17
+ it('still targets the admin tenant id when the option is set', () => {
18
+ const row = createAdminTenantSignInExperience({ disablePwnedPasswordCheck: true });
19
+ expect(row.tenantId).toBe(adminTenantId);
20
+ });
21
+ });
22
+ describe('createDefaultSignInExperience (unchanged contract)', () => {
23
+ it('still has a two-parameter signature and seeds an empty passwordPolicy', () => {
24
+ const row = createDefaultSignInExperience('some-tenant-id', false);
25
+ expect(row.passwordPolicy).toEqual({});
26
+ });
27
+ });
@@ -1,4 +1,9 @@
1
1
  import type { CommonQueryMethods, DatabaseTransactionConnection } from '@silverhand/slonik';
2
+ /**
3
+ * IMPORTANT: Logto Cloud has a parallel `AlterationScript` type in `@logto/cloud-alterations`
4
+ * (logto-cloud repo: `packages/cloud-alterations/src/types.ts`).
5
+ * Any changes to this type must be synchronized with the Cloud type definition.
6
+ */
2
7
  export type AlterationScript = {
3
8
  /**
4
9
  * Optional hook that runs before `up` outside of a transaction.
@@ -48,6 +48,7 @@ export declare const featuredApplicationGuard: z.ZodObject<Pick<{
48
48
  pageRules: {
49
49
  path: string;
50
50
  }[];
51
+ additionalScopes?: (UserScope.CustomData | UserScope.Identities | UserScope.Roles | UserScope.Organizations | UserScope.OrganizationRoles)[] | undefined;
51
52
  customDomains?: {
52
53
  status: import("../index.js").DomainStatus;
53
54
  domain: string;
@@ -76,6 +77,7 @@ export declare const featuredApplicationGuard: z.ZodObject<Pick<{
76
77
  pageRules: {
77
78
  path: string;
78
79
  }[];
80
+ additionalScopes?: (UserScope.CustomData | UserScope.Identities | UserScope.Roles | UserScope.Organizations | UserScope.OrganizationRoles)[] | undefined;
79
81
  customDomains?: {
80
82
  status: import("../index.js").DomainStatus;
81
83
  domain: string;
@@ -100,6 +102,7 @@ export declare const featuredApplicationGuard: z.ZodObject<Pick<{
100
102
  } | null>;
101
103
  customData: z.ZodType<import("@withtyped/server").JsonObject, z.ZodTypeDef, import("@withtyped/server").JsonObject>;
102
104
  isThirdParty: z.ZodType<boolean, z.ZodTypeDef, boolean>;
105
+ appLevelAccessControlEnabled: z.ZodType<boolean, z.ZodTypeDef, boolean>;
103
106
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
104
107
  }, "type" | "name" | "id">, "strip", z.ZodTypeAny, {
105
108
  type: import("../db-entries/custom-types.js").ApplicationType;
@@ -144,6 +147,7 @@ export declare const applicationCreateGuard: z.ZodObject<{
144
147
  pageRules: {
145
148
  path: string;
146
149
  }[];
150
+ additionalScopes?: (UserScope.CustomData | UserScope.Identities | UserScope.Roles | UserScope.Organizations | UserScope.OrganizationRoles)[] | undefined;
147
151
  customDomains?: {
148
152
  status: import("../index.js").DomainStatus;
149
153
  domain: string;
@@ -172,6 +176,7 @@ export declare const applicationCreateGuard: z.ZodObject<{
172
176
  pageRules: {
173
177
  path: string;
174
178
  }[];
179
+ additionalScopes?: (UserScope.CustomData | UserScope.Identities | UserScope.Roles | UserScope.Organizations | UserScope.OrganizationRoles)[] | undefined;
175
180
  customDomains?: {
176
181
  status: import("../index.js").DomainStatus;
177
182
  domain: string;
@@ -251,6 +256,7 @@ export declare const applicationPatchGuard: z.ZodObject<Omit<{
251
256
  pageRules: {
252
257
  path: string;
253
258
  }[];
259
+ additionalScopes?: (UserScope.CustomData | UserScope.Identities | UserScope.Roles | UserScope.Organizations | UserScope.OrganizationRoles)[] | undefined;
254
260
  customDomains?: {
255
261
  status: import("../index.js").DomainStatus;
256
262
  domain: string;
@@ -279,6 +285,7 @@ export declare const applicationPatchGuard: z.ZodObject<Omit<{
279
285
  pageRules: {
280
286
  path: string;
281
287
  }[];
288
+ additionalScopes?: (UserScope.CustomData | UserScope.Identities | UserScope.Roles | UserScope.Organizations | UserScope.OrganizationRoles)[] | undefined;
282
289
  customDomains?: {
283
290
  status: import("../index.js").DomainStatus;
284
291
  domain: string;
@@ -319,6 +326,98 @@ export declare const applicationPatchGuard: z.ZodObject<Omit<{
319
326
  customClientMetadata?: import("../index.js").CustomClientMetadata;
320
327
  protectedAppMetadata?: import("../index.js").ProtectedAppMetadata | null;
321
328
  }>;
329
+ /** The guard for one organization role access-control rule group. */
330
+ export declare const applicationAccessControlOrganizationRoleRuleGuard: z.ZodObject<{
331
+ organizationId: z.ZodString;
332
+ organizationRoleIds: z.ZodPipeline<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>, z.ZodArray<z.ZodString, "many">>;
333
+ }, "strip", z.ZodTypeAny, {
334
+ organizationId: string;
335
+ organizationRoleIds: string[];
336
+ }, {
337
+ organizationId: string;
338
+ organizationRoleIds: string[];
339
+ }>;
340
+ /** The guard for application-level access control rule payloads. */
341
+ export declare const applicationAccessControlGuard: z.ZodPipeline<z.ZodEffects<z.ZodObject<{
342
+ userIds: z.ZodPipeline<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>, z.ZodArray<z.ZodString, "many">>;
343
+ userRoleIds: z.ZodPipeline<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>, z.ZodArray<z.ZodString, "many">>;
344
+ organizationIds: z.ZodPipeline<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>, z.ZodArray<z.ZodString, "many">>;
345
+ organizationRoleRules: z.ZodArray<z.ZodObject<{
346
+ organizationId: z.ZodString;
347
+ organizationRoleIds: z.ZodPipeline<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>, z.ZodArray<z.ZodString, "many">>;
348
+ }, "strip", z.ZodTypeAny, {
349
+ organizationId: string;
350
+ organizationRoleIds: string[];
351
+ }, {
352
+ organizationId: string;
353
+ organizationRoleIds: string[];
354
+ }>, "many">;
355
+ }, "strip", z.ZodTypeAny, {
356
+ userIds: string[];
357
+ userRoleIds: string[];
358
+ organizationIds: string[];
359
+ organizationRoleRules: {
360
+ organizationId: string;
361
+ organizationRoleIds: string[];
362
+ }[];
363
+ }, {
364
+ userIds: string[];
365
+ userRoleIds: string[];
366
+ organizationIds: string[];
367
+ organizationRoleRules: {
368
+ organizationId: string;
369
+ organizationRoleIds: string[];
370
+ }[];
371
+ }>, {
372
+ organizationRoleRules: {
373
+ organizationId: string;
374
+ organizationRoleIds: string[];
375
+ }[];
376
+ userIds: string[];
377
+ userRoleIds: string[];
378
+ organizationIds: string[];
379
+ }, {
380
+ userIds: string[];
381
+ userRoleIds: string[];
382
+ organizationIds: string[];
383
+ organizationRoleRules: {
384
+ organizationId: string;
385
+ organizationRoleIds: string[];
386
+ }[];
387
+ }>, z.ZodObject<{
388
+ userIds: z.ZodArray<z.ZodString, "many">;
389
+ userRoleIds: z.ZodArray<z.ZodString, "many">;
390
+ organizationIds: z.ZodArray<z.ZodString, "many">;
391
+ organizationRoleRules: z.ZodArray<z.ZodObject<{
392
+ organizationId: z.ZodString;
393
+ organizationRoleIds: z.ZodPipeline<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>, z.ZodArray<z.ZodString, "many">>;
394
+ }, "strip", z.ZodTypeAny, {
395
+ organizationId: string;
396
+ organizationRoleIds: string[];
397
+ }, {
398
+ organizationId: string;
399
+ organizationRoleIds: string[];
400
+ }>, "many">;
401
+ }, "strip", z.ZodTypeAny, {
402
+ userIds: string[];
403
+ userRoleIds: string[];
404
+ organizationIds: string[];
405
+ organizationRoleRules: {
406
+ organizationId: string;
407
+ organizationRoleIds: string[];
408
+ }[];
409
+ }, {
410
+ userIds: string[];
411
+ userRoleIds: string[];
412
+ organizationIds: string[];
413
+ organizationRoleRules: {
414
+ organizationId: string;
415
+ organizationRoleIds: string[];
416
+ }[];
417
+ }>>;
418
+ export type ApplicationAccessControl = z.infer<typeof applicationAccessControlGuard>;
419
+ /** Create an empty application-level access control rule set. */
420
+ export declare const createDefaultApplicationAccessControl: () => ApplicationAccessControl;
322
421
  export declare const applicationUserConsentScopesResponseGuard: z.ZodObject<{
323
422
  organizationScopes: z.ZodArray<z.ZodObject<Pick<{
324
423
  tenantId: z.ZodType<string, z.ZodTypeDef, string>;
@@ -549,16 +648,16 @@ export declare const applicationSignInExperienceCreateGuard: z.ZodObject<Omit<{
549
648
  privacyPolicyUrl: z.ZodUnion<[z.ZodNullable<z.ZodOptional<z.ZodString>>, z.ZodLiteral<"">]>;
550
649
  }, "strip", z.ZodTypeAny, {
551
650
  displayName?: string | null;
651
+ customCss?: string | null;
552
652
  color?: import("../index.js").PartialColor;
553
653
  branding?: import("../index.js").Branding;
554
- customCss?: string | null;
555
654
  termsOfUseUrl?: string | null | undefined;
556
655
  privacyPolicyUrl?: string | null | undefined;
557
656
  }, {
558
657
  displayName?: string | null;
658
+ customCss?: string | null;
559
659
  color?: import("../index.js").PartialColor;
560
660
  branding?: import("../index.js").Branding;
561
- customCss?: string | null;
562
661
  termsOfUseUrl?: string | null | undefined;
563
662
  privacyPolicyUrl?: string | null | undefined;
564
663
  }>;
@@ -9,6 +9,7 @@ export const featuredApplicationGuard = Applications.guard.pick({
9
9
  });
10
10
  export const applicationCreateGuard = Applications.createGuard
11
11
  .omit({
12
+ appLevelAccessControlEnabled: true,
12
13
  id: true,
13
14
  createdAt: true,
14
15
  secret: true,
@@ -20,6 +21,60 @@ export const applicationPatchGuard = applicationCreateGuard.partial().omit({
20
21
  type: true,
21
22
  isThirdParty: true,
22
23
  });
24
+ const applicationAccessControlRuleLimit = 1000;
25
+ const applicationAccessControlRawRuleLimit = applicationAccessControlRuleLimit * 2;
26
+ const uniqueStringArrayGuard = z
27
+ .array(z.string())
28
+ .max(applicationAccessControlRawRuleLimit)
29
+ .transform((values) => [...new Set(values)])
30
+ .pipe(z.array(z.string()).max(applicationAccessControlRuleLimit));
31
+ /** The guard for one organization role access-control rule group. */
32
+ export const applicationAccessControlOrganizationRoleRuleGuard = z.object({
33
+ organizationId: z.string(),
34
+ organizationRoleIds: uniqueStringArrayGuard,
35
+ });
36
+ /** The guard for application-level access control rule payloads. */
37
+ export const applicationAccessControlGuard = z
38
+ .object({
39
+ userIds: uniqueStringArrayGuard,
40
+ userRoleIds: uniqueStringArrayGuard,
41
+ organizationIds: uniqueStringArrayGuard,
42
+ organizationRoleRules: z
43
+ .array(applicationAccessControlOrganizationRoleRuleGuard)
44
+ .max(applicationAccessControlRawRuleLimit),
45
+ })
46
+ .transform(({ organizationRoleRules, ...rest }) => {
47
+ const organizationRoleRulesMap = new Map();
48
+ for (const { organizationId, organizationRoleIds } of organizationRoleRules) {
49
+ const roleIds = organizationRoleRulesMap.get(organizationId) ?? new Set();
50
+ for (const roleId of organizationRoleIds) {
51
+ roleIds.add(roleId);
52
+ }
53
+ organizationRoleRulesMap.set(organizationId, roleIds);
54
+ }
55
+ return {
56
+ ...rest,
57
+ organizationRoleRules: [...organizationRoleRulesMap.entries()].map(([organizationId, organizationRoleIds]) => ({
58
+ organizationId,
59
+ organizationRoleIds: [...organizationRoleIds],
60
+ })),
61
+ };
62
+ })
63
+ .pipe(z.object({
64
+ userIds: z.array(z.string()).max(applicationAccessControlRuleLimit),
65
+ userRoleIds: z.array(z.string()).max(applicationAccessControlRuleLimit),
66
+ organizationIds: z.array(z.string()).max(applicationAccessControlRuleLimit),
67
+ organizationRoleRules: z
68
+ .array(applicationAccessControlOrganizationRoleRuleGuard)
69
+ .max(applicationAccessControlRuleLimit),
70
+ }));
71
+ /** Create an empty application-level access control rule set. */
72
+ export const createDefaultApplicationAccessControl = () => ({
73
+ userIds: [],
74
+ userRoleIds: [],
75
+ organizationIds: [],
76
+ organizationRoleRules: [],
77
+ });
23
78
  const resourceScopesGuard = z.array(z.object({
24
79
  resource: Resources.guard.pick({ id: true, name: true, indicator: true }),
25
80
  scopes: z.array(Scopes.guard.pick({ id: true, name: true, description: true })),
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,120 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { applicationAccessControlGuard, createDefaultApplicationAccessControl, } from './application.js';
3
+ describe('applicationAccessControlGuard', () => {
4
+ it('deduplicates direct user and role rules', () => {
5
+ expect(applicationAccessControlGuard.parse({
6
+ userIds: ['user-1', 'user-2', 'user-1'],
7
+ userRoleIds: ['role-1', 'role-1', 'role-2'],
8
+ organizationIds: ['organization-1', 'organization-1', 'organization-2'],
9
+ organizationRoleRules: [],
10
+ })).toMatchObject({
11
+ userIds: ['user-1', 'user-2'],
12
+ userRoleIds: ['role-1', 'role-2'],
13
+ organizationIds: ['organization-1', 'organization-2'],
14
+ organizationRoleRules: [],
15
+ });
16
+ });
17
+ it('merges organization role rules by organization', () => {
18
+ expect(applicationAccessControlGuard.parse({
19
+ userIds: [],
20
+ userRoleIds: [],
21
+ organizationIds: [],
22
+ organizationRoleRules: [
23
+ {
24
+ organizationId: 'organization-1',
25
+ organizationRoleIds: ['organization-role-1', 'organization-role-2'],
26
+ },
27
+ {
28
+ organizationId: 'organization-1',
29
+ organizationRoleIds: ['organization-role-1', 'organization-role-3'],
30
+ },
31
+ {
32
+ organizationId: 'organization-2',
33
+ organizationRoleIds: ['organization-role-1'],
34
+ },
35
+ ],
36
+ })).toMatchObject({
37
+ userIds: [],
38
+ userRoleIds: [],
39
+ organizationIds: [],
40
+ organizationRoleRules: [
41
+ {
42
+ organizationId: 'organization-1',
43
+ organizationRoleIds: [
44
+ 'organization-role-1',
45
+ 'organization-role-2',
46
+ 'organization-role-3',
47
+ ],
48
+ },
49
+ {
50
+ organizationId: 'organization-2',
51
+ organizationRoleIds: ['organization-role-1'],
52
+ },
53
+ ],
54
+ });
55
+ });
56
+ it('creates a fresh default rule set', () => {
57
+ const first = createDefaultApplicationAccessControl();
58
+ const second = createDefaultApplicationAccessControl();
59
+ expect(first).not.toBe(second);
60
+ expect(first.userIds).not.toBe(second.userIds);
61
+ expect(first.userRoleIds).not.toBe(second.userRoleIds);
62
+ expect(first.organizationIds).not.toBe(second.organizationIds);
63
+ expect(first.organizationRoleRules).not.toBe(second.organizationRoleRules);
64
+ });
65
+ it('rejects oversized rule lists', () => {
66
+ const oversizedIds = Array.from({ length: 1001 }, (_, index) => `id-${index}`);
67
+ const emptyAccessControl = createDefaultApplicationAccessControl();
68
+ expect(() => applicationAccessControlGuard.parse({ ...emptyAccessControl, userIds: oversizedIds })).toThrow();
69
+ expect(() => applicationAccessControlGuard.parse({
70
+ ...emptyAccessControl,
71
+ organizationRoleRules: oversizedIds.map((organizationId) => ({
72
+ organizationId,
73
+ organizationRoleIds: [],
74
+ })),
75
+ })).toThrow();
76
+ expect(() => applicationAccessControlGuard.parse({
77
+ ...emptyAccessControl,
78
+ organizationRoleRules: [
79
+ { organizationId: 'organization-1', organizationRoleIds: oversizedIds },
80
+ ],
81
+ })).toThrow();
82
+ });
83
+ it('enforces rule list limits after normalization', () => {
84
+ const emptyAccessControl = createDefaultApplicationAccessControl();
85
+ const duplicateHeavyIds = Array.from({ length: 1001 }, () => 'user-1');
86
+ const mergedOrganizationRoleRules = [
87
+ {
88
+ organizationId: 'organization-1',
89
+ organizationRoleIds: Array.from({ length: 1000 }, (_, index) => `role-${index}`),
90
+ },
91
+ {
92
+ organizationId: 'organization-1',
93
+ organizationRoleIds: ['role-1000'],
94
+ },
95
+ ];
96
+ expect(applicationAccessControlGuard.parse({ ...emptyAccessControl, userIds: duplicateHeavyIds })).toMatchObject({ userIds: ['user-1'] });
97
+ expect(() => applicationAccessControlGuard.parse({
98
+ ...emptyAccessControl,
99
+ organizationRoleRules: mergedOrganizationRoleRules,
100
+ })).toThrow();
101
+ });
102
+ it('rejects overly large raw rule inputs before normalization', () => {
103
+ const emptyAccessControl = createDefaultApplicationAccessControl();
104
+ const oversizedDuplicateIds = Array.from({ length: 2001 }, () => 'id-1');
105
+ expect(() => applicationAccessControlGuard.parse({ ...emptyAccessControl, userIds: oversizedDuplicateIds })).toThrow();
106
+ expect(() => applicationAccessControlGuard.parse({
107
+ ...emptyAccessControl,
108
+ organizationRoleRules: oversizedDuplicateIds.map(() => ({
109
+ organizationId: 'organization-1',
110
+ organizationRoleIds: [],
111
+ })),
112
+ })).toThrow();
113
+ expect(() => applicationAccessControlGuard.parse({
114
+ ...emptyAccessControl,
115
+ organizationRoleRules: [
116
+ { organizationId: 'organization-1', organizationRoleIds: oversizedDuplicateIds },
117
+ ],
118
+ })).toThrow();
119
+ });
120
+ });
@@ -179,6 +179,7 @@ export declare const publicApplicationGuard: z.ZodObject<Pick<{
179
179
  pageRules: {
180
180
  path: string;
181
181
  }[];
182
+ additionalScopes?: (import("@logto/core-kit").UserScope.CustomData | import("@logto/core-kit").UserScope.Identities | import("@logto/core-kit").UserScope.Roles | import("@logto/core-kit").UserScope.Organizations | import("@logto/core-kit").UserScope.OrganizationRoles)[] | undefined;
182
183
  customDomains?: {
183
184
  status: import("../index.js").DomainStatus;
184
185
  domain: string;
@@ -207,6 +208,7 @@ export declare const publicApplicationGuard: z.ZodObject<Pick<{
207
208
  pageRules: {
208
209
  path: string;
209
210
  }[];
211
+ additionalScopes?: (import("@logto/core-kit").UserScope.CustomData | import("@logto/core-kit").UserScope.Identities | import("@logto/core-kit").UserScope.Roles | import("@logto/core-kit").UserScope.Organizations | import("@logto/core-kit").UserScope.OrganizationRoles)[] | undefined;
210
212
  customDomains?: {
211
213
  status: import("../index.js").DomainStatus;
212
214
  domain: string;
@@ -231,6 +233,7 @@ export declare const publicApplicationGuard: z.ZodObject<Pick<{
231
233
  } | null>;
232
234
  customData: z.ZodType<import("@withtyped/server").JsonObject, z.ZodTypeDef, import("@withtyped/server").JsonObject>;
233
235
  isThirdParty: z.ZodType<boolean, z.ZodTypeDef, boolean>;
236
+ appLevelAccessControlEnabled: z.ZodType<boolean, z.ZodTypeDef, boolean>;
234
237
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
235
238
  }, "name" | "id">, "strip", z.ZodTypeAny, {
236
239
  name: string;
@@ -502,6 +505,7 @@ export declare const consentInfoResponseGuard: z.ZodObject<{
502
505
  pageRules: {
503
506
  path: string;
504
507
  }[];
508
+ additionalScopes?: (import("@logto/core-kit").UserScope.CustomData | import("@logto/core-kit").UserScope.Identities | import("@logto/core-kit").UserScope.Roles | import("@logto/core-kit").UserScope.Organizations | import("@logto/core-kit").UserScope.OrganizationRoles)[] | undefined;
505
509
  customDomains?: {
506
510
  status: import("../index.js").DomainStatus;
507
511
  domain: string;
@@ -530,6 +534,7 @@ export declare const consentInfoResponseGuard: z.ZodObject<{
530
534
  pageRules: {
531
535
  path: string;
532
536
  }[];
537
+ additionalScopes?: (import("@logto/core-kit").UserScope.CustomData | import("@logto/core-kit").UserScope.Identities | import("@logto/core-kit").UserScope.Roles | import("@logto/core-kit").UserScope.Organizations | import("@logto/core-kit").UserScope.OrganizationRoles)[] | undefined;
533
538
  customDomains?: {
534
539
  status: import("../index.js").DomainStatus;
535
540
  domain: string;
@@ -554,6 +559,7 @@ export declare const consentInfoResponseGuard: z.ZodObject<{
554
559
  } | null>;
555
560
  customData: z.ZodType<import("@withtyped/server").JsonObject, z.ZodTypeDef, import("@withtyped/server").JsonObject>;
556
561
  isThirdParty: z.ZodType<boolean, z.ZodTypeDef, boolean>;
562
+ appLevelAccessControlEnabled: z.ZodType<boolean, z.ZodTypeDef, boolean>;
557
563
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
558
564
  }, "name" | "id"> & {
559
565
  displayName: z.ZodOptional<z.ZodType<string | null, z.ZodTypeDef, string | null>>;
@@ -2383,11 +2383,10 @@ export declare const updateCustomProfileFieldSieOrderGuard: z.ZodObject<{
2383
2383
  sieOrder: number;
2384
2384
  }>;
2385
2385
  export type UpdateCustomProfileFieldSieOrder = z.infer<typeof updateCustomProfileFieldSieOrderGuard>;
2386
- /**
2387
- * Reserved custom data keys, which are used by the system and should not be used by custom profile fields.
2388
- */
2386
+ /** Reserved custom data keys, which are used by the system and should not be used by custom profile fields. */
2389
2387
  export declare const reservedCustomDataKeyGuard: z.ZodObject<{
2390
2388
  onboarding: z.ZodOptional<z.ZodString>;
2389
+ ossOnboarding: z.ZodOptional<z.ZodString>;
2391
2390
  guideRequests: z.ZodOptional<z.ZodString>;
2392
2391
  adminConsolePreferences: z.ZodOptional<z.ZodString>;
2393
2392
  defaultTenantId: z.ZodOptional<z.ZodString>;
@@ -2396,17 +2395,16 @@ export declare const reservedCustomDataKeyGuard: z.ZodObject<{
2396
2395
  guideRequests?: string | undefined;
2397
2396
  defaultTenantId?: string | undefined;
2398
2397
  onboarding?: string | undefined;
2398
+ ossOnboarding?: string | undefined;
2399
2399
  }, {
2400
2400
  adminConsolePreferences?: string | undefined;
2401
2401
  guideRequests?: string | undefined;
2402
2402
  defaultTenantId?: string | undefined;
2403
2403
  onboarding?: string | undefined;
2404
+ ossOnboarding?: string | undefined;
2404
2405
  }>;
2405
- export declare const reservedCustomDataKeys: readonly ["adminConsolePreferences", "guideRequests", "defaultTenantId", "onboarding"];
2406
- /**
2407
- * Disallow sign-in identifiers related field keys in custom profile fields, as this is conflicting
2408
- * with the built-in sign-in/sign-up experience flows.
2409
- */
2406
+ export declare const reservedCustomDataKeys: readonly ["adminConsolePreferences", "guideRequests", "defaultTenantId", "onboarding", "ossOnboarding"];
2407
+ /** Disallow sign-in identifier related field keys in custom profile fields to avoid conflicts with built-in sign-in/sign-up flows. */
2410
2408
  export declare const signInIdentifierKeyGuard: z.ZodObject<Pick<{
2411
2409
  tenantId: z.ZodOptional<z.ZodType<string, z.ZodTypeDef, string>>;
2412
2410
  id: z.ZodType<string, z.ZodTypeDef, string>;
@@ -2544,11 +2542,7 @@ export declare const signInIdentifierKeyGuard: z.ZodObject<Pick<{
2544
2542
  primaryPhone?: string | null;
2545
2543
  }>;
2546
2544
  export declare const reservedSignInIdentifierKeys: readonly ["username", "email", "phone", "primaryEmail", "primaryPhone"];
2547
- /**
2548
- * Reserved user profile keys.
2549
- * Currently only `preferredUsername` is reserved since it is the standard username property used
2550
- * by most identity providers. Should not allow user updating this field via profile related APIs.
2551
- */
2545
+ /** Reserved user profile keys. Currently only `preferredUsername` is reserved for standard IdP usage. */
2552
2546
  export declare const reservedBuiltInProfileKeyGuard: z.ZodObject<Pick<{
2553
2547
  familyName: z.ZodOptional<z.ZodString>;
2554
2548
  givenName: z.ZodOptional<z.ZodString>;
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { Users } from '../db-entries/user.js';
3
3
  import { CustomProfileFieldType, customProfileFieldTypeGuard, fieldPartGuard, userProfileAddressKeys, userProfileGuard, } from '../foundations/index.js';
4
- import { userOnboardingDataKey } from './onboarding.js';
4
+ import { ossUserOnboardingDataKey, userOnboardingDataKey } from './onboarding.js';
5
5
  import { defaultTenantIdKey } from './tenant.js';
6
6
  import { consoleUserPreferenceKey, guideRequestsKey } from './user.js';
7
7
  const baseProfileFieldGuard = z.object({
@@ -129,22 +129,18 @@ export const updateCustomProfileFieldSieOrderGuard = z.object({
129
129
  name: z.string(),
130
130
  sieOrder: z.number(),
131
131
  });
132
- /**
133
- * Reserved custom data keys, which are used by the system and should not be used by custom profile fields.
134
- */
132
+ /** Reserved custom data keys, which are used by the system and should not be used by custom profile fields. */
135
133
  export const reservedCustomDataKeyGuard = z
136
134
  .object({
137
135
  [userOnboardingDataKey]: z.string(),
136
+ [ossUserOnboardingDataKey]: z.string(),
138
137
  [guideRequestsKey]: z.string(),
139
138
  [consoleUserPreferenceKey]: z.string(),
140
139
  [defaultTenantIdKey]: z.string(),
141
140
  })
142
141
  .partial();
143
142
  export const reservedCustomDataKeys = Object.freeze(reservedCustomDataKeyGuard.keyof().options);
144
- /**
145
- * Disallow sign-in identifiers related field keys in custom profile fields, as this is conflicting
146
- * with the built-in sign-in/sign-up experience flows.
147
- */
143
+ /** Disallow sign-in identifier related field keys in custom profile fields to avoid conflicts with built-in sign-in/sign-up flows. */
148
144
  export const signInIdentifierKeyGuard = Users.createGuard
149
145
  .pick({
150
146
  username: true,
@@ -156,11 +152,7 @@ export const signInIdentifierKeyGuard = Users.createGuard
156
152
  phone: z.string().nullable().optional(),
157
153
  });
158
154
  export const reservedSignInIdentifierKeys = Object.freeze(signInIdentifierKeyGuard.keyof().options);
159
- /**
160
- * Reserved user profile keys.
161
- * Currently only `preferredUsername` is reserved since it is the standard username property used
162
- * by most identity providers. Should not allow user updating this field via profile related APIs.
163
- */
155
+ /** Reserved user profile keys. Currently only `preferredUsername` is reserved for standard IdP usage. */
164
156
  export const reservedBuiltInProfileKeyGuard = userProfileGuard.pick({ preferredUsername: true });
165
157
  export const reservedBuiltInProfileKeys = Object.freeze(reservedBuiltInProfileKeyGuard.keyof().options);
166
158
  export var SupportedDateFormat;
@@ -176,3 +168,4 @@ export var Gender;
176
168
  Gender["Male"] = "male";
177
169
  Gender["Other"] = "prefer_not_to_say";
178
170
  })(Gender || (Gender = {}));
171
+ /* eslint-enable max-lines */