@cosmicdrift/kumiko-bundled-features 0.332.0 → 0.334.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/handlers/list.query.js +4 -3
- package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -1
- package/dist/auth-email-password/handlers/invite-create.write.js +2 -2
- package/dist/auth-mfa/schema/user-mfa.d.ts +6 -0
- package/dist/billing-foundation/entities.d.ts +8 -0
- package/dist/billing-foundation/projection.d.ts +8 -0
- package/dist/cap-counter/entity.d.ts +1 -0
- package/dist/compliance-profiles/schema/profile-selection.d.ts +2 -2
- package/dist/config/table.d.ts +6 -0
- package/dist/config/web/i18n.js +12 -4
- package/dist/custom-fields/entity.d.ts +4 -0
- package/dist/data-retention/schema/tenant-retention-override.d.ts +4 -0
- package/dist/delivery/tables.d.ts +6 -0
- package/dist/document-ingest-foundation/entity.d.ts +4 -0
- package/dist/file-provider-s3/feature.js +1 -1
- package/dist/folders/entity.d.ts +8 -0
- package/dist/form-draft/entity.d.ts +2 -0
- package/dist/inbound-mail-foundation/entities.d.ts +25 -0
- package/dist/inbound-mail-foundation/projection.d.ts +20 -0
- package/dist/jobs/job-run-table.d.ts +6 -0
- package/dist/ledger/entity.d.ts +16 -3
- package/dist/managed-pages/table.d.ts +12 -0
- package/dist/notes-history/entity.d.ts +12 -0
- package/dist/personal-access-tokens/schema/api-token.d.ts +6 -0
- package/dist/secrets/table.d.ts +1 -0
- package/dist/sessions/schema/user-session.d.ts +4 -0
- package/dist/subscription-stripe/feature.js +3 -3
- package/dist/tags/entity.d.ts +9 -0
- package/dist/template-resolver/table.d.ts +18 -8
- package/dist/template-resolver/user-content-table.d.ts +14 -4
- package/dist/tenant/constants.d.ts +1 -1
- package/dist/tenant/constants.js +7 -1
- package/dist/tenant/feature.d.ts +4 -1
- package/dist/tenant/feature.js +13 -4
- package/dist/tenant/handlers/update-member-roles.write.js +2 -2
- package/dist/tenant/i18n.js +2 -0
- package/dist/tenant/index.d.ts +1 -1
- package/dist/tenant/index.js +1 -1
- package/dist/tenant/invitation-table.d.ts +8 -2
- package/dist/tenant/membership-table.d.ts +4 -0
- package/dist/tenant/schema/tenant.d.ts +8 -2
- package/dist/tenant/screens.d.ts +59 -3
- package/dist/tenant/screens.js +54 -36
- package/dist/tenant-settings/feature.js +9 -6
- package/dist/tier-engine/entity.d.ts +2 -0
- package/dist/tier-engine/tier-resolver.d.ts +2 -0
- package/dist/user/schema/user.d.ts +14 -2
- package/dist/user-data-rights/run-user-export.js +6 -2
- package/dist/user-data-rights/schema/download-attempt.d.ts +14 -0
- package/dist/user-data-rights/schema/download-token.d.ts +8 -0
- package/dist/user-data-rights/schema/export-job.d.ts +8 -2
- package/package.json +9 -9
- package/src/tenant/changes.json +5 -0
package/dist/tenant/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { TenantCommandSchemas } from "./command-schemas.js";
|
|
2
2
|
export { TENANT_FEATURE, TenantErrors, TenantHandlers, TenantQueries } from "./constants.js";
|
|
3
|
-
export { createTenantFeature } from "./feature.js";
|
|
3
|
+
export { collectAssignableAppRoles, createTenantFeature } from "./feature.js";
|
|
4
4
|
export type { InvitationStatus } from "./invitation-table.js";
|
|
5
5
|
export { INVITATION_STATUS, INVITATION_STATUSES, tenantInvitationEntity, tenantInvitationsTable, } from "./invitation-table.js";
|
|
6
6
|
export { isTenantServingPublicContent } from "./is-tenant-serving-public-content.js";
|
package/dist/tenant/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { TenantCommandSchemas } from "./command-schemas.js";
|
|
2
2
|
export { TENANT_FEATURE, TenantErrors, TenantHandlers, TenantQueries } from "./constants.js";
|
|
3
|
-
export { createTenantFeature } from "./feature.js";
|
|
3
|
+
export { collectAssignableAppRoles, createTenantFeature } from "./feature.js";
|
|
4
4
|
export { INVITATION_STATUS, INVITATION_STATUSES, tenantInvitationEntity, tenantInvitationsTable, } from "./invitation-table.js";
|
|
5
5
|
export { isTenantServingPublicContent } from "./is-tenant-serving-public-content.js";
|
|
6
6
|
export { tenantMembershipEntity, tenantMembershipsTable } from "./membership-table.js";
|
|
@@ -17,6 +17,7 @@ export declare const tenantInvitationEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
17
17
|
readonly filterable?: boolean;
|
|
18
18
|
readonly encrypted?: boolean;
|
|
19
19
|
readonly sensitive?: boolean;
|
|
20
|
+
readonly writeOnly?: boolean;
|
|
20
21
|
readonly readAsInstruction?: boolean;
|
|
21
22
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
22
23
|
readonly default?: string;
|
|
@@ -37,6 +38,7 @@ export declare const tenantInvitationEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
37
38
|
readonly filterable?: boolean;
|
|
38
39
|
readonly encrypted?: boolean;
|
|
39
40
|
readonly sensitive?: boolean;
|
|
41
|
+
readonly writeOnly?: boolean;
|
|
40
42
|
readonly readAsInstruction?: boolean;
|
|
41
43
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
42
44
|
readonly default?: string;
|
|
@@ -65,7 +67,7 @@ export declare const tenantInvitationEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
65
67
|
readonly pending?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
|
|
66
68
|
} | undefined;
|
|
67
69
|
readonly optionsQuery?: string;
|
|
68
|
-
readonly optionsQueryPayload?:
|
|
70
|
+
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
69
71
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
70
72
|
required: true;
|
|
71
73
|
};
|
|
@@ -79,6 +81,7 @@ export declare const tenantInvitationEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
79
81
|
readonly filterable?: boolean;
|
|
80
82
|
readonly encrypted?: boolean;
|
|
81
83
|
readonly sensitive?: boolean;
|
|
84
|
+
readonly writeOnly?: boolean;
|
|
82
85
|
readonly readAsInstruction?: boolean;
|
|
83
86
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
84
87
|
readonly default?: string;
|
|
@@ -116,6 +119,7 @@ export declare const tenantInvitationsTable: import("@cosmicdrift/kumiko-framewo
|
|
|
116
119
|
readonly filterable?: boolean;
|
|
117
120
|
readonly encrypted?: boolean;
|
|
118
121
|
readonly sensitive?: boolean;
|
|
122
|
+
readonly writeOnly?: boolean;
|
|
119
123
|
readonly readAsInstruction?: boolean;
|
|
120
124
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
121
125
|
readonly default?: string;
|
|
@@ -136,6 +140,7 @@ export declare const tenantInvitationsTable: import("@cosmicdrift/kumiko-framewo
|
|
|
136
140
|
readonly filterable?: boolean;
|
|
137
141
|
readonly encrypted?: boolean;
|
|
138
142
|
readonly sensitive?: boolean;
|
|
143
|
+
readonly writeOnly?: boolean;
|
|
139
144
|
readonly readAsInstruction?: boolean;
|
|
140
145
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
141
146
|
readonly default?: string;
|
|
@@ -164,7 +169,7 @@ export declare const tenantInvitationsTable: import("@cosmicdrift/kumiko-framewo
|
|
|
164
169
|
readonly pending?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
|
|
165
170
|
} | undefined;
|
|
166
171
|
readonly optionsQuery?: string;
|
|
167
|
-
readonly optionsQueryPayload?:
|
|
172
|
+
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
168
173
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
169
174
|
required: true;
|
|
170
175
|
};
|
|
@@ -178,6 +183,7 @@ export declare const tenantInvitationsTable: import("@cosmicdrift/kumiko-framewo
|
|
|
178
183
|
readonly filterable?: boolean;
|
|
179
184
|
readonly encrypted?: boolean;
|
|
180
185
|
readonly sensitive?: boolean;
|
|
186
|
+
readonly writeOnly?: boolean;
|
|
181
187
|
readonly readAsInstruction?: boolean;
|
|
182
188
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
183
189
|
readonly default?: string;
|
|
@@ -9,6 +9,7 @@ export declare const tenantMembershipEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
9
9
|
readonly filterable?: boolean;
|
|
10
10
|
readonly encrypted?: boolean;
|
|
11
11
|
readonly sensitive?: boolean;
|
|
12
|
+
readonly writeOnly?: boolean;
|
|
12
13
|
readonly readAsInstruction?: boolean;
|
|
13
14
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
14
15
|
readonly default?: string;
|
|
@@ -29,6 +30,7 @@ export declare const tenantMembershipEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
29
30
|
readonly filterable?: boolean;
|
|
30
31
|
readonly encrypted?: boolean;
|
|
31
32
|
readonly sensitive?: boolean;
|
|
33
|
+
readonly writeOnly?: boolean;
|
|
32
34
|
readonly readAsInstruction?: boolean;
|
|
33
35
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
34
36
|
readonly default?: string;
|
|
@@ -51,6 +53,7 @@ export declare const tenantMembershipsTable: import("@cosmicdrift/kumiko-framewo
|
|
|
51
53
|
readonly filterable?: boolean;
|
|
52
54
|
readonly encrypted?: boolean;
|
|
53
55
|
readonly sensitive?: boolean;
|
|
56
|
+
readonly writeOnly?: boolean;
|
|
54
57
|
readonly readAsInstruction?: boolean;
|
|
55
58
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
56
59
|
readonly default?: string;
|
|
@@ -71,6 +74,7 @@ export declare const tenantMembershipsTable: import("@cosmicdrift/kumiko-framewo
|
|
|
71
74
|
readonly filterable?: boolean;
|
|
72
75
|
readonly encrypted?: boolean;
|
|
73
76
|
readonly sensitive?: boolean;
|
|
77
|
+
readonly writeOnly?: boolean;
|
|
74
78
|
readonly readAsInstruction?: boolean;
|
|
75
79
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
76
80
|
readonly default?: string;
|
|
@@ -11,6 +11,7 @@ export declare const tenantEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
11
11
|
readonly filterable?: boolean;
|
|
12
12
|
readonly encrypted?: boolean;
|
|
13
13
|
readonly sensitive?: boolean;
|
|
14
|
+
readonly writeOnly?: boolean;
|
|
14
15
|
readonly readAsInstruction?: boolean;
|
|
15
16
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
16
17
|
readonly default?: string;
|
|
@@ -31,6 +32,7 @@ export declare const tenantEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
31
32
|
readonly filterable?: boolean;
|
|
32
33
|
readonly encrypted?: boolean;
|
|
33
34
|
readonly sensitive?: boolean;
|
|
35
|
+
readonly writeOnly?: boolean;
|
|
34
36
|
readonly readAsInstruction?: boolean;
|
|
35
37
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
36
38
|
readonly default?: string;
|
|
@@ -63,7 +65,7 @@ export declare const tenantEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
63
65
|
readonly destroying?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
|
|
64
66
|
} | undefined;
|
|
65
67
|
readonly optionsQuery?: string;
|
|
66
|
-
readonly optionsQueryPayload?:
|
|
68
|
+
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
67
69
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
68
70
|
required: true;
|
|
69
71
|
};
|
|
@@ -92,6 +94,7 @@ export declare const tenantEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
92
94
|
readonly filterable?: boolean;
|
|
93
95
|
readonly encrypted?: boolean;
|
|
94
96
|
readonly sensitive?: boolean;
|
|
97
|
+
readonly writeOnly?: boolean;
|
|
95
98
|
readonly readAsInstruction?: boolean;
|
|
96
99
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
97
100
|
readonly default?: string;
|
|
@@ -159,6 +162,7 @@ export declare const tenantTable: import("@cosmicdrift/kumiko-framework/db").Ent
|
|
|
159
162
|
readonly filterable?: boolean;
|
|
160
163
|
readonly encrypted?: boolean;
|
|
161
164
|
readonly sensitive?: boolean;
|
|
165
|
+
readonly writeOnly?: boolean;
|
|
162
166
|
readonly readAsInstruction?: boolean;
|
|
163
167
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
164
168
|
readonly default?: string;
|
|
@@ -179,6 +183,7 @@ export declare const tenantTable: import("@cosmicdrift/kumiko-framework/db").Ent
|
|
|
179
183
|
readonly filterable?: boolean;
|
|
180
184
|
readonly encrypted?: boolean;
|
|
181
185
|
readonly sensitive?: boolean;
|
|
186
|
+
readonly writeOnly?: boolean;
|
|
182
187
|
readonly readAsInstruction?: boolean;
|
|
183
188
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
184
189
|
readonly default?: string;
|
|
@@ -211,7 +216,7 @@ export declare const tenantTable: import("@cosmicdrift/kumiko-framework/db").Ent
|
|
|
211
216
|
readonly destroying?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
|
|
212
217
|
} | undefined;
|
|
213
218
|
readonly optionsQuery?: string;
|
|
214
|
-
readonly optionsQueryPayload?:
|
|
219
|
+
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
215
220
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
216
221
|
required: true;
|
|
217
222
|
};
|
|
@@ -240,6 +245,7 @@ export declare const tenantTable: import("@cosmicdrift/kumiko-framework/db").Ent
|
|
|
240
245
|
readonly filterable?: boolean;
|
|
241
246
|
readonly encrypted?: boolean;
|
|
242
247
|
readonly sensitive?: boolean;
|
|
248
|
+
readonly writeOnly?: boolean;
|
|
243
249
|
readonly readAsInstruction?: boolean;
|
|
244
250
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
245
251
|
readonly default?: string;
|
package/dist/tenant/screens.d.ts
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
|
-
import { type EntityEditScreenDefinition, type EntityListScreenDefinition, type ScreenDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
1
|
+
import { type AssignableAppRoles, type EntityEditScreenDefinition, type EntityListScreenDefinition, type ScreenDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
export declare const tenantListScreen: EntityListScreenDefinition;
|
|
3
3
|
export declare const tenantEditScreen: EntityEditScreenDefinition;
|
|
4
4
|
export declare function createMembersScreen(options?: {
|
|
5
5
|
readonly inviteScreen?: boolean;
|
|
6
6
|
}): ScreenDefinition;
|
|
7
|
+
export declare function createInviteCreateScreen(assignableAppRoles?: AssignableAppRoles): {
|
|
8
|
+
id: "invite-create";
|
|
9
|
+
type: "actionForm";
|
|
10
|
+
handler: "auth-email-password:write:invite-create";
|
|
11
|
+
fields: {
|
|
12
|
+
email: {
|
|
13
|
+
type: "text";
|
|
14
|
+
required: true;
|
|
15
|
+
format: "email";
|
|
16
|
+
};
|
|
17
|
+
role: {
|
|
18
|
+
type: "select";
|
|
19
|
+
options: string[];
|
|
20
|
+
required: true;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
layout: {
|
|
24
|
+
sections: {
|
|
25
|
+
fields: string[];
|
|
26
|
+
}[];
|
|
27
|
+
};
|
|
28
|
+
submitLabel: string;
|
|
29
|
+
access: {
|
|
30
|
+
roles: readonly string[];
|
|
31
|
+
};
|
|
32
|
+
};
|
|
7
33
|
export declare const inviteCreateScreen: {
|
|
8
34
|
id: "invite-create";
|
|
9
35
|
type: "actionForm";
|
|
@@ -16,7 +42,7 @@ export declare const inviteCreateScreen: {
|
|
|
16
42
|
};
|
|
17
43
|
role: {
|
|
18
44
|
type: "select";
|
|
19
|
-
options:
|
|
45
|
+
options: string[];
|
|
20
46
|
required: true;
|
|
21
47
|
};
|
|
22
48
|
};
|
|
@@ -30,6 +56,36 @@ export declare const inviteCreateScreen: {
|
|
|
30
56
|
roles: readonly string[];
|
|
31
57
|
};
|
|
32
58
|
};
|
|
59
|
+
export declare function createMemberRolesEditScreen(assignableAppRoles?: AssignableAppRoles): {
|
|
60
|
+
id: "member-roles-edit";
|
|
61
|
+
type: "actionForm";
|
|
62
|
+
handler: "tenant:write:update-member-roles";
|
|
63
|
+
redirect: "members";
|
|
64
|
+
cancelTarget: "members";
|
|
65
|
+
fields: {
|
|
66
|
+
userId: {
|
|
67
|
+
type: "text";
|
|
68
|
+
required: true;
|
|
69
|
+
};
|
|
70
|
+
roles: {
|
|
71
|
+
type: "multiSelect";
|
|
72
|
+
options: string[];
|
|
73
|
+
required: true;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
layout: {
|
|
77
|
+
sections: {
|
|
78
|
+
fields: (string | {
|
|
79
|
+
field: string;
|
|
80
|
+
readOnly: true;
|
|
81
|
+
})[];
|
|
82
|
+
}[];
|
|
83
|
+
};
|
|
84
|
+
submitLabel: string;
|
|
85
|
+
access: {
|
|
86
|
+
roles: readonly string[];
|
|
87
|
+
};
|
|
88
|
+
};
|
|
33
89
|
export declare const memberRolesEditScreen: {
|
|
34
90
|
id: "member-roles-edit";
|
|
35
91
|
type: "actionForm";
|
|
@@ -43,7 +99,7 @@ export declare const memberRolesEditScreen: {
|
|
|
43
99
|
};
|
|
44
100
|
roles: {
|
|
45
101
|
type: "multiSelect";
|
|
46
|
-
options:
|
|
102
|
+
options: string[];
|
|
47
103
|
required: true;
|
|
48
104
|
};
|
|
49
105
|
};
|
package/dist/tenant/screens.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AuthHandlers } from "@cosmicdrift/kumiko-bundled-features/auth-email-password/constants";
|
|
2
|
-
import { access, i18nKey, } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { access, i18nKey, isAssignableByRole, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { DEFAULT_INVITE_ROLE_OPTIONS, INVITE_CREATE_SCREEN_ID, MEMBER_ROLES_CELL_COMPONENT, MEMBER_ROLES_EDIT_SCREEN_ID, MEMBER_STATUS_CELL_COMPONENT, MEMBERS_SCREEN_ID, OWNER_INVITE_ROLE_OPTIONS, TenantHandlers, TenantQueries, } from "./constants.js";
|
|
4
4
|
// Cross-tenant SystemAdmin platform view of the tenants themselves. The tenant
|
|
5
5
|
// feature runs with `r.systemScope()`, so the entityList returns every tenant.
|
|
@@ -138,38 +138,56 @@ export function createMembersScreen(options) {
|
|
|
138
138
|
// only entry point is the drawer button on /members. Only registered by
|
|
139
139
|
// feature.ts when `TenantFeatureOptions.inviteScreen` is set — see
|
|
140
140
|
// createMembersScreen's doc comment above for why.
|
|
141
|
-
export
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
141
|
+
export function createInviteCreateScreen(assignableAppRoles = new Map()) {
|
|
142
|
+
// Admin sees this screen too, so only app roles Admin may grant are offered (fw#2414).
|
|
143
|
+
const appRoleOptions = [...assignableAppRoles]
|
|
144
|
+
.filter(([, assignableFrom]) => isAssignableByRole(assignableFrom, "Admin"))
|
|
145
|
+
.map(([role]) => role);
|
|
146
|
+
return {
|
|
147
|
+
id: INVITE_CREATE_SCREEN_ID,
|
|
148
|
+
type: "actionForm",
|
|
149
|
+
handler: AuthHandlers.inviteCreate,
|
|
150
|
+
fields: {
|
|
151
|
+
email: { type: "text", required: true, format: "email" },
|
|
152
|
+
role: {
|
|
153
|
+
type: "select",
|
|
154
|
+
options: [...DEFAULT_INVITE_ROLE_OPTIONS, ...appRoleOptions],
|
|
155
|
+
required: true,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
layout: {
|
|
159
|
+
sections: [{ fields: ["email", "role"] }],
|
|
160
|
+
},
|
|
161
|
+
submitLabel: i18nKey("tenant.members.invite.submit"),
|
|
162
|
+
access: { roles: access.admin },
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export const inviteCreateScreen = createInviteCreateScreen();
|
|
166
|
+
export function createMemberRolesEditScreen(assignableAppRoles = new Map()) {
|
|
167
|
+
return {
|
|
168
|
+
id: MEMBER_ROLES_EDIT_SCREEN_ID,
|
|
169
|
+
type: "actionForm",
|
|
170
|
+
handler: TenantHandlers.updateMemberRoles,
|
|
171
|
+
redirect: MEMBERS_SCREEN_ID,
|
|
172
|
+
cancelTarget: MEMBERS_SCREEN_ID,
|
|
173
|
+
fields: {
|
|
174
|
+
userId: { type: "text", required: true },
|
|
175
|
+
// Prefilled with the member's current roles, so the option list must be
|
|
176
|
+
// able to represent every assignable rank — DEFAULT_INVITE_ROLE_OPTIONS
|
|
177
|
+
// omits TenantAdmin and would silently strip it on submit. Escalation
|
|
178
|
+
// still stays server-side via findForbiddenRoleAssignment (update-member-roles.write.ts).
|
|
179
|
+
roles: {
|
|
180
|
+
type: "multiSelect",
|
|
181
|
+
options: [...OWNER_INVITE_ROLE_OPTIONS, ...assignableAppRoles.keys()],
|
|
182
|
+
required: true,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
layout: {
|
|
186
|
+
// Prefill userId from rowAction; readOnly so the operator cannot retarget.
|
|
187
|
+
sections: [{ fields: [{ field: "userId", readOnly: true }, "roles"] }],
|
|
188
|
+
},
|
|
189
|
+
submitLabel: i18nKey("tenant.members.roles.edit.submit"),
|
|
190
|
+
access: { roles: access.admin },
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
export const memberRolesEditScreen = createMemberRolesEditScreen();
|
|
@@ -21,21 +21,24 @@ export function createTenantSettingsFeature(opts = {}) {
|
|
|
21
21
|
r.config({ keys: buildTenantSettingsKeys(opts) });
|
|
22
22
|
r.translations({
|
|
23
23
|
keys: {
|
|
24
|
-
"tenant-settings.currency": { en: "Default
|
|
25
|
-
"tenant-settings.locale": { en: "Default
|
|
24
|
+
"tenant-settings.currency": { en: "Default currency" },
|
|
25
|
+
"tenant-settings.locale": { en: "Default locale" },
|
|
26
26
|
// Settings-Hub-derived configEdit screen title (buildConfigFeatureSchema) —
|
|
27
27
|
// required by the i18n boot-validator whenever a feature masks config keys.
|
|
28
|
-
"screen:tenant-settings-system.title": { en: "Tenant
|
|
29
|
-
"screen:tenant-settings-tenant.title": { en: "Tenant
|
|
28
|
+
"screen:tenant-settings-system.title": { en: "Tenant defaults" },
|
|
29
|
+
"screen:tenant-settings-tenant.title": { en: "Tenant settings" },
|
|
30
30
|
// Settings-Hub nav label + configEdit section heading (same key, both
|
|
31
31
|
// scopes fall back here — see buildConfigFeatureSchema).
|
|
32
|
-
"tenant-settings.settings": { en: "Tenant
|
|
32
|
+
"tenant-settings.settings": { en: "Tenant settings" },
|
|
33
|
+
// Section heading below the page title (the page title is the same words as
|
|
34
|
+
// `.settings`, which RenderEdit would drop as a repeat).
|
|
35
|
+
"tenant-settings.settings.section": { en: "Currency and language" },
|
|
33
36
|
// Both currency/locale are tenant-home with admin write access, which
|
|
34
37
|
// cascades a SystemAdmin-only "set the platform default" screen up to
|
|
35
38
|
// the system audience — scoped override so its nav entry reads
|
|
36
39
|
// differently from the tenant-home entry instead of repeating the
|
|
37
40
|
// same words under both "Platform" and "Organization".
|
|
38
|
-
"tenant-settings.settings.system": { en: "Tenant
|
|
41
|
+
"tenant-settings.settings.system": { en: "Tenant defaults" },
|
|
39
42
|
},
|
|
40
43
|
});
|
|
41
44
|
});
|
|
@@ -9,6 +9,7 @@ export declare const tierAssignmentEntity: import("@cosmicdrift/kumiko-types/fie
|
|
|
9
9
|
readonly filterable?: boolean;
|
|
10
10
|
readonly encrypted?: boolean;
|
|
11
11
|
readonly sensitive?: boolean;
|
|
12
|
+
readonly writeOnly?: boolean;
|
|
12
13
|
readonly readAsInstruction?: boolean;
|
|
13
14
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
14
15
|
readonly default?: string;
|
|
@@ -29,6 +30,7 @@ export declare const tierAssignmentEntity: import("@cosmicdrift/kumiko-types/fie
|
|
|
29
30
|
readonly filterable?: boolean;
|
|
30
31
|
readonly encrypted?: boolean;
|
|
31
32
|
readonly sensitive?: boolean;
|
|
33
|
+
readonly writeOnly?: boolean;
|
|
32
34
|
readonly readAsInstruction?: boolean;
|
|
33
35
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
34
36
|
readonly default?: string;
|
|
@@ -17,6 +17,7 @@ export declare function createTierResolver<TTier extends string, TCaps>(deps: Ti
|
|
|
17
17
|
readonly filterable?: boolean;
|
|
18
18
|
readonly encrypted?: boolean;
|
|
19
19
|
readonly sensitive?: boolean;
|
|
20
|
+
readonly writeOnly?: boolean;
|
|
20
21
|
readonly readAsInstruction?: boolean;
|
|
21
22
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
22
23
|
readonly default?: string;
|
|
@@ -37,6 +38,7 @@ export declare function createTierResolver<TTier extends string, TCaps>(deps: Ti
|
|
|
37
38
|
readonly filterable?: boolean;
|
|
38
39
|
readonly encrypted?: boolean;
|
|
39
40
|
readonly sensitive?: boolean;
|
|
41
|
+
readonly writeOnly?: boolean;
|
|
40
42
|
readonly readAsInstruction?: boolean;
|
|
41
43
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
42
44
|
readonly default?: string;
|
|
@@ -38,6 +38,7 @@ export declare const userEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
38
38
|
readonly filterable?: boolean;
|
|
39
39
|
readonly encrypted?: boolean;
|
|
40
40
|
readonly sensitive?: boolean;
|
|
41
|
+
readonly writeOnly?: boolean;
|
|
41
42
|
readonly readAsInstruction?: boolean;
|
|
42
43
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
43
44
|
readonly default?: string;
|
|
@@ -58,6 +59,7 @@ export declare const userEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
58
59
|
readonly filterable?: boolean;
|
|
59
60
|
readonly encrypted?: boolean;
|
|
60
61
|
readonly sensitive?: boolean;
|
|
62
|
+
readonly writeOnly?: boolean;
|
|
61
63
|
readonly readAsInstruction?: boolean;
|
|
62
64
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
63
65
|
readonly default?: string;
|
|
@@ -78,6 +80,7 @@ export declare const userEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
78
80
|
readonly filterable?: boolean;
|
|
79
81
|
readonly encrypted?: boolean;
|
|
80
82
|
readonly sensitive?: boolean;
|
|
83
|
+
readonly writeOnly?: boolean;
|
|
81
84
|
readonly readAsInstruction?: boolean;
|
|
82
85
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
83
86
|
readonly default?: string;
|
|
@@ -98,6 +101,7 @@ export declare const userEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
98
101
|
readonly filterable?: boolean;
|
|
99
102
|
readonly encrypted?: boolean;
|
|
100
103
|
readonly sensitive?: boolean;
|
|
104
|
+
readonly writeOnly?: boolean;
|
|
101
105
|
readonly readAsInstruction?: boolean;
|
|
102
106
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
103
107
|
readonly default?: string;
|
|
@@ -127,6 +131,7 @@ export declare const userEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
127
131
|
readonly filterable?: boolean;
|
|
128
132
|
readonly encrypted?: boolean;
|
|
129
133
|
readonly sensitive?: boolean;
|
|
134
|
+
readonly writeOnly?: boolean;
|
|
130
135
|
readonly readAsInstruction?: boolean;
|
|
131
136
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
132
137
|
readonly default?: string;
|
|
@@ -159,7 +164,7 @@ export declare const userEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
159
164
|
readonly restricted?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
|
|
160
165
|
} | undefined;
|
|
161
166
|
readonly optionsQuery?: string;
|
|
162
|
-
readonly optionsQueryPayload?:
|
|
167
|
+
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
163
168
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
164
169
|
required: true;
|
|
165
170
|
};
|
|
@@ -188,6 +193,7 @@ export declare const userEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
188
193
|
readonly filterable?: boolean;
|
|
189
194
|
readonly encrypted?: boolean;
|
|
190
195
|
readonly sensitive?: boolean;
|
|
196
|
+
readonly writeOnly?: boolean;
|
|
191
197
|
readonly readAsInstruction?: boolean;
|
|
192
198
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
193
199
|
readonly default?: string;
|
|
@@ -210,6 +216,7 @@ export declare const userTable: import("@cosmicdrift/kumiko-framework/db").Entit
|
|
|
210
216
|
readonly filterable?: boolean;
|
|
211
217
|
readonly encrypted?: boolean;
|
|
212
218
|
readonly sensitive?: boolean;
|
|
219
|
+
readonly writeOnly?: boolean;
|
|
213
220
|
readonly readAsInstruction?: boolean;
|
|
214
221
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
215
222
|
readonly default?: string;
|
|
@@ -230,6 +237,7 @@ export declare const userTable: import("@cosmicdrift/kumiko-framework/db").Entit
|
|
|
230
237
|
readonly filterable?: boolean;
|
|
231
238
|
readonly encrypted?: boolean;
|
|
232
239
|
readonly sensitive?: boolean;
|
|
240
|
+
readonly writeOnly?: boolean;
|
|
233
241
|
readonly readAsInstruction?: boolean;
|
|
234
242
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
235
243
|
readonly default?: string;
|
|
@@ -250,6 +258,7 @@ export declare const userTable: import("@cosmicdrift/kumiko-framework/db").Entit
|
|
|
250
258
|
readonly filterable?: boolean;
|
|
251
259
|
readonly encrypted?: boolean;
|
|
252
260
|
readonly sensitive?: boolean;
|
|
261
|
+
readonly writeOnly?: boolean;
|
|
253
262
|
readonly readAsInstruction?: boolean;
|
|
254
263
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
255
264
|
readonly default?: string;
|
|
@@ -270,6 +279,7 @@ export declare const userTable: import("@cosmicdrift/kumiko-framework/db").Entit
|
|
|
270
279
|
readonly filterable?: boolean;
|
|
271
280
|
readonly encrypted?: boolean;
|
|
272
281
|
readonly sensitive?: boolean;
|
|
282
|
+
readonly writeOnly?: boolean;
|
|
273
283
|
readonly readAsInstruction?: boolean;
|
|
274
284
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
275
285
|
readonly default?: string;
|
|
@@ -299,6 +309,7 @@ export declare const userTable: import("@cosmicdrift/kumiko-framework/db").Entit
|
|
|
299
309
|
readonly filterable?: boolean;
|
|
300
310
|
readonly encrypted?: boolean;
|
|
301
311
|
readonly sensitive?: boolean;
|
|
312
|
+
readonly writeOnly?: boolean;
|
|
302
313
|
readonly readAsInstruction?: boolean;
|
|
303
314
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
304
315
|
readonly default?: string;
|
|
@@ -331,7 +342,7 @@ export declare const userTable: import("@cosmicdrift/kumiko-framework/db").Entit
|
|
|
331
342
|
readonly restricted?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
|
|
332
343
|
} | undefined;
|
|
333
344
|
readonly optionsQuery?: string;
|
|
334
|
-
readonly optionsQueryPayload?:
|
|
345
|
+
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
335
346
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
336
347
|
required: true;
|
|
337
348
|
};
|
|
@@ -360,6 +371,7 @@ export declare const userTable: import("@cosmicdrift/kumiko-framework/db").Entit
|
|
|
360
371
|
readonly filterable?: boolean;
|
|
361
372
|
readonly encrypted?: boolean;
|
|
362
373
|
readonly sensitive?: boolean;
|
|
374
|
+
readonly writeOnly?: boolean;
|
|
363
375
|
readonly readAsInstruction?: boolean;
|
|
364
376
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
365
377
|
readonly default?: string;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
23
23
|
import { configuredPiiSubjectKms, decryptPiiFieldValues, isPiiCiphertext, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
24
24
|
import { collectEncryptedFieldNames, configuredEntityFieldEncryption, createTenantDb, decryptEntityFieldValues, } from "@cosmicdrift/kumiko-framework/db";
|
|
25
|
-
import { EXT_USER_DATA, extensionUsageEscapeHatchReason, } from "@cosmicdrift/kumiko-framework/engine";
|
|
25
|
+
import { EXT_USER_DATA, extensionUsageEscapeHatchReason, maskWriteOnlyFields, } from "@cosmicdrift/kumiko-framework/engine";
|
|
26
26
|
import { createEscapeHatchReporter } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
27
27
|
import { tenantMembershipsTable } from "../tenant/index.js";
|
|
28
28
|
import { buildFileRefZipPath } from "./zip-path.js";
|
|
@@ -214,7 +214,11 @@ async function decryptSnippetFields(registry, hookEntityName, snippet) {
|
|
|
214
214
|
const entity = registry.getEntity(snippet.entity) ?? registry.getEntity(hookEntityName);
|
|
215
215
|
const encryptedFields = entity ? collectEncryptedFieldNames(entity) : new Set();
|
|
216
216
|
const kms = configuredPiiSubjectKms();
|
|
217
|
-
const
|
|
217
|
+
const decryptedRows = await decryptRecords(snippet.rows, encryptedFields, kms);
|
|
218
|
+
// Decrypting would otherwise hand writeOnly secrets out as plaintext.
|
|
219
|
+
const rows = entity
|
|
220
|
+
? decryptedRows.map((row) => maskWriteOnlyFields(entity, row))
|
|
221
|
+
: decryptedRows;
|
|
218
222
|
if (!snippet.fileRefs || snippet.fileRefs.length === 0) {
|
|
219
223
|
return { ...snippet, rows };
|
|
220
224
|
}
|