@logto/schemas 1.15.0 → 1.17.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 (66) hide show
  1. package/alterations/1.16.0-1712912361-delete-jwt-customier-with-empty-script.ts +23 -0
  2. package/alterations/1.16.0-1713942039-add-organization-custom-data.ts +25 -0
  3. package/alterations/1.16.0-1714270244-application-org-resource-scope.ts +32 -0
  4. package/alterations/1.17.0-1715826336-add-default-user-role-config.ts +18 -0
  5. package/alterations/1.17.0-1715829731-rename-data-hook-schema-update-event.ts +120 -0
  6. package/alterations/1.17.0-1716278409-remove-internal-role-database-policies.ts +37 -0
  7. package/alterations/1.17.0-1716291265-create-pre-configured-m-api-role.ts +92 -0
  8. package/alterations/1.17.0-1717148078-remove-service-log-reference.ts +19 -0
  9. package/alterations/utils/1716643968-id-generation.ts +46 -0
  10. package/alterations-js/1.16.0-1712912361-delete-jwt-customier-with-empty-script.d.ts +3 -0
  11. package/alterations-js/1.16.0-1712912361-delete-jwt-customier-with-empty-script.js +17 -0
  12. package/alterations-js/1.16.0-1713942039-add-organization-custom-data.d.ts +4 -0
  13. package/alterations-js/1.16.0-1713942039-add-organization-custom-data.js +17 -0
  14. package/alterations-js/1.16.0-1714270244-application-org-resource-scope.d.ts +3 -0
  15. package/alterations-js/1.16.0-1714270244-application-org-resource-scope.js +27 -0
  16. package/alterations-js/1.17.0-1715826336-add-default-user-role-config.d.ts +3 -0
  17. package/alterations-js/1.17.0-1715826336-add-default-user-role-config.js +14 -0
  18. package/alterations-js/1.17.0-1715829731-rename-data-hook-schema-update-event.d.ts +3 -0
  19. package/alterations-js/1.17.0-1715829731-rename-data-hook-schema-update-event.js +96 -0
  20. package/alterations-js/1.17.0-1716278409-remove-internal-role-database-policies.d.ts +3 -0
  21. package/alterations-js/1.17.0-1716278409-remove-internal-role-database-policies.js +33 -0
  22. package/alterations-js/1.17.0-1716291265-create-pre-configured-m-api-role.d.ts +7 -0
  23. package/alterations-js/1.17.0-1716291265-create-pre-configured-m-api-role.js +77 -0
  24. package/alterations-js/1.17.0-1717148078-remove-service-log-reference.d.ts +3 -0
  25. package/alterations-js/1.17.0-1717148078-remove-service-log-reference.js +15 -0
  26. package/alterations-js/utils/1716643968-id-generation.d.ts +19 -0
  27. package/alterations-js/utils/1716643968-id-generation.js +26 -0
  28. package/lib/db-entries/application-user-consent-organization-resource-scope.d.ts +24 -0
  29. package/lib/db-entries/application-user-consent-organization-resource-scope.js +29 -0
  30. package/lib/db-entries/index.d.ts +1 -0
  31. package/lib/db-entries/index.js +1 -0
  32. package/lib/db-entries/organization.d.ts +6 -2
  33. package/lib/db-entries/organization.js +5 -0
  34. package/lib/db-entries/role.d.ts +5 -1
  35. package/lib/db-entries/role.js +4 -0
  36. package/lib/foundations/jsonb-types/hooks.d.ts +73 -3
  37. package/lib/foundations/jsonb-types/hooks.js +101 -7
  38. package/lib/models/tenants.d.ts +0 -21
  39. package/lib/models/tenants.js +0 -3
  40. package/lib/seeds/cloud-api.js +1 -0
  41. package/lib/seeds/management-api.d.ts +4 -0
  42. package/lib/seeds/management-api.js +10 -0
  43. package/lib/types/application.d.ts +81 -0
  44. package/lib/types/application.js +7 -4
  45. package/lib/types/consent.d.ts +207 -22
  46. package/lib/types/consent.js +11 -7
  47. package/lib/types/hook.d.ts +66 -19
  48. package/lib/types/logto-config/index.d.ts +20 -19
  49. package/lib/types/logto-config/jwt-customizer.d.ts +47 -40
  50. package/lib/types/logto-config/jwt-customizer.js +19 -24
  51. package/lib/types/logto-config/jwt-customizer.test.js +10 -2
  52. package/lib/types/mapi-proxy.js +1 -0
  53. package/lib/types/organization.d.ts +0 -1
  54. package/lib/types/organization.js +0 -9
  55. package/lib/types/system.d.ts +28 -1
  56. package/lib/types/system.js +16 -0
  57. package/lib/types/user.d.ts +12 -8
  58. package/lib/types/user.js +5 -1
  59. package/lib/utils/role.d.ts +2 -0
  60. package/lib/utils/role.js +2 -0
  61. package/package.json +10 -9
  62. package/tables/_after_all.sql +0 -27
  63. package/tables/application_user_consent_organization_resource_scopes.sql +18 -0
  64. package/tables/organizations.sql +2 -0
  65. package/tables/roles.sql +2 -0
  66. package/tables/service_logs.sql +1 -2
@@ -0,0 +1,23 @@
1
+ import { sql } from '@silverhand/slonik';
2
+
3
+ import type { AlterationScript } from '../lib/types/alteration.js';
4
+
5
+ const alteration: AlterationScript = {
6
+ // We are making the jwt-customizer script field mandatory
7
+ // Delete the records in logto_configs where key is jwt.accessToken or jwt.clientCredentials and value jsonb's script field is undefined
8
+ up: async (pool) => {
9
+ await pool.query(
10
+ sql`
11
+ delete from logto_configs
12
+ where key in ('jwt.accessToken', 'jwt.clientCredentials')
13
+ and value->>'script' is null
14
+ `
15
+ );
16
+ },
17
+ down: async () => {
18
+ // No down script available, this is a non-reversible operation
19
+ // It is fine since we have not released this feature yet
20
+ },
21
+ };
22
+
23
+ export default alteration;
@@ -0,0 +1,25 @@
1
+ import { sql } from '@silverhand/slonik';
2
+
3
+ import type { AlterationScript } from '../lib/types/alteration.js';
4
+
5
+ /** The alteration script to add the `custom_data` field to the `organizations` table. */
6
+ const alteration: AlterationScript = {
7
+ up: async (pool) => {
8
+ await pool.query(
9
+ sql`
10
+ alter table organizations
11
+ add column custom_data jsonb not null default '{}'::jsonb;
12
+ `
13
+ );
14
+ },
15
+ down: async (pool) => {
16
+ await pool.query(
17
+ sql`
18
+ alter table organizations
19
+ drop column custom_data;
20
+ `
21
+ );
22
+ },
23
+ };
24
+
25
+ export default alteration;
@@ -0,0 +1,32 @@
1
+ import { sql } from '@silverhand/slonik';
2
+
3
+ import type { AlterationScript } from '../lib/types/alteration.js';
4
+
5
+ import { applyTableRls, dropTableRls } from './utils/1704934999-tables.js';
6
+
7
+ const alteration: AlterationScript = {
8
+ up: async (pool) => {
9
+ await pool.query(sql`
10
+ create table application_user_consent_organization_resource_scopes (
11
+ tenant_id varchar(21) not null
12
+ references tenants (id) on update cascade on delete cascade,
13
+ /** The globally unique identifier of the application. */
14
+ application_id varchar(21) not null
15
+ references applications (id) on update cascade on delete cascade,
16
+ /** The globally unique identifier of the resource scope. */
17
+ scope_id varchar(21) not null
18
+ references scopes (id) on update cascade on delete cascade,
19
+ primary key (application_id, scope_id)
20
+ );
21
+ `);
22
+ await applyTableRls(pool, 'application_user_consent_organization_resource_scopes');
23
+ },
24
+ down: async (pool) => {
25
+ await dropTableRls(pool, 'application_user_consent_organization_resource_scopes');
26
+ await pool.query(sql`
27
+ drop table application_user_consent_organization_resource_scopes
28
+ `);
29
+ },
30
+ };
31
+
32
+ export default alteration;
@@ -0,0 +1,18 @@
1
+ import { sql } from '@silverhand/slonik';
2
+
3
+ import type { AlterationScript } from '../lib/types/alteration.js';
4
+
5
+ const alteration: AlterationScript = {
6
+ up: async (pool) => {
7
+ await pool.query(sql`
8
+ alter table roles add column is_default boolean not null default false;
9
+ `);
10
+ },
11
+ down: async (pool) => {
12
+ await pool.query(sql`
13
+ alter table roles drop column is_default;
14
+ `);
15
+ },
16
+ };
17
+
18
+ export default alteration;
@@ -0,0 +1,120 @@
1
+ import { sql } from '@silverhand/slonik';
2
+
3
+ import type { AlterationScript } from '../lib/types/alteration.js';
4
+
5
+ enum DataHookSchema {
6
+ User = 'User',
7
+ Role = 'Role',
8
+ Scope = 'Scope',
9
+ Organization = 'Organization',
10
+ OrganizationRole = 'OrganizationRole',
11
+ OrganizationScope = 'OrganizationScope',
12
+ }
13
+
14
+ type OldSchemaUpdateEvent = `${DataHookSchema}.${'Updated'}`;
15
+ type NewSchemaUpdateEvent = `${DataHookSchema}.Data.Updated`;
16
+
17
+ const oldSchemaUpdateEvents = Object.freeze([
18
+ 'User.Updated',
19
+ 'Role.Updated',
20
+ 'Scope.Updated',
21
+ 'Organization.Updated',
22
+ 'OrganizationRole.Updated',
23
+ 'OrganizationScope.Updated',
24
+ ] satisfies OldSchemaUpdateEvent[]);
25
+
26
+ const newSchemaUpdateEvents = Object.freeze([
27
+ 'User.Data.Updated',
28
+ 'Role.Data.Updated',
29
+ 'Scope.Data.Updated',
30
+ 'Organization.Data.Updated',
31
+ 'OrganizationRole.Data.Updated',
32
+ 'OrganizationScope.Data.Updated',
33
+ ] as const satisfies NewSchemaUpdateEvent[]);
34
+
35
+ const updateMap: { [key in OldSchemaUpdateEvent]: NewSchemaUpdateEvent } = {
36
+ 'User.Updated': 'User.Data.Updated',
37
+ 'Role.Updated': 'Role.Data.Updated',
38
+ 'Scope.Updated': 'Scope.Data.Updated',
39
+ 'Organization.Updated': 'Organization.Data.Updated',
40
+ 'OrganizationRole.Updated': 'OrganizationRole.Data.Updated',
41
+ 'OrganizationScope.Updated': 'OrganizationScope.Data.Updated',
42
+ };
43
+
44
+ const reverseMap: { [key in NewSchemaUpdateEvent]: OldSchemaUpdateEvent } = {
45
+ 'User.Data.Updated': 'User.Updated',
46
+ 'Role.Data.Updated': 'Role.Updated',
47
+ 'Scope.Data.Updated': 'Scope.Updated',
48
+ 'Organization.Data.Updated': 'Organization.Updated',
49
+ 'OrganizationRole.Data.Updated': 'OrganizationRole.Updated',
50
+ 'OrganizationScope.Data.Updated': 'OrganizationScope.Updated',
51
+ };
52
+
53
+ // This alteration script filters all the hook's events jsonb column to replace all the old schema update events with the new schema update events.
54
+
55
+ const isOldSchemaUpdateEvent = (event: string): event is OldSchemaUpdateEvent =>
56
+ // eslint-disable-next-line no-restricted-syntax
57
+ oldSchemaUpdateEvents.includes(event as OldSchemaUpdateEvent);
58
+
59
+ const isNewSchemaUpdateEvent = (event: string): event is NewSchemaUpdateEvent =>
60
+ // eslint-disable-next-line no-restricted-syntax
61
+ newSchemaUpdateEvents.includes(event as NewSchemaUpdateEvent);
62
+
63
+ const alteration: AlterationScript = {
64
+ up: async (pool) => {
65
+ const { rows: hooks } = await pool.query<{ id: string; events: string[] }>(sql`
66
+ select id, events
67
+ from hooks
68
+ `);
69
+
70
+ const hooksToBeUpdate = hooks.filter(({ events }) => {
71
+ return oldSchemaUpdateEvents.some((oldEvent) => events.includes(oldEvent));
72
+ });
73
+
74
+ await Promise.all(
75
+ hooksToBeUpdate.map(async ({ id, events }) => {
76
+ const updateEvents = events.reduce<string[]>((accumulator, event) => {
77
+ if (isOldSchemaUpdateEvent(event)) {
78
+ return [...accumulator, updateMap[event]];
79
+ }
80
+ return [...accumulator, event];
81
+ }, []);
82
+
83
+ await pool.query(sql`
84
+ update hooks
85
+ set events = ${JSON.stringify(updateEvents)}
86
+ where id = ${id};
87
+ `);
88
+ })
89
+ );
90
+ },
91
+ down: async (pool) => {
92
+ const { rows: hooks } = await pool.query<{ id: string; events: string[] }>(sql`
93
+ select id, events
94
+ from hooks
95
+ `);
96
+
97
+ const hooksToBeUpdate = hooks.filter(({ events }) => {
98
+ return newSchemaUpdateEvents.some((newEvent) => events.includes(newEvent));
99
+ });
100
+
101
+ await Promise.all(
102
+ hooksToBeUpdate.map(async ({ id, events }) => {
103
+ const updateEvents = events.reduce<string[]>((accumulator, event) => {
104
+ if (isNewSchemaUpdateEvent(event)) {
105
+ return [...accumulator, reverseMap[event]];
106
+ }
107
+ return [...accumulator, event];
108
+ }, []);
109
+
110
+ await pool.query(sql`
111
+ update hooks
112
+ set events = ${JSON.stringify(updateEvents)}
113
+ where id = ${id};
114
+ `);
115
+ })
116
+ );
117
+ },
118
+ };
119
+
120
+ export default alteration;
@@ -0,0 +1,37 @@
1
+ import { sql } from '@silverhand/slonik';
2
+
3
+ import type { AlterationScript } from '../lib/types/alteration.js';
4
+
5
+ const alteration: AlterationScript = {
6
+ up: async (pool) => {
7
+ await pool.query(sql`
8
+ drop policy if exists roles_select on roles;
9
+ drop policy if exists roles_modification on roles;
10
+ create policy roles_modification on roles using (true);
11
+
12
+ drop policy if exists roles_scopes_select on roles_scopes;
13
+ drop policy if exists roles_scopes_modification on roles_scopes;
14
+ create policy roles_scopes_modification on roles_scopes using (true);
15
+ `);
16
+ },
17
+ down: async (pool) => {
18
+ await pool.query(sql`
19
+ create policy roles_select on roles
20
+ for select using (true);
21
+
22
+ drop policy roles_modification on roles;
23
+ create policy roles_modification on roles
24
+ using (not starts_with(name, '#internal:'));
25
+
26
+ -- Restrict role - scope modification
27
+ create policy roles_scopes_select on roles_scopes
28
+ for select using (true);
29
+
30
+ drop policy roles_scopes_modification on roles_scopes;
31
+ create policy roles_scopes_modification on roles_scopes
32
+ using (not starts_with((select roles.name from roles where roles.id = role_id), '#internal:'));
33
+ `);
34
+ },
35
+ };
36
+
37
+ export default alteration;
@@ -0,0 +1,92 @@
1
+ import { yes } from '@silverhand/essentials';
2
+ import { sql } from '@silverhand/slonik';
3
+
4
+ import type { AlterationScript } from '../lib/types/alteration.js';
5
+
6
+ import { generateStandardId } from './utils/1716643968-id-generation.js';
7
+
8
+ const isCi = yes(process.env.CI);
9
+
10
+ const defaultTenantId = 'default';
11
+ const defaultTenantManagementApiIndicator = `https://${defaultTenantId}.logto.app/api`;
12
+ const roleName = 'Logto Management API access';
13
+ const roleDescription = 'This default role grants access to the Logto management API.';
14
+ enum RoleType {
15
+ MachineToMachine = 'MachineToMachine',
16
+ }
17
+
18
+ enum PredefinedScope {
19
+ All = 'all',
20
+ }
21
+
22
+ /**
23
+ * This script is to create a pre-configured Management API M2M role for new users.
24
+ * This script is **only for CI**, since we won't create this role for existing users, so this script is not applicable for existing db data.
25
+ */
26
+ const alteration: AlterationScript = {
27
+ up: async (pool) => {
28
+ if (!isCi) {
29
+ console.info(
30
+ "Skipping the alteration script `next-1716291265-create-pre-configured-m-api-role.ts` since it's should not be applied to existing db data."
31
+ );
32
+ return;
33
+ }
34
+
35
+ /**
36
+ * Only affect the `default` tenant, since this is the only tenant in the OSS version and the initial tenant in the cloud version.
37
+ * So we only need to care about this role for the `default` tenant.
38
+ */
39
+
40
+ const roleId = generateStandardId();
41
+
42
+ await pool.query(sql`
43
+ insert into roles (id, tenant_id, name, description, type)
44
+ values (
45
+ ${roleId},
46
+ ${defaultTenantId},
47
+ ${roleName},
48
+ ${roleDescription},
49
+ ${RoleType.MachineToMachine}
50
+ );
51
+ `);
52
+
53
+ // Assign Logto Management API permission `all` to the Logto Management API M2M role
54
+ await pool.query(sql`
55
+ insert into roles_scopes (id, role_id, scope_id, tenant_id)
56
+ values (
57
+ ${generateStandardId()},
58
+ ${roleId},
59
+ (
60
+ select scopes.id
61
+ from scopes
62
+ join resources on
63
+ scopes.tenant_id = resources.tenant_id and
64
+ scopes.resource_id = resources.id
65
+ where resources.indicator = ${defaultTenantManagementApiIndicator}
66
+ and scopes.name = ${PredefinedScope.All}
67
+ and scopes.tenant_id = ${defaultTenantId}
68
+ ),
69
+ ${defaultTenantId}
70
+ )
71
+ `);
72
+ },
73
+ down: async (pool) => {
74
+ if (!isCi) {
75
+ console.info(
76
+ "Skipping the down script `next-1716291265-create-pre-configured-m-api-role.ts` since it's should not be applied to production db."
77
+ );
78
+ return;
79
+ }
80
+
81
+ // Delete the created role
82
+ await pool.query(sql`
83
+ delete from roles
84
+ where tenant_id = ${defaultTenantId}
85
+ and name = ${roleName}
86
+ and description = ${roleDescription}
87
+ and type = ${RoleType.MachineToMachine}
88
+ `);
89
+ },
90
+ };
91
+
92
+ export default alteration;
@@ -0,0 +1,19 @@
1
+ import { sql } from '@silverhand/slonik';
2
+
3
+ import type { AlterationScript } from '../lib/types/alteration.js';
4
+
5
+ const alteration: AlterationScript = {
6
+ up: async (pool) => {
7
+ await pool.query(sql`
8
+ alter table service_logs drop constraint service_logs_tenant_id_fkey;
9
+ `);
10
+ },
11
+ down: async (pool) => {
12
+ await pool.query(sql`
13
+ alter table service_logs add constraint service_logs_tenant_id_fkey
14
+ foreign key (tenant_id) references tenants(id) on update cascade on delete cascade;
15
+ `);
16
+ },
17
+ };
18
+
19
+ export default alteration;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * This file is forked from `@logto/shared` 3.1.0 to avoid alteration scripts to depend on outer packages.
3
+ */
4
+ import { customAlphabet } from 'nanoid';
5
+
6
+ const lowercaseAlphabet = '0123456789abcdefghijklmnopqrstuvwxyz';
7
+ const alphabet = `${lowercaseAlphabet}ABCDEFGHIJKLMNOPQRSTUVWXYZ` as const;
8
+
9
+ type BuildIdGenerator = {
10
+ /**
11
+ * Build a nanoid generator function uses numbers (0-9), lowercase letters (a-z), and uppercase letters (A-Z) as the alphabet.
12
+ * @param size The default id length for the generator.
13
+ */
14
+ (size: number): ReturnType<typeof customAlphabet>;
15
+ /**
16
+ * Build a nanoid generator function uses numbers (0-9) and lowercase letters (a-z) as the alphabet.
17
+ * @param size The default id length for the generator.
18
+ */
19
+ // eslint-disable-next-line @typescript-eslint/unified-signatures
20
+ (size: number, includingUppercase: false): ReturnType<typeof customAlphabet>;
21
+ };
22
+
23
+ const buildIdGenerator: BuildIdGenerator = (size: number, includingUppercase = true) =>
24
+ customAlphabet(includingUppercase ? alphabet : lowercaseAlphabet, size);
25
+
26
+ /**
27
+ * Generate a standard id with 21 characters, including lowercase letters and numbers.
28
+ *
29
+ * @see {@link lowercaseAlphabet}
30
+ */
31
+ export const generateStandardId = buildIdGenerator(21, false);
32
+
33
+ /**
34
+ * Generate a standard short id with 12 characters, including lowercase letters and numbers.
35
+ *
36
+ * @see {@link lowercaseAlphabet}
37
+ */
38
+ export const generateStandardShortId = buildIdGenerator(12, false);
39
+
40
+ /**
41
+ * Generate a standard secret with 32 characters, including uppercase letters, lowercase
42
+ * letters, and numbers.
43
+ *
44
+ * @see {@link alphabet}
45
+ */
46
+ export const generateStandardSecret = buildIdGenerator(32);
@@ -0,0 +1,3 @@
1
+ import type { AlterationScript } from '../lib/types/alteration.js';
2
+ declare const alteration: AlterationScript;
3
+ export default alteration;
@@ -0,0 +1,17 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ // We are making the jwt-customizer script field mandatory
4
+ // Delete the records in logto_configs where key is jwt.accessToken or jwt.clientCredentials and value jsonb's script field is undefined
5
+ up: async (pool) => {
6
+ await pool.query(sql `
7
+ delete from logto_configs
8
+ where key in ('jwt.accessToken', 'jwt.clientCredentials')
9
+ and value->>'script' is null
10
+ `);
11
+ },
12
+ down: async () => {
13
+ // No down script available, this is a non-reversible operation
14
+ // It is fine since we have not released this feature yet
15
+ },
16
+ };
17
+ export default alteration;
@@ -0,0 +1,4 @@
1
+ import type { AlterationScript } from '../lib/types/alteration.js';
2
+ /** The alteration script to add the `custom_data` field to the `organizations` table. */
3
+ declare const alteration: AlterationScript;
4
+ export default alteration;
@@ -0,0 +1,17 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ /** The alteration script to add the `custom_data` field to the `organizations` table. */
3
+ const alteration = {
4
+ up: async (pool) => {
5
+ await pool.query(sql `
6
+ alter table organizations
7
+ add column custom_data jsonb not null default '{}'::jsonb;
8
+ `);
9
+ },
10
+ down: async (pool) => {
11
+ await pool.query(sql `
12
+ alter table organizations
13
+ drop column custom_data;
14
+ `);
15
+ },
16
+ };
17
+ export default alteration;
@@ -0,0 +1,3 @@
1
+ import type { AlterationScript } from '../lib/types/alteration.js';
2
+ declare const alteration: AlterationScript;
3
+ export default alteration;
@@ -0,0 +1,27 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ import { applyTableRls, dropTableRls } from './utils/1704934999-tables.js';
3
+ const alteration = {
4
+ up: async (pool) => {
5
+ await pool.query(sql `
6
+ create table application_user_consent_organization_resource_scopes (
7
+ tenant_id varchar(21) not null
8
+ references tenants (id) on update cascade on delete cascade,
9
+ /** The globally unique identifier of the application. */
10
+ application_id varchar(21) not null
11
+ references applications (id) on update cascade on delete cascade,
12
+ /** The globally unique identifier of the resource scope. */
13
+ scope_id varchar(21) not null
14
+ references scopes (id) on update cascade on delete cascade,
15
+ primary key (application_id, scope_id)
16
+ );
17
+ `);
18
+ await applyTableRls(pool, 'application_user_consent_organization_resource_scopes');
19
+ },
20
+ down: async (pool) => {
21
+ await dropTableRls(pool, 'application_user_consent_organization_resource_scopes');
22
+ await pool.query(sql `
23
+ drop table application_user_consent_organization_resource_scopes
24
+ `);
25
+ },
26
+ };
27
+ export default alteration;
@@ -0,0 +1,3 @@
1
+ import type { AlterationScript } from '../lib/types/alteration.js';
2
+ declare const alteration: AlterationScript;
3
+ export default alteration;
@@ -0,0 +1,14 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ await pool.query(sql `
5
+ alter table roles add column is_default boolean not null default false;
6
+ `);
7
+ },
8
+ down: async (pool) => {
9
+ await pool.query(sql `
10
+ alter table roles drop column is_default;
11
+ `);
12
+ },
13
+ };
14
+ export default alteration;
@@ -0,0 +1,3 @@
1
+ import type { AlterationScript } from '../lib/types/alteration.js';
2
+ declare const alteration: AlterationScript;
3
+ export default alteration;
@@ -0,0 +1,96 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ var DataHookSchema;
3
+ (function (DataHookSchema) {
4
+ DataHookSchema["User"] = "User";
5
+ DataHookSchema["Role"] = "Role";
6
+ DataHookSchema["Scope"] = "Scope";
7
+ DataHookSchema["Organization"] = "Organization";
8
+ DataHookSchema["OrganizationRole"] = "OrganizationRole";
9
+ DataHookSchema["OrganizationScope"] = "OrganizationScope";
10
+ })(DataHookSchema || (DataHookSchema = {}));
11
+ const oldSchemaUpdateEvents = Object.freeze([
12
+ 'User.Updated',
13
+ 'Role.Updated',
14
+ 'Scope.Updated',
15
+ 'Organization.Updated',
16
+ 'OrganizationRole.Updated',
17
+ 'OrganizationScope.Updated',
18
+ ]);
19
+ const newSchemaUpdateEvents = Object.freeze([
20
+ 'User.Data.Updated',
21
+ 'Role.Data.Updated',
22
+ 'Scope.Data.Updated',
23
+ 'Organization.Data.Updated',
24
+ 'OrganizationRole.Data.Updated',
25
+ 'OrganizationScope.Data.Updated',
26
+ ]);
27
+ const updateMap = {
28
+ 'User.Updated': 'User.Data.Updated',
29
+ 'Role.Updated': 'Role.Data.Updated',
30
+ 'Scope.Updated': 'Scope.Data.Updated',
31
+ 'Organization.Updated': 'Organization.Data.Updated',
32
+ 'OrganizationRole.Updated': 'OrganizationRole.Data.Updated',
33
+ 'OrganizationScope.Updated': 'OrganizationScope.Data.Updated',
34
+ };
35
+ const reverseMap = {
36
+ 'User.Data.Updated': 'User.Updated',
37
+ 'Role.Data.Updated': 'Role.Updated',
38
+ 'Scope.Data.Updated': 'Scope.Updated',
39
+ 'Organization.Data.Updated': 'Organization.Updated',
40
+ 'OrganizationRole.Data.Updated': 'OrganizationRole.Updated',
41
+ 'OrganizationScope.Data.Updated': 'OrganizationScope.Updated',
42
+ };
43
+ // This alteration script filters all the hook's events jsonb column to replace all the old schema update events with the new schema update events.
44
+ const isOldSchemaUpdateEvent = (event) =>
45
+ // eslint-disable-next-line no-restricted-syntax
46
+ oldSchemaUpdateEvents.includes(event);
47
+ const isNewSchemaUpdateEvent = (event) =>
48
+ // eslint-disable-next-line no-restricted-syntax
49
+ newSchemaUpdateEvents.includes(event);
50
+ const alteration = {
51
+ up: async (pool) => {
52
+ const { rows: hooks } = await pool.query(sql `
53
+ select id, events
54
+ from hooks
55
+ `);
56
+ const hooksToBeUpdate = hooks.filter(({ events }) => {
57
+ return oldSchemaUpdateEvents.some((oldEvent) => events.includes(oldEvent));
58
+ });
59
+ await Promise.all(hooksToBeUpdate.map(async ({ id, events }) => {
60
+ const updateEvents = events.reduce((accumulator, event) => {
61
+ if (isOldSchemaUpdateEvent(event)) {
62
+ return [...accumulator, updateMap[event]];
63
+ }
64
+ return [...accumulator, event];
65
+ }, []);
66
+ await pool.query(sql `
67
+ update hooks
68
+ set events = ${JSON.stringify(updateEvents)}
69
+ where id = ${id};
70
+ `);
71
+ }));
72
+ },
73
+ down: async (pool) => {
74
+ const { rows: hooks } = await pool.query(sql `
75
+ select id, events
76
+ from hooks
77
+ `);
78
+ const hooksToBeUpdate = hooks.filter(({ events }) => {
79
+ return newSchemaUpdateEvents.some((newEvent) => events.includes(newEvent));
80
+ });
81
+ await Promise.all(hooksToBeUpdate.map(async ({ id, events }) => {
82
+ const updateEvents = events.reduce((accumulator, event) => {
83
+ if (isNewSchemaUpdateEvent(event)) {
84
+ return [...accumulator, reverseMap[event]];
85
+ }
86
+ return [...accumulator, event];
87
+ }, []);
88
+ await pool.query(sql `
89
+ update hooks
90
+ set events = ${JSON.stringify(updateEvents)}
91
+ where id = ${id};
92
+ `);
93
+ }));
94
+ },
95
+ };
96
+ export default alteration;
@@ -0,0 +1,3 @@
1
+ import type { AlterationScript } from '../lib/types/alteration.js';
2
+ declare const alteration: AlterationScript;
3
+ export default alteration;
@@ -0,0 +1,33 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ await pool.query(sql `
5
+ drop policy if exists roles_select on roles;
6
+ drop policy if exists roles_modification on roles;
7
+ create policy roles_modification on roles using (true);
8
+
9
+ drop policy if exists roles_scopes_select on roles_scopes;
10
+ drop policy if exists roles_scopes_modification on roles_scopes;
11
+ create policy roles_scopes_modification on roles_scopes using (true);
12
+ `);
13
+ },
14
+ down: async (pool) => {
15
+ await pool.query(sql `
16
+ create policy roles_select on roles
17
+ for select using (true);
18
+
19
+ drop policy roles_modification on roles;
20
+ create policy roles_modification on roles
21
+ using (not starts_with(name, '#internal:'));
22
+
23
+ -- Restrict role - scope modification
24
+ create policy roles_scopes_select on roles_scopes
25
+ for select using (true);
26
+
27
+ drop policy roles_scopes_modification on roles_scopes;
28
+ create policy roles_scopes_modification on roles_scopes
29
+ using (not starts_with((select roles.name from roles where roles.id = role_id), '#internal:'));
30
+ `);
31
+ },
32
+ };
33
+ export default alteration;
@@ -0,0 +1,7 @@
1
+ import type { AlterationScript } from '../lib/types/alteration.js';
2
+ /**
3
+ * This script is to create a pre-configured Management API M2M role for new users.
4
+ * This script is **only for CI**, since we won't create this role for existing users, so this script is not applicable for existing db data.
5
+ */
6
+ declare const alteration: AlterationScript;
7
+ export default alteration;