@antelopejs/interface-dms 0.7.4 → 0.9.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/CHANGELOG.md +176 -0
- package/dist/auth/index.d.ts +3 -3
- package/dist/auth/index.js +11 -9
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/internal/jwt-auth-decorator.d.ts +20 -0
- package/dist/auth/internal/jwt-auth-decorator.js +51 -0
- package/dist/auth/internal/jwt-auth-decorator.js.map +1 -0
- package/dist/auth/internal/request-authenticators.d.ts +12 -0
- package/dist/auth/internal/request-authenticators.js +22 -0
- package/dist/auth/internal/request-authenticators.js.map +1 -1
- package/dist/base/activity-feed.d.ts +6 -6
- package/dist/base/block-registry/types.d.ts +16 -0
- package/dist/base/block-types.d.ts +1 -0
- package/dist/base/block-types.js +1 -0
- package/dist/base/block-types.js.map +1 -1
- package/dist/base/chart-card.d.ts +15 -0
- package/dist/base/chart-card.js +4 -0
- package/dist/base/chart-card.js.map +1 -1
- package/dist/base/chart-schemas.d.ts +26 -26
- package/dist/base/code-block.d.ts +3 -3
- package/dist/base/data-types/compare-types.js +19 -13
- package/dist/base/data-types/compare-types.js.map +1 -1
- package/dist/base/data-types/core.d.ts +11 -0
- package/dist/base/data-types/core.js +14 -1
- package/dist/base/data-types/core.js.map +1 -1
- package/dist/base/data-types/default-types.d.ts +112 -2
- package/dist/base/data-types/default-types.js +90 -19
- package/dist/base/data-types/default-types.js.map +1 -1
- package/dist/base/data-types/field-types.d.ts +10 -4
- package/dist/base/data-types/field-types.js +12 -2
- package/dist/base/data-types/field-types.js.map +1 -1
- package/dist/base/data-types/internal/compare-types.d.ts +3 -0
- package/dist/base/data-types/internal/compare-types.js +7 -0
- package/dist/base/data-types/internal/compare-types.js.map +1 -1
- package/dist/base/empty-state.d.ts +4 -4
- package/dist/base/form-block-schema.d.ts +59 -3
- package/dist/base/form-block-schema.js +12 -2
- package/dist/base/form-block-schema.js.map +1 -1
- package/dist/base/form-schema.d.ts +57 -5
- package/dist/base/form-schema.js +22 -0
- package/dist/base/form-schema.js.map +1 -1
- package/dist/base/form-types.d.ts +82 -13
- package/dist/base/form-types.js +12 -4
- package/dist/base/form-types.js.map +1 -1
- package/dist/base/guard.d.ts +6 -6
- package/dist/base/helpers/archive-mode-helpers.js +6 -2
- package/dist/base/helpers/archive-mode-helpers.js.map +1 -1
- package/dist/base/index.d.ts +1 -0
- package/dist/base/index.js +1 -0
- package/dist/base/index.js.map +1 -1
- package/dist/base/internal/form-schema.js +5 -0
- package/dist/base/internal/form-schema.js.map +1 -1
- package/dist/base/internal/layouts.d.ts +15 -3
- package/dist/base/key-value-list.d.ts +12 -9
- package/dist/base/key-value-list.js +1 -1
- package/dist/base/key-value-list.js.map +1 -1
- package/dist/base/kpi-card.d.ts +39 -5
- package/dist/base/kpi-card.js +18 -6
- package/dist/base/kpi-card.js.map +1 -1
- package/dist/base/layouts.d.ts +24 -1
- package/dist/base/layouts.js.map +1 -1
- package/dist/base/live-toggle.d.ts +11 -0
- package/dist/base/live-toggle.js +8 -1
- package/dist/base/live-toggle.js.map +1 -1
- package/dist/base/page-toolbar.d.ts +158 -0
- package/dist/base/page-toolbar.js +198 -0
- package/dist/base/page-toolbar.js.map +1 -0
- package/dist/base/period-selector.d.ts +9 -2
- package/dist/base/period-selector.js.map +1 -1
- package/dist/base/placeholder.d.ts +2 -2
- package/dist/base/section.d.ts +2 -2
- package/dist/base/stack.d.ts +2 -2
- package/dist/base/stat-group.d.ts +18 -6
- package/dist/base/stat-group.js +9 -0
- package/dist/base/stat-group.js.map +1 -1
- package/dist/base/table-view/column-display.d.ts +9 -5
- package/dist/base/table-view/column-display.js +1 -1
- package/dist/base/table-view/column-display.js.map +1 -1
- package/dist/base/table-view/data-functions.d.ts +26 -7
- package/dist/base/table-view/data-functions.js +10 -6
- package/dist/base/table-view/data-functions.js.map +1 -1
- package/dist/base/table-view/factory.js +24 -13
- package/dist/base/table-view/factory.js.map +1 -1
- package/dist/base/table-view/internal/auth.d.ts +2 -0
- package/dist/base/table-view/internal/auth.js +3 -1
- package/dist/base/table-view/internal/auth.js.map +1 -1
- package/dist/base/table-view/internal/column-conditions.d.ts +15 -0
- package/dist/base/table-view/internal/column-conditions.js +94 -0
- package/dist/base/table-view/internal/column-conditions.js.map +1 -0
- package/dist/base/table-view/internal/factory-helpers.d.ts +5 -0
- package/dist/base/table-view/internal/factory-helpers.js +55 -11
- package/dist/base/table-view/internal/factory-helpers.js.map +1 -1
- package/dist/base/table-view/internal/guards.js +19 -2
- package/dist/base/table-view/internal/guards.js.map +1 -1
- package/dist/base/table-view/internal/realtime.js +17 -0
- package/dist/base/table-view/internal/realtime.js.map +1 -1
- package/dist/base/table-view/internal/resource-form.js +1 -0
- package/dist/base/table-view/internal/resource-form.js.map +1 -1
- package/dist/base/table-view/internal/row-actions-schema.d.ts +296 -0
- package/dist/base/table-view/internal/row-actions-schema.js +62 -0
- package/dist/base/table-view/internal/row-actions-schema.js.map +1 -0
- package/dist/base/table-view/internal/validation.d.ts +22 -3
- package/dist/base/table-view/internal/validation.js +92 -2
- package/dist/base/table-view/internal/validation.js.map +1 -1
- package/dist/base/table-view/meta.d.ts +25 -1
- package/dist/base/table-view/meta.js +36 -4
- package/dist/base/table-view/meta.js.map +1 -1
- package/dist/base/table-view/options.d.ts +92 -16
- package/dist/base/table-view/options.js.map +1 -1
- package/dist/base/table-view/realtime.d.ts +8 -0
- package/dist/base/table-view/realtime.js.map +1 -1
- package/dist/base/table-view/routes.js +8 -4
- package/dist/base/table-view/routes.js.map +1 -1
- package/dist/base/table-view/schema.d.ts +36 -30
- package/dist/base/table-view/schema.js +11 -57
- package/dist/base/table-view/schema.js.map +1 -1
- package/dist/base/table-view/source.d.ts +1 -1
- package/dist/base/table-view/source.js +4 -1
- package/dist/base/table-view/source.js.map +1 -1
- package/dist/base/table-view.d.ts +2 -2
- package/dist/base/table-view.js.map +1 -1
- package/dist/base/top-list-card.d.ts +5 -5
- package/dist/base/types/action-target.d.ts +77 -20
- package/dist/base/types/confirm-dialog.d.ts +5 -1
- package/dist/base/types/custom-button.d.ts +5 -3
- package/dist/base/types/field-config.d.ts +4 -4
- package/dist/base/types/guards.d.ts +10 -0
- package/dist/base/types/row-action.d.ts +6 -1
- package/dist/base/types/size.d.ts +3 -1
- package/dist/client-ip.d.ts +6 -2
- package/dist/client-ip.js +4 -2
- package/dist/client-ip.js.map +1 -1
- package/dist/component.d.ts +14 -0
- package/dist/component.js.map +1 -1
- package/dist/data-controllers/members.d.ts +0 -3
- package/dist/data-controllers/members.js +30 -8
- package/dist/data-controllers/members.js.map +1 -1
- package/dist/db/internal/tenantLifecycle.model.js +5 -2
- package/dist/db/internal/tenantLifecycle.model.js.map +1 -1
- package/dist/guards.js +2 -3
- package/dist/guards.js.map +1 -1
- package/dist/hooks.d.ts +54 -10
- package/dist/hooks.js +12 -4
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/invite-membership.d.ts +9 -0
- package/dist/internal/invite-membership.js +25 -7
- package/dist/internal/invite-membership.js.map +1 -1
- package/dist/internal/member-changes.d.ts +24 -0
- package/dist/internal/member-changes.js +66 -0
- package/dist/internal/member-changes.js.map +1 -0
- package/dist/internal/tenant-ownership.d.ts +4 -1
- package/dist/internal/tenant-ownership.js +4 -10
- package/dist/internal/tenant-ownership.js.map +1 -1
- package/dist/invite-extensions/internal/form-slot.js +1 -1
- package/dist/invite-extensions/internal/form-slot.js.map +1 -1
- package/dist/invite-extensions.d.ts +0 -9
- package/dist/invite-extensions.js +1 -36
- package/dist/invite-extensions.js.map +1 -1
- package/dist/invite-resolution.js +6 -2
- package/dist/invite-resolution.js.map +1 -1
- package/dist/invites.js +36 -22
- package/dist/invites.js.map +1 -1
- package/dist/layout-banners.d.ts +40 -4
- package/dist/layout-banners.js +25 -3
- package/dist/layout-banners.js.map +1 -1
- package/dist/notifications/internal.d.ts +2 -2
- package/dist/notifications/internal.js.map +1 -1
- package/dist/notifications/sendable.d.ts +3 -2
- package/dist/notifications/sendable.js +2 -1
- package/dist/notifications/sendable.js.map +1 -1
- package/dist/notifications/types.d.ts +9 -0
- package/dist/page/controllers.d.ts +44 -0
- package/dist/page/controllers.js +14 -1
- package/dist/page/controllers.js.map +1 -1
- package/dist/page/internal/layout-filter.d.ts +10 -4
- package/dist/page/internal/layout-filter.js +27 -14
- package/dist/page/internal/layout-filter.js.map +1 -1
- package/dist/page/internal/metadata-helpers.d.ts +7 -0
- package/dist/page/internal/metadata-helpers.js +13 -2
- package/dist/page/internal/metadata-helpers.js.map +1 -1
- package/dist/page/internal/page-record.d.ts +34 -0
- package/dist/page/internal/page-record.js +87 -0
- package/dist/page/internal/page-record.js.map +1 -0
- package/dist/page/internal/page-registration.d.ts +2 -0
- package/dist/page/internal/page-registration.js.map +1 -1
- package/dist/page/layout-filter.js +31 -10
- package/dist/page/layout-filter.js.map +1 -1
- package/dist/page/metadata.js +36 -26
- package/dist/page/metadata.js.map +1 -1
- package/dist/page/types.d.ts +39 -4
- package/dist/page/types.js.map +1 -1
- package/dist/page.d.ts +1 -1
- package/dist/page.js +2 -1
- package/dist/page.js.map +1 -1
- package/dist/permissions-resolver.d.ts +26 -3
- package/dist/permissions-resolver.js +2 -1
- package/dist/permissions-resolver.js.map +1 -1
- package/dist/permissions.d.ts +7 -3
- package/dist/permissions.js +8 -6
- package/dist/permissions.js.map +1 -1
- package/dist/realtime.d.ts +24 -1
- package/dist/realtime.js +7 -1
- package/dist/realtime.js.map +1 -1
- package/dist/request-tenant.d.ts +17 -13
- package/dist/request-tenant.js +54 -42
- package/dist/request-tenant.js.map +1 -1
- package/dist/tenant-members.d.ts +26 -0
- package/dist/tenant-members.js +29 -0
- package/dist/tenant-members.js.map +1 -0
- package/dist/tenant-ownership.d.ts +4 -1
- package/dist/tenant-ownership.js +12 -17
- package/dist/tenant-ownership.js.map +1 -1
- package/dist/tenant-provisioning.d.ts +15 -0
- package/dist/tenant-provisioning.js +27 -0
- package/dist/tenant-provisioning.js.map +1 -0
- package/dist/tenant-scoped-model.d.ts +2 -1
- package/dist/tenant-scoped-model.js +4 -3
- package/dist/tenant-scoped-model.js.map +1 -1
- package/docs/1.core/10.layout-banners.md +57 -2
- package/docs/1.core/2.pages-and-modules.md +20 -11
- package/docs/1.core/4.permissions.md +34 -1
- package/docs/1.core/5.tenancy.md +37 -6
- package/docs/1.core/7.hooks.md +24 -4
- package/docs/1.core/8.realtime.md +24 -3
- package/docs/2.auth/2.authentication.md +3 -3
- package/docs/3.base/1.introduction.md +1 -0
- package/docs/3.base/10.display-blocks.md +20 -2
- package/docs/3.base/2.types.md +7 -5
- package/docs/3.base/3.forms.md +28 -8
- package/docs/3.base/4.tables.md +27 -9
- package/docs/3.base/5.charts-and-widgets.md +8 -4
- package/docs/3.base/6.layout.md +47 -1
- package/docs/3.base/8.data-types.md +16 -9
- package/docs/4.notifications/3.sending.md +4 -3
- package/docs/5.html-render/1.introduction.md +5 -7
- package/package.json +7 -11
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
import { RegisteringProxy } from "@antelopejs/interface-core";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* A role preview a resolver call computes the set for (Settings › Roles ›
|
|
4
|
+
* Preview as role), instead of a real member's.
|
|
5
|
+
*/
|
|
6
|
+
export interface PermissionsResolverPreview {
|
|
7
|
+
/** The previewed role's permissions, before any resolver reshaped them. */
|
|
8
|
+
rolePermissions: ReadonlySet<string>;
|
|
9
|
+
}
|
|
10
|
+
/** What a resolver call is for, besides the user and the tenant. */
|
|
11
|
+
export interface PermissionsResolverContext {
|
|
12
|
+
/**
|
|
13
|
+
* Set when the call previews a role. `userId` is then the viewer's, but the
|
|
14
|
+
* set is the previewed role's: a resolver keyed on the user (an owner
|
|
15
|
+
* handed more, a screen kept for owners) must shape it as for an ordinary
|
|
16
|
+
* member holding only that role, never from the viewer's own standing.
|
|
17
|
+
*/
|
|
18
|
+
preview?: PermissionsResolverPreview;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Reshape a user's permission set for a tenant. `context` says what the set is
|
|
22
|
+
* computed for: always passed, `{}` for a real member.
|
|
23
|
+
*/
|
|
24
|
+
export type PermissionsResolverFn = (userId: string, tenantId: string, currentPermissions: Set<string>, context: PermissionsResolverContext) => Promise<Set<string>> | Set<string>;
|
|
3
25
|
export interface PermissionsResolverInfo {
|
|
4
26
|
id: string;
|
|
5
27
|
resolver: PermissionsResolverFn;
|
|
@@ -31,6 +53,7 @@ export declare function RegisterPermissionsResolver(info: PermissionsResolverInf
|
|
|
31
53
|
/**
|
|
32
54
|
* Run the registered resolvers over a base permission set and return the
|
|
33
55
|
* effective set. Prefer `GetEffectiveUserPermissions` from `dms/permissions`,
|
|
34
|
-
* which composes the base set computation with this pipeline.
|
|
56
|
+
* which composes the base set computation with this pipeline. `context` is
|
|
57
|
+
* handed to every resolver as is.
|
|
35
58
|
*/
|
|
36
|
-
export declare const ApplyPermissionsResolvers: (userId: string, tenantId: string, basePermissions: Set<string
|
|
59
|
+
export declare const ApplyPermissionsResolvers: (userId: string, tenantId: string, basePermissions: Set<string>, context: PermissionsResolverContext) => Promise<Set<string>>;
|
|
@@ -32,7 +32,8 @@ function RegisterPermissionsResolver(info) {
|
|
|
32
32
|
/**
|
|
33
33
|
* Run the registered resolvers over a base permission set and return the
|
|
34
34
|
* effective set. Prefer `GetEffectiveUserPermissions` from `dms/permissions`,
|
|
35
|
-
* which composes the base set computation with this pipeline.
|
|
35
|
+
* which composes the base set computation with this pipeline. `context` is
|
|
36
|
+
* handed to every resolver as is.
|
|
36
37
|
*/
|
|
37
38
|
exports.ApplyPermissionsResolvers = (0, interface_core_1.InterfaceFunction)();
|
|
38
39
|
//# sourceMappingURL=permissions-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions-resolver.js","sourceRoot":"","sources":["../src/permissions-resolver.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"permissions-resolver.js","sourceRoot":"","sources":["../src/permissions-resolver.ts"],"names":[],"mappings":";;;AAmEA,kEAIC;AAvED,+DAGoC;AAuCpC,gBAAgB;AAChB,IAAiB,QAAQ,CAIxB;AAJD,WAAiB,QAAQ;IACV,oCAA2B,GAAG,IAAI,iCAAgB,EAE5D,CAAC;AACN,CAAC,EAJgB,QAAQ,wBAAR,QAAQ,QAIxB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,2BAA2B,CACzC,IAA6B;IAE7B,QAAQ,CAAC,2BAA2B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACU,QAAA,yBAAyB,GACpC,IAAA,kCAAiB,GAOd,CAAC"}
|
package/dist/permissions.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RegisteringProxy } from "@antelopejs/interface-core";
|
|
2
2
|
import type { RoleModel } from "./db";
|
|
3
|
+
import { type PermissionsResolverContext } from "./permissions-resolver";
|
|
3
4
|
export interface Permission {
|
|
4
5
|
id: string;
|
|
5
6
|
title: string;
|
|
@@ -54,17 +55,20 @@ export declare function GetUserPermissions(user: {
|
|
|
54
55
|
* (`ApplyPermissionsResolvers`): the dms module wires it in `construct()`.
|
|
55
56
|
* In standalone contexts (unit tests, thin consumers) connect it manually
|
|
56
57
|
* with `ImplementInterface`, otherwise the call queues until wired.
|
|
58
|
+
*
|
|
59
|
+
* `context` is handed to the resolvers: `{}` for the user's own set, `preview`
|
|
60
|
+
* when the set is a role previewed by that user.
|
|
57
61
|
*/
|
|
58
62
|
export declare function GetEffectiveUserPermissions(user: {
|
|
59
63
|
_id: string;
|
|
60
64
|
owner?: boolean;
|
|
61
|
-
}, tenantId: string, roleIds: string[], roleModel: RoleModel): Promise<Set<string>>;
|
|
65
|
+
}, tenantId: string, roleIds: string[], roleModel: RoleModel, context?: PermissionsResolverContext): Promise<Set<string>>;
|
|
62
66
|
/**
|
|
63
67
|
* Whether `permissions` grants `permissionId`: on the `*` wildcard, on a
|
|
64
68
|
* `defaultGranted` permission, or on a direct grant whose ancestors (the ids
|
|
65
69
|
* it sits under) and `dependencies` are held too — a table's delete action
|
|
66
|
-
* grants nothing without its table and its
|
|
67
|
-
* the view that loads the row.
|
|
70
|
+
* grants nothing without its table, its page and its list, its edit nothing
|
|
71
|
+
* without the view that loads the row.
|
|
68
72
|
*/
|
|
69
73
|
export declare function HasPermission(permissions: Set<string>, permissionId: string): Promise<boolean>;
|
|
70
74
|
/** Whether `permissions` grants at least one of `permissionIds`. */
|
package/dist/permissions.js
CHANGED
|
@@ -76,17 +76,20 @@ async function GetUserPermissions(user, roleIds, roleModel) {
|
|
|
76
76
|
* (`ApplyPermissionsResolvers`): the dms module wires it in `construct()`.
|
|
77
77
|
* In standalone contexts (unit tests, thin consumers) connect it manually
|
|
78
78
|
* with `ImplementInterface`, otherwise the call queues until wired.
|
|
79
|
+
*
|
|
80
|
+
* `context` is handed to the resolvers: `{}` for the user's own set, `preview`
|
|
81
|
+
* when the set is a role previewed by that user.
|
|
79
82
|
*/
|
|
80
|
-
async function GetEffectiveUserPermissions(user, tenantId, roleIds, roleModel) {
|
|
83
|
+
async function GetEffectiveUserPermissions(user, tenantId, roleIds, roleModel, context = {}) {
|
|
81
84
|
const basePermissions = await GetUserPermissions(user, roleIds, roleModel);
|
|
82
|
-
return (0, permissions_resolver_1.ApplyPermissionsResolvers)(user._id, tenantId, basePermissions);
|
|
85
|
+
return (0, permissions_resolver_1.ApplyPermissionsResolvers)(user._id, tenantId, basePermissions, context);
|
|
83
86
|
}
|
|
84
87
|
/**
|
|
85
88
|
* Whether `permissions` grants `permissionId`: on the `*` wildcard, on a
|
|
86
89
|
* `defaultGranted` permission, or on a direct grant whose ancestors (the ids
|
|
87
90
|
* it sits under) and `dependencies` are held too — a table's delete action
|
|
88
|
-
* grants nothing without its table and its
|
|
89
|
-
* the view that loads the row.
|
|
91
|
+
* grants nothing without its table, its page and its list, its edit nothing
|
|
92
|
+
* without the view that loads the row.
|
|
90
93
|
*/
|
|
91
94
|
async function HasPermission(permissions, permissionId) {
|
|
92
95
|
return grantsPermission(permissions, permissionId, new Set());
|
|
@@ -111,8 +114,7 @@ async function grantsPermission(permissions, permissionId, checked) {
|
|
|
111
114
|
return ((await holdsAncestors(permissions, permissionId)) &&
|
|
112
115
|
holdsDependencies(permissions, permission, checked));
|
|
113
116
|
}
|
|
114
|
-
// The role routes store a grant with every id it sits under
|
|
115
|
-
// before they did, or a set a resolver reshaped, may lack some. An ancestor
|
|
117
|
+
// The role routes store a grant with every id it sits under. An ancestor
|
|
116
118
|
// counts as held when granted, `defaultGranted`, or not a registered
|
|
117
119
|
// permission at all (a page declaring `permission: { id: "mailing.access" }`
|
|
118
120
|
// has no `mailing` above it).
|
package/dist/permissions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"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"}
|
package/dist/realtime.d.ts
CHANGED
|
@@ -2,6 +2,17 @@ import { RegisteringProxy } from "@antelopejs/interface-core";
|
|
|
2
2
|
export interface PublishMessageOptions {
|
|
3
3
|
payload?: Record<string, unknown>;
|
|
4
4
|
actorId?: string;
|
|
5
|
+
/**
|
|
6
|
+
* The tenant (workspace) the message is about. A message published with it
|
|
7
|
+
* reaches only the page sessions of that tenant; without it, the message is
|
|
8
|
+
* global and reaches every session subscribed to the topic, whatever their
|
|
9
|
+
* tenant.
|
|
10
|
+
*
|
|
11
|
+
* Pass it whenever the topic carries one workspace's data — a row changed, a
|
|
12
|
+
* send finished, a run completed — so the other workspaces' pages neither
|
|
13
|
+
* refetch nor count the message as missed.
|
|
14
|
+
*/
|
|
15
|
+
tenantId?: string;
|
|
5
16
|
}
|
|
6
17
|
/** One message delivered to a {@link SubscribeMessage} handler. */
|
|
7
18
|
export interface RealtimeMessage {
|
|
@@ -9,6 +20,12 @@ export interface RealtimeMessage {
|
|
|
9
20
|
type: string;
|
|
10
21
|
payload?: Record<string, unknown>;
|
|
11
22
|
actorId?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The tenant the message was published for, absent on a global message. A
|
|
25
|
+
* {@link SubscribeMessage} handler receives the messages of every tenant
|
|
26
|
+
* and filters on this field itself when it serves one.
|
|
27
|
+
*/
|
|
28
|
+
tenantId?: string;
|
|
12
29
|
ts: number;
|
|
13
30
|
}
|
|
14
31
|
export type RealtimeMessageHandler = (message: RealtimeMessage) => void;
|
|
@@ -29,9 +46,15 @@ export declare namespace internal {
|
|
|
29
46
|
* module is unloaded, and it outlives a reload of the DMS module.
|
|
30
47
|
*/
|
|
31
48
|
export declare const RegisterPageTopic: (pageId: string, topic: string) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Publish a message on `topic`. The page sessions bound to the topic refetch
|
|
51
|
+
* on it; with `options.tenantId` only those of that tenant do, without it the
|
|
52
|
+
* message is global.
|
|
53
|
+
*/
|
|
32
54
|
export declare const PublishMessage: (topic: string, type: string, options?: PublishMessageOptions | undefined) => Promise<void>;
|
|
33
55
|
/**
|
|
34
|
-
* Receive every message published on `topic`, whichever instance published it
|
|
56
|
+
* Receive every message published on `topic`, whichever instance published it
|
|
57
|
+
* and whichever tenant it names (see {@link RealtimeMessage.tenantId}):
|
|
35
58
|
* the subscription rides the same broker as {@link PublishMessage}, so what one
|
|
36
59
|
* instance publishes reaches the subscribers of every other.
|
|
37
60
|
*
|
package/dist/realtime.js
CHANGED
|
@@ -29,9 +29,15 @@ const RegisterPageTopic = (pageId, topic) => {
|
|
|
29
29
|
internal.RegisterPageTopic.register(pageTopicId(pageId, topic), pageId, topic);
|
|
30
30
|
};
|
|
31
31
|
exports.RegisterPageTopic = RegisterPageTopic;
|
|
32
|
+
/**
|
|
33
|
+
* Publish a message on `topic`. The page sessions bound to the topic refetch
|
|
34
|
+
* on it; with `options.tenantId` only those of that tenant do, without it the
|
|
35
|
+
* message is global.
|
|
36
|
+
*/
|
|
32
37
|
exports.PublishMessage = (0, interface_core_1.InterfaceFunction)();
|
|
33
38
|
/**
|
|
34
|
-
* Receive every message published on `topic`, whichever instance published it
|
|
39
|
+
* Receive every message published on `topic`, whichever instance published it
|
|
40
|
+
* and whichever tenant it names (see {@link RealtimeMessage.tenantId}):
|
|
35
41
|
* the subscription rides the same broker as {@link PublishMessage}, so what one
|
|
36
42
|
* instance publishes reaches the subscribers of every other.
|
|
37
43
|
*
|
package/dist/realtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.js","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"realtime.js","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":";;;AA6GA,4CAOC;AApHD,6CAAyC;AACzC,+DAGoC;AAsCpC;;GAEG;AACH,IAAiB,QAAQ,CAQxB;AARD,WAAiB,QAAQ;IACV,0BAAiB,GAAG,IAAI,iCAAgB,EAElD,CAAC;IAES,yBAAgB,GAAG,IAAI,iCAAgB,EAEjD,CAAC;AACN,CAAC,EARgB,QAAQ,wBAAR,QAAQ,QAQxB;AAED,+EAA+E;AAC/E,2EAA2E;AAC3E,0CAA0C;AAC1C,SAAS,WAAW,CAAC,MAAc,EAAE,KAAa;IAChD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACI,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAE,KAAa,EAAQ,EAAE;IACvE,QAAQ,CAAC,iBAAiB,CAAC,QAAQ,CACjC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAC1B,MAAM,EACN,KAAK,CACN,CAAC;AACJ,CAAC,CAAC;AANW,QAAA,iBAAiB,qBAM5B;AAEF;;;;GAIG;AACU,QAAA,cAAc,GACzB,IAAA,kCAAiB,GAMd,CAAC;AAEN;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,gBAAgB,CAC9B,KAAa,EACb,OAA+B;IAE/B,MAAM,EAAE,GAAG,IAAA,wBAAU,GAAE,CAAC;IACxB,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACvD,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC"}
|
package/dist/request-tenant.d.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import type { RequestContext } from "@antelopejs/interface-api";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* The tenant of the request's verified credential: the one bound by the DMS
|
|
4
|
+
* auth decorators (`AuthUser`, `AuthUserWithPermission`, `IfAuthUser` with a
|
|
5
|
+
* valid token…), the tenant guards or `authenticateRequestPrincipal`.
|
|
6
|
+
* Without a verified credential, `DEFAULT_TENANT_ID`: a token is never read
|
|
7
|
+
* for its tenant before its signature, user and session are checked.
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* gating performed by `PageController`) — those validators verify the signature
|
|
11
|
-
* before this function runs, so the decoded `tenantId` is authentic.
|
|
9
|
+
* Call it once the route's auth decorator has run (in the handler). A
|
|
10
|
+
* parameter or property provider resolved alongside the auth decorator uses
|
|
11
|
+
* {@link resolveRequestTenantId} instead.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* Do NOT introduce new routes that rely on `tenantId` for authorization without
|
|
17
|
-
* upstream auth verification — without signature checks, the claim is forgeable.
|
|
13
|
+
* @throws HTTPResult 401 when the request's authentication failed or its
|
|
14
|
+
* credential changed since
|
|
18
15
|
*/
|
|
19
16
|
export declare function getRequestTenantId(ctx: RequestContext): string;
|
|
17
|
+
/**
|
|
18
|
+
* {@link getRequestTenantId} for a provider that may run before the route's
|
|
19
|
+
* auth decorator (`TenantScopedModel`, a tenant-scoped `Model`): a bearer
|
|
20
|
+
* token not yet verified is verified here, and its tenant bound to the
|
|
21
|
+
* request. An invalid token reads as anonymous: `DEFAULT_TENANT_ID`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveRequestTenantId(ctx: RequestContext): Promise<string>;
|
package/dist/request-tenant.js
CHANGED
|
@@ -1,58 +1,70 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getRequestTenantId = getRequestTenantId;
|
|
4
|
-
|
|
4
|
+
exports.resolveRequestTenantId = resolveRequestTenantId;
|
|
5
|
+
const auth_1 = require("./auth");
|
|
5
6
|
const request_authenticators_1 = require("./auth/internal/request-authenticators");
|
|
6
7
|
const constants_1 = require("./constants");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const BEARER_SCHEME = /^Bearer\s+(\S+)$/i;
|
|
9
|
+
const pendingResolutions = new WeakMap();
|
|
10
|
+
/**
|
|
11
|
+
* The tenant of the request's verified credential: the one bound by the DMS
|
|
12
|
+
* auth decorators (`AuthUser`, `AuthUserWithPermission`, `IfAuthUser` with a
|
|
13
|
+
* valid token…), the tenant guards or `authenticateRequestPrincipal`.
|
|
14
|
+
* Without a verified credential, `DEFAULT_TENANT_ID`: a token is never read
|
|
15
|
+
* for its tenant before its signature, user and session are checked.
|
|
16
|
+
*
|
|
17
|
+
* Call it once the route's auth decorator has run (in the handler). A
|
|
18
|
+
* parameter or property provider resolved alongside the auth decorator uses
|
|
19
|
+
* {@link resolveRequestTenantId} instead.
|
|
20
|
+
*
|
|
21
|
+
* @throws HTTPResult 401 when the request's authentication failed or its
|
|
22
|
+
* credential changed since
|
|
23
|
+
*/
|
|
24
|
+
function getRequestTenantId(ctx) {
|
|
25
|
+
return (0, request_authenticators_1.getAuthenticatedRequestTenantId)(ctx) ?? constants_1.DEFAULT_TENANT_ID;
|
|
14
26
|
}
|
|
15
|
-
function
|
|
27
|
+
async function verifyRequestTenantId(ctx, token) {
|
|
16
28
|
try {
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
const data = await auth_1.internal.IfAuthUserAuthenticator(token);
|
|
30
|
+
if (!data)
|
|
31
|
+
return constants_1.DEFAULT_TENANT_ID;
|
|
32
|
+
const user = await auth_1.internal.AuthRawUserValidator(data);
|
|
33
|
+
if (!user || typeof user === "boolean")
|
|
34
|
+
return constants_1.DEFAULT_TENANT_ID;
|
|
35
|
+
const tenantId = data.tenantId || constants_1.DEFAULT_TENANT_ID;
|
|
36
|
+
(0, request_authenticators_1.bindVerifiedRequestPrincipal)(ctx, { userId: user._id, tenantId });
|
|
37
|
+
return tenantId;
|
|
23
38
|
}
|
|
24
39
|
catch {
|
|
25
|
-
return
|
|
40
|
+
return constants_1.DEFAULT_TENANT_ID;
|
|
26
41
|
}
|
|
27
|
-
return undefined;
|
|
28
42
|
}
|
|
29
43
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* The legacy value is only *decoded*: this function does NOT verify the
|
|
35
|
-
* JWT signature. It is safe when the request has already been authenticated
|
|
36
|
-
* upstream (auth decorators such as `@AuthUser`, `@AuthTenantMember`, or the
|
|
37
|
-
* gating performed by `PageController`) — those validators verify the signature
|
|
38
|
-
* before this function runs, so the decoded `tenantId` is authentic.
|
|
39
|
-
*
|
|
40
|
-
* For routes that legitimately accept anonymous traffic (e.g. `@IfAuthUser`),
|
|
41
|
-
* the fallback resolves to `DEFAULT_TENANT_ID` so public layouts can be served.
|
|
42
|
-
*
|
|
43
|
-
* Do NOT introduce new routes that rely on `tenantId` for authorization without
|
|
44
|
-
* upstream auth verification — without signature checks, the claim is forgeable.
|
|
44
|
+
* {@link getRequestTenantId} for a provider that may run before the route's
|
|
45
|
+
* auth decorator (`TenantScopedModel`, a tenant-scoped `Model`): a bearer
|
|
46
|
+
* token not yet verified is verified here, and its tenant bound to the
|
|
47
|
+
* request. An invalid token reads as anonymous: `DEFAULT_TENANT_ID`.
|
|
45
48
|
*/
|
|
46
|
-
function
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
return
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
async function resolveRequestTenantId(ctx) {
|
|
50
|
+
const bound = (0, request_authenticators_1.getAuthenticatedRequestTenantId)(ctx);
|
|
51
|
+
if (bound)
|
|
52
|
+
return bound;
|
|
53
|
+
const header = ctx.rawRequest?.headers?.authorization;
|
|
54
|
+
const token = typeof header === "string" ? header.match(BEARER_SCHEME)?.[1] : undefined;
|
|
55
|
+
if (!token)
|
|
56
|
+
return constants_1.DEFAULT_TENANT_ID;
|
|
57
|
+
const request = ctx.rawRequest;
|
|
58
|
+
const pending = pendingResolutions.get(request);
|
|
59
|
+
if (pending)
|
|
60
|
+
return pending;
|
|
61
|
+
const resolution = verifyRequestTenantId(ctx, token);
|
|
62
|
+
pendingResolutions.set(request, resolution);
|
|
63
|
+
try {
|
|
64
|
+
return await resolution;
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
pendingResolutions.delete(request);
|
|
55
68
|
}
|
|
56
|
-
return constants_1.DEFAULT_TENANT_ID;
|
|
57
69
|
}
|
|
58
70
|
//# sourceMappingURL=request-tenant.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-tenant.js","sourceRoot":"","sources":["../src/request-tenant.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"request-tenant.js","sourceRoot":"","sources":["../src/request-tenant.ts"],"names":[],"mappings":";;AA2BA,gDAEC;AAyBD,wDAmBC;AAvED,iCAAkC;AAClC,mFAGgD;AAChD,2CAAgD;AAEhD,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAE1C,MAAM,kBAAkB,GAAG,IAAI,OAAO,EAAoC,CAAC;AAE3E;;;;;;;;;;;;;GAaG;AACH,SAAgB,kBAAkB,CAAC,GAAmB;IACpD,OAAO,IAAA,wDAA+B,EAAC,GAAG,CAAC,IAAI,6BAAiB,CAAC;AACnE,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,GAAmB,EACnB,KAAa;IAEb,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,eAAQ,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI;YAAE,OAAO,6BAAiB,CAAC;QACpC,MAAM,IAAI,GAAG,MAAM,eAAQ,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,SAAS;YAAE,OAAO,6BAAiB,CAAC;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,6BAAiB,CAAC;QACpD,IAAA,qDAA4B,EAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,6BAAiB,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,sBAAsB,CAC1C,GAAmB;IAEnB,MAAM,KAAK,GAAG,IAAA,wDAA+B,EAAC,GAAG,CAAC,CAAC;IACnD,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,aAAa,CAAC;IACtD,MAAM,KAAK,GACT,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAO,6BAAiB,CAAC;IACrC,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrD,kBAAkB,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,MAAM,UAAU,CAAC;IAC1B,CAAC;YAAS,CAAC;QACT,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type MemberChange } from "./hooks";
|
|
2
|
+
/** What one membership or invitation write changes, and the write itself. */
|
|
3
|
+
export interface TenantMembersWrite<T> {
|
|
4
|
+
/**
|
|
5
|
+
* Announced through `Hook.MEMBER_BEING_CHANGED`, in order, before `write`
|
|
6
|
+
* runs. Empty for a write that changes no membership, such as an invitation
|
|
7
|
+
* created, edited or retired.
|
|
8
|
+
*/
|
|
9
|
+
changes: MemberChange[];
|
|
10
|
+
write: () => Promise<T>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The one entry point for writing tenant members and invitations: every
|
|
14
|
+
* insert, update or delete of a `TenantMemberModel` or `UserInviteModel` row
|
|
15
|
+
* goes through it. It admits the write under the tenant's lifecycle (refused
|
|
16
|
+
* while a barrier is held or once the tenant is closed), calls `plan` to read
|
|
17
|
+
* the current state and describe the change, fires `Hook.MEMBER_BEING_CHANGED`
|
|
18
|
+
* for each change (a throwing handler refuses the write, replays included),
|
|
19
|
+
* then runs the write and releases the admission.
|
|
20
|
+
*
|
|
21
|
+
* `plan` runs inside the admission so the change it describes is read from
|
|
22
|
+
* state no paused initiator is validating. Never call this from inside
|
|
23
|
+
* another `changeTenantMembers` or `runTenantLifecycleOperation` callback:
|
|
24
|
+
* each call takes its own admission.
|
|
25
|
+
*/
|
|
26
|
+
export declare function changeTenantMembers<T>(tenantId: string, plan: () => Promise<TenantMembersWrite<T>>): Promise<T>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.changeTenantMembers = changeTenantMembers;
|
|
4
|
+
const hooks_1 = require("./hooks");
|
|
5
|
+
const tenant_lifecycle_1 = require("./tenant-lifecycle");
|
|
6
|
+
/**
|
|
7
|
+
* The one entry point for writing tenant members and invitations: every
|
|
8
|
+
* insert, update or delete of a `TenantMemberModel` or `UserInviteModel` row
|
|
9
|
+
* goes through it. It admits the write under the tenant's lifecycle (refused
|
|
10
|
+
* while a barrier is held or once the tenant is closed), calls `plan` to read
|
|
11
|
+
* the current state and describe the change, fires `Hook.MEMBER_BEING_CHANGED`
|
|
12
|
+
* for each change (a throwing handler refuses the write, replays included),
|
|
13
|
+
* then runs the write and releases the admission.
|
|
14
|
+
*
|
|
15
|
+
* `plan` runs inside the admission so the change it describes is read from
|
|
16
|
+
* state no paused initiator is validating. Never call this from inside
|
|
17
|
+
* another `changeTenantMembers` or `runTenantLifecycleOperation` callback:
|
|
18
|
+
* each call takes its own admission.
|
|
19
|
+
*/
|
|
20
|
+
async function changeTenantMembers(tenantId, plan) {
|
|
21
|
+
return (0, tenant_lifecycle_1.runTenantLifecycleOperation)(tenantId, async () => {
|
|
22
|
+
const { changes, write } = await plan();
|
|
23
|
+
for (const change of changes) {
|
|
24
|
+
await (0, hooks_1.ExecuteHooks)(hooks_1.Hook.MEMBER_BEING_CHANGED, { tenantId, ...change });
|
|
25
|
+
}
|
|
26
|
+
return write();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=tenant-members.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-members.js","sourceRoot":"","sources":["../src/tenant-members.ts"],"names":[],"mappings":";;AA4BA,kDAWC;AAvCD,mCAAgE;AAChE,yDAAiE;AAajE;;;;;;;;;;;;;GAaG;AACI,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAChB,IAA0C;IAE1C,OAAO,IAAA,8CAA2B,EAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;QACxC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAA,oBAAY,EAAC,YAAI,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -6,7 +6,10 @@ export interface TenantMembershipPatch {
|
|
|
6
6
|
/** Durable invite delivery; grants membership without replacing later edits. */
|
|
7
7
|
deliveryId?: string;
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Adds the user to the tenant, or sets the roles and ownership of an existing
|
|
11
|
+
* member, through `changeTenantMembers`.
|
|
12
|
+
*/
|
|
10
13
|
export declare function applyTenantOwnership(userModel: UserModel, userId: string, tenantId: string, patch: TenantMembershipPatch): Promise<void>;
|
|
11
14
|
export declare function syncPlatformOwnerOnTenantOwnerChange(userModel: UserModel, userId: string, tenantId: string, nextIsTenantOwner: boolean): Promise<void>;
|
|
12
15
|
export declare function clearPlatformOwnerOnMemberRemoval(userModel: UserModel, userId: string, tenantId: string, removedMemberWasTenantOwner: boolean): Promise<void>;
|
package/dist/tenant-ownership.js
CHANGED
|
@@ -5,25 +5,20 @@ exports.syncPlatformOwnerOnTenantOwnerChange = syncPlatformOwnerOnTenantOwnerCha
|
|
|
5
5
|
exports.clearPlatformOwnerOnMemberRemoval = clearPlatformOwnerOnMemberRemoval;
|
|
6
6
|
const interface_database_decorators_1 = require("@antelopejs/interface-database-decorators");
|
|
7
7
|
const tenantMembers_model_1 = require("./db/models/tenantMembers.model");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
8
|
+
const tenant_members_1 = require("./tenant-members");
|
|
9
|
+
const member_changes_1 = require("./internal/member-changes");
|
|
10
10
|
const tenant_ownership_1 = require("./internal/tenant-ownership");
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Adds the user to the tenant, or sets the roles and ownership of an existing
|
|
13
|
+
* member, through `changeTenantMembers`.
|
|
14
|
+
*/
|
|
12
15
|
async function applyTenantOwnership(userModel, userId, tenantId, patch) {
|
|
13
|
-
await (0,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
tenantId,
|
|
20
|
-
userId,
|
|
21
|
-
isTenantOwner: patch.isTenantOwner,
|
|
22
|
-
previousIsTenantOwner: null,
|
|
23
|
-
deliveryId: patch.deliveryId,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
await (0, tenant_ownership_1.applyAdmittedTenantOwnership)(userModel, userId, tenantId, patch);
|
|
16
|
+
await (0, tenant_members_1.changeTenantMembers)(tenantId, async () => {
|
|
17
|
+
const existing = await (0, interface_database_decorators_1.GetModel)(tenantMembers_model_1.TenantMemberModel, tenantId).getByUser(userId);
|
|
18
|
+
return {
|
|
19
|
+
changes: (0, member_changes_1.describeMembershipPatch)(existing, userId, patch),
|
|
20
|
+
write: () => (0, tenant_ownership_1.applyAdmittedTenantOwnership)(userModel, userId, tenantId, patch),
|
|
21
|
+
};
|
|
27
22
|
});
|
|
28
23
|
}
|
|
29
24
|
async function syncPlatformOwnerOnTenantOwnerChange(userModel, userId, tenantId, nextIsTenantOwner) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-ownership.js","sourceRoot":"","sources":["../src/tenant-ownership.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"tenant-ownership.js","sourceRoot":"","sources":["../src/tenant-ownership.ts"],"names":[],"mappings":";;AAsBA,oDAgBC;AAED,oFAOC;AAED,8EAQC;AAxDD,6FAAqE;AACrE,yEAAoE;AACpE,qDAAuD;AACvD,8DAAoE;AACpE,kEAGqC;AAUrC;;;GAGG;AACI,KAAK,UAAU,oBAAoB,CACxC,SAAoB,EACpB,MAAc,EACd,QAAgB,EAChB,KAA4B;IAE5B,MAAM,IAAA,oCAAmB,EAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,QAAQ,GAAG,MAAM,IAAA,wCAAQ,EAAC,uCAAiB,EAAE,QAAQ,CAAC,CAAC,SAAS,CACpE,MAAM,CACP,CAAC;QACF,OAAO;YACL,OAAO,EAAE,IAAA,wCAAuB,EAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;YACzD,KAAK,EAAE,GAAG,EAAE,CACV,IAAA,+CAA4B,EAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;SACnE,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,oCAAoC,CACxD,SAAoB,EACpB,MAAc,EACd,QAAgB,EAChB,iBAA0B;IAE1B,MAAM,IAAA,sCAAmB,EAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;AAC5E,CAAC;AAEM,KAAK,UAAU,iCAAiC,CACrD,SAAoB,EACpB,MAAc,EACd,QAAgB,EAChB,2BAAoC;IAEpC,IAAI,CAAC,2BAA2B;QAAE,OAAO;IACzC,MAAM,IAAA,sCAAmB,EAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type TenantProvisioningHookPayload } from "./hooks";
|
|
2
|
+
/**
|
|
3
|
+
* Provision a tenant whose row was just created: register it as an instance
|
|
4
|
+
* of the tenant schema, then run the `Hook.TENANT_BEING_PROVISIONED`
|
|
5
|
+
* handlers in series. The instance is registered first, here rather than by a
|
|
6
|
+
* handler, so no handler ever runs before it, whatever order the modules
|
|
7
|
+
* registered in.
|
|
8
|
+
*
|
|
9
|
+
* Call it once per tenant, at its creation, and fire the hook through it
|
|
10
|
+
* only. A handler that throws rejects the call, and the caller unwinds the
|
|
11
|
+
* tenant it was creating.
|
|
12
|
+
*
|
|
13
|
+
* @param payload Tenant being provisioned and what the caller carries along
|
|
14
|
+
*/
|
|
15
|
+
export declare function ProvisionTenant(payload: TenantProvisioningHookPayload): Promise<void>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProvisionTenant = ProvisionTenant;
|
|
4
|
+
const node_assert_1 = require("node:assert");
|
|
5
|
+
const interface_database_1 = require("@antelopejs/interface-database");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
const hooks_1 = require("./hooks");
|
|
8
|
+
/**
|
|
9
|
+
* Provision a tenant whose row was just created: register it as an instance
|
|
10
|
+
* of the tenant schema, then run the `Hook.TENANT_BEING_PROVISIONED`
|
|
11
|
+
* handlers in series. The instance is registered first, here rather than by a
|
|
12
|
+
* handler, so no handler ever runs before it, whatever order the modules
|
|
13
|
+
* registered in.
|
|
14
|
+
*
|
|
15
|
+
* Call it once per tenant, at its creation, and fire the hook through it
|
|
16
|
+
* only. A handler that throws rejects the call, and the caller unwinds the
|
|
17
|
+
* tenant it was creating.
|
|
18
|
+
*
|
|
19
|
+
* @param payload Tenant being provisioned and what the caller carries along
|
|
20
|
+
*/
|
|
21
|
+
async function ProvisionTenant(payload) {
|
|
22
|
+
const schema = interface_database_1.Schema.get(constants_1.TENANT_SCHEMA_NAME);
|
|
23
|
+
(0, node_assert_1.strict)(schema, `Schema '${constants_1.TENANT_SCHEMA_NAME}' is not registered`);
|
|
24
|
+
await schema.createInstance(payload.tenantId);
|
|
25
|
+
await (0, hooks_1.ExecuteHooks)(hooks_1.Hook.TENANT_BEING_PROVISIONED, payload);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=tenant-provisioning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-provisioning.js","sourceRoot":"","sources":["../src/tenant-provisioning.ts"],"names":[],"mappings":";;AAsBA,0CAOC;AA7BD,6CAA+C;AAC/C,uEAAwD;AACxD,2CAAiD;AACjD,mCAIiB;AAEjB;;;;;;;;;;;;GAYG;AACI,KAAK,UAAU,eAAe,CACnC,OAAsC;IAEtC,MAAM,MAAM,GAAG,2BAAM,CAAC,GAAG,CAAC,8BAAkB,CAAC,CAAC;IAC9C,IAAA,oBAAM,EAAC,MAAM,EAAE,WAAW,8BAAkB,qBAAqB,CAAC,CAAC;IACnE,MAAM,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,IAAA,oBAAY,EAAC,YAAI,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -2,7 +2,8 @@ import { type Class } from "@antelopejs/interface-core/decorators";
|
|
|
2
2
|
import { type DataModel } from "@antelopejs/interface-database-decorators";
|
|
3
3
|
/**
|
|
4
4
|
* Parameter/property decorator that injects `GetModel(cl, currentTenantId)`,
|
|
5
|
-
* where `currentTenantId` is
|
|
5
|
+
* where `currentTenantId` is the tenant of the request's verified credential
|
|
6
|
+
* ({@link resolveRequestTenantId}), `DEFAULT_TENANT_ID` without one.
|
|
6
7
|
*
|
|
7
8
|
* Use on a `Model`-typed parameter of a route handler or DataAPI field. Only
|
|
8
9
|
* applicable when the target table is registered in the `dms-tenant` schema
|
|
@@ -7,15 +7,16 @@ const interface_database_decorators_1 = require("@antelopejs/interface-database-
|
|
|
7
7
|
const request_tenant_1 = require("./request-tenant");
|
|
8
8
|
/**
|
|
9
9
|
* Parameter/property decorator that injects `GetModel(cl, currentTenantId)`,
|
|
10
|
-
* where `currentTenantId` is
|
|
10
|
+
* where `currentTenantId` is the tenant of the request's verified credential
|
|
11
|
+
* ({@link resolveRequestTenantId}), `DEFAULT_TENANT_ID` without one.
|
|
11
12
|
*
|
|
12
13
|
* Use on a `Model`-typed parameter of a route handler or DataAPI field. Only
|
|
13
14
|
* applicable when the target table is registered in the `dms-tenant` schema
|
|
14
15
|
* (or any schema with one instance per tenant).
|
|
15
16
|
*/
|
|
16
17
|
exports.TenantScopedModel = (0, decorators_1.MakeParameterAndPropertyDecorator)((target, key, index, cl) => {
|
|
17
|
-
(0, interface_api_1.SetParameterProvider)(target, key, index, (ctx) => {
|
|
18
|
-
return (0, interface_database_decorators_1.GetModel)(cl, (0, request_tenant_1.
|
|
18
|
+
(0, interface_api_1.SetParameterProvider)(target, key, index, async (ctx) => {
|
|
19
|
+
return (0, interface_database_decorators_1.GetModel)(cl, await (0, request_tenant_1.resolveRequestTenantId)(ctx));
|
|
19
20
|
});
|
|
20
21
|
});
|
|
21
22
|
//# sourceMappingURL=tenant-scoped-model.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-scoped-model.js","sourceRoot":"","sources":["../src/tenant-scoped-model.ts"],"names":[],"mappings":";;;AAAA,6DAGmC;AACnC,sEAG+C;AAC/C,6FAGmD;AACnD,
|
|
1
|
+
{"version":3,"file":"tenant-scoped-model.js","sourceRoot":"","sources":["../src/tenant-scoped-model.ts"],"names":[],"mappings":";;;AAAA,6DAGmC;AACnC,sEAG+C;AAC/C,6FAGmD;AACnD,qDAA0D;AAE1D;;;;;;;;GAQG;AACU,QAAA,iBAAiB,GAAG,IAAA,8CAAiC,EAChE,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,EAA8C,EAAE,EAAE;IACrE,IAAA,oCAAoB,EAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE;QACrE,OAAO,IAAA,wCAAQ,EAAC,EAAE,EAAE,MAAM,IAAA,uCAAsB,EAAC,GAAG,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CACF,CAAC"}
|