@remit/backend 2.0.0 → 2.1.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/src/config/api-config.d.ts +3 -0
- package/dist/src/config/from-env.js +4 -0
- package/dist/src/handlers/calendar-feed.js +6 -0
- package/dist/src/handlers/index.d.ts +5 -0
- package/dist/src/handlers/index.js +2 -0
- package/dist/src/handlers/people.d.ts +2 -0
- package/dist/src/handlers/people.js +119 -0
- package/dist/src/service/people-directory.d.ts +8 -0
- package/dist/src/service/people-directory.js +10 -0
- package/dist/src/types.d.ts +2 -1
- package/package.json +1 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { MsOAuthConfig } from "./msoauth.js";
|
|
2
|
+
export type Switch = "Enabled" | "Disabled";
|
|
2
3
|
export type AuthConfig = {
|
|
3
4
|
mode: "BetterAuthJwt";
|
|
4
5
|
contentSigningSecret: string;
|
|
6
|
+
signIn: Switch;
|
|
7
|
+
selfSignUp: Switch;
|
|
5
8
|
} | {
|
|
6
9
|
mode: "GatewayAuthorizer";
|
|
7
10
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveSelfSignUpEnabled, resolveSignInEnabled, } from "@remit/auth-service/verifier";
|
|
1
2
|
import { msOAuthCredentialsFromSecret } from "./msoauth-secrets-manager.js";
|
|
2
3
|
const DEFAULT_UPDATE_CONTROL_DIR = "/data/control";
|
|
3
4
|
const optional = (env, key) => env[key] || undefined;
|
|
@@ -11,10 +12,13 @@ const commaList = (raw) => (raw ?? "")
|
|
|
11
12
|
.split(",")
|
|
12
13
|
.map((origin) => origin.trim())
|
|
13
14
|
.filter((origin) => origin.length > 0);
|
|
15
|
+
const switchOf = (on) => (on ? "Enabled" : "Disabled");
|
|
14
16
|
const authFromEnv = (env) => env.DATA_BACKEND === "sqlite"
|
|
15
17
|
? {
|
|
16
18
|
mode: "BetterAuthJwt",
|
|
17
19
|
contentSigningSecret: required(env, "BETTER_AUTH_SECRET", "The self-host SQL backend signs content URLs with it."),
|
|
20
|
+
signIn: switchOf(resolveSignInEnabled(env.SIGN_IN_ENABLED)),
|
|
21
|
+
selfSignUp: switchOf(resolveSelfSignUpEnabled(env.SELF_SIGN_UP_ENABLED)),
|
|
18
22
|
}
|
|
19
23
|
: { mode: "GatewayAuthorizer" };
|
|
20
24
|
const contentDeliveryDomainFromEnv = (env, auth, publicOrigin) => {
|
|
@@ -174,6 +174,12 @@ export const getCalendarFeedIcal = async (context, ctx) => {
|
|
|
174
174
|
const feedToken = readCalendarFeedToken(context.request.path);
|
|
175
175
|
if (feedToken === null)
|
|
176
176
|
return feedNotFound();
|
|
177
|
+
// The kill switch stops every feed with the answer an unknown token gets;
|
|
178
|
+
// the rows stay, so feeds resume when sign-in is turned back on.
|
|
179
|
+
if (ctx.config.auth.mode === "BetterAuthJwt" &&
|
|
180
|
+
ctx.config.auth.signIn === "Disabled") {
|
|
181
|
+
return feedNotFound();
|
|
182
|
+
}
|
|
177
183
|
const ifNoneMatch = context.request.headers["if-none-match"];
|
|
178
184
|
const ifModifiedSince = context.request.headers["if-modified-since"];
|
|
179
185
|
const deps = calendarDepsOf(ctx.client);
|
|
@@ -175,6 +175,11 @@ export declare const handlers: {
|
|
|
175
175
|
AccountDetailOperations_deleteAccount: (context: import("openapi-backend").Context, ctx: import("../types.js").HandlerContext<"accountFanout">) => Promise<import("@remit/api-openapi-types").DeleteAccountResponse>;
|
|
176
176
|
AccountOperations_createAccount: (context: import("openapi-backend").Context, ctx: import("../types.js").HandlerContext<"sync">) => Promise<import("@remit/api-openapi-types").AccountResponse>;
|
|
177
177
|
AccountOperations_testConnection: (context: import("openapi-backend").Context, ctx: import("../types.js").HandlerContext) => Promise<import("@remit/api-openapi-types").TestConnectionResponse>;
|
|
178
|
+
PeopleOperations_listPeople: OperationHandler<import("../types.js").PeopleOperationIds>;
|
|
179
|
+
PeopleOperations_createStepUp: OperationHandler<import("../types.js").PeopleOperationIds>;
|
|
180
|
+
PeopleOperations_updatePerson: OperationHandler<import("../types.js").PeopleOperationIds>;
|
|
181
|
+
PeopleOperations_createPasswordReset: OperationHandler<import("../types.js").PeopleOperationIds>;
|
|
182
|
+
PeopleOperations_signOutPerson: OperationHandler<import("../types.js").PeopleOperationIds>;
|
|
178
183
|
SystemOperations_getSystemUpdate: OperationHandler<import("../types.js").SystemOperationIds>;
|
|
179
184
|
SystemOperations_applySystemUpdate: OperationHandler<import("../types.js").SystemOperationIds>;
|
|
180
185
|
ConfigOperations_getConfig: (_context: import("openapi-backend").Context, ctx: import("../types.js").HandlerContext<"sync">) => Promise<import("@remit/api-openapi-types").ConfigDescriptionResponse>;
|
|
@@ -15,6 +15,7 @@ import { MeOperations } from "./me.js";
|
|
|
15
15
|
import { MessageBulkOperations, MessageOperations } from "./message.js";
|
|
16
16
|
import { OrganizeJobDetailOperations, OrganizeOperations } from "./organize.js";
|
|
17
17
|
import { OutboxAttachmentOperations, OutboxDetailOperations, OutboxOperations, } from "./outbox.js";
|
|
18
|
+
import { PeopleOperations } from "./people.js";
|
|
18
19
|
import { SyncOperations } from "./sync.js";
|
|
19
20
|
import { SystemOperations } from "./system-update.js";
|
|
20
21
|
import { ThreadDetailOperations, ThreadOperations } from "./thread.js";
|
|
@@ -24,6 +25,7 @@ export const handlers = {
|
|
|
24
25
|
...MeOperations,
|
|
25
26
|
...ConfigOperations,
|
|
26
27
|
...SystemOperations,
|
|
28
|
+
...PeopleOperations,
|
|
27
29
|
...AccountOperations,
|
|
28
30
|
...AccountDetailOperations,
|
|
29
31
|
...MicrosoftOAuthOperations,
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { getPeopleDirectory } from "../service/people-directory.js";
|
|
2
|
+
const CLIENT_IP_HEADER = "x-remit-client-ip";
|
|
3
|
+
const refuse = (statusCode, code, message) => ({ statusCode, body: { code, message } });
|
|
4
|
+
const REFUSALS = {
|
|
5
|
+
caller_disabled: [403, "Your account is disabled."],
|
|
6
|
+
not_found: [404, "Not found"],
|
|
7
|
+
step_up_required: [403, "Confirm your password again."],
|
|
8
|
+
wrong_password: [403, "That password is not right."],
|
|
9
|
+
step_up_locked: [429, "Too many wrong passwords. Try again in 15 minutes."],
|
|
10
|
+
cannot_disable_self: [409, "You cannot disable your own account."],
|
|
11
|
+
};
|
|
12
|
+
const refusalOf = (refusal) => {
|
|
13
|
+
const [statusCode, message] = REFUSALS[refusal];
|
|
14
|
+
return refuse(statusCode, refusal, message);
|
|
15
|
+
};
|
|
16
|
+
const headerOf = (context, name) => {
|
|
17
|
+
const headers = context.request.headers;
|
|
18
|
+
const key = Object.keys(headers).find((each) => each.toLowerCase() === name);
|
|
19
|
+
const value = key === undefined ? undefined : headers[key];
|
|
20
|
+
return typeof value === "string" ? value : undefined;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The guards every People operation runs before any read or write. The
|
|
24
|
+
* surface does not exist (404) while anyone can sign up, since anyone could
|
|
25
|
+
* then make themselves an operator; the kill switch refuses it; an unsafe
|
|
26
|
+
* request from an origin this instance does not serve is refused. The caller's
|
|
27
|
+
* own row is checked inside the directory, in the transaction that acts.
|
|
28
|
+
*/
|
|
29
|
+
const guard = (context, ctx, targetId, unsafe) => {
|
|
30
|
+
const directory = getPeopleDirectory();
|
|
31
|
+
const { auth } = ctx.config;
|
|
32
|
+
if (auth.mode !== "BetterAuthJwt" ||
|
|
33
|
+
auth.selfSignUp === "Enabled" ||
|
|
34
|
+
!directory) {
|
|
35
|
+
return refusalOf("not_found");
|
|
36
|
+
}
|
|
37
|
+
const request = {
|
|
38
|
+
directory,
|
|
39
|
+
callerId: ctx.identity.sub,
|
|
40
|
+
clientIp: headerOf(context, CLIENT_IP_HEADER) ?? "unknown",
|
|
41
|
+
};
|
|
42
|
+
const refuseAudited = (outcome, code, message) => {
|
|
43
|
+
directory.recordRefusal({ ...request, targetId, outcome });
|
|
44
|
+
return refuse(403, code, message);
|
|
45
|
+
};
|
|
46
|
+
if (auth.signIn === "Disabled") {
|
|
47
|
+
return refuseAudited("RefusedSignInOff", "sign_in_disabled", "Sign-in is turned off on this server.");
|
|
48
|
+
}
|
|
49
|
+
const origin = headerOf(context, "origin");
|
|
50
|
+
if (unsafe &&
|
|
51
|
+
origin !== undefined &&
|
|
52
|
+
!ctx.config.corsAllowedOrigins.includes(origin)) {
|
|
53
|
+
return refuseAudited("RefusedForeignOrigin", "foreign_origin", "This request came from a page this server does not serve.");
|
|
54
|
+
}
|
|
55
|
+
return request;
|
|
56
|
+
};
|
|
57
|
+
const isGuarded = (value) => "directory" in value;
|
|
58
|
+
const answer = (outcome) => outcome.ok ? outcome.value : refusalOf(outcome.refusal);
|
|
59
|
+
const targetOf = (context) => context.request.params.userId;
|
|
60
|
+
export const PeopleOperations = {
|
|
61
|
+
PeopleOperations_listPeople: async (context, ctx) => {
|
|
62
|
+
const guarded = guard(context, ctx, "all", false);
|
|
63
|
+
if (!isGuarded(guarded))
|
|
64
|
+
return guarded;
|
|
65
|
+
const listed = answer(await guarded.directory.listPeople(guarded));
|
|
66
|
+
return Array.isArray(listed) ? { people: listed } : listed;
|
|
67
|
+
},
|
|
68
|
+
PeopleOperations_createStepUp: async (context, ctx) => {
|
|
69
|
+
const body = context.request.requestBody;
|
|
70
|
+
const guarded = guard(context, ctx, body.userId, true);
|
|
71
|
+
if (!isGuarded(guarded))
|
|
72
|
+
return guarded;
|
|
73
|
+
return answer(await guarded.directory.createStepUp({
|
|
74
|
+
...guarded,
|
|
75
|
+
targetId: body.userId,
|
|
76
|
+
action: body.action,
|
|
77
|
+
password: body.password,
|
|
78
|
+
}));
|
|
79
|
+
},
|
|
80
|
+
PeopleOperations_signOutPerson: async (context, ctx) => {
|
|
81
|
+
const targetId = targetOf(context);
|
|
82
|
+
const guarded = guard(context, ctx, targetId, true);
|
|
83
|
+
if (!isGuarded(guarded))
|
|
84
|
+
return guarded;
|
|
85
|
+
const { stepUpToken } = context.request.requestBody;
|
|
86
|
+
return answer(await guarded.directory.signOutPerson({
|
|
87
|
+
...guarded,
|
|
88
|
+
targetId,
|
|
89
|
+
stepUpToken,
|
|
90
|
+
}));
|
|
91
|
+
},
|
|
92
|
+
PeopleOperations_updatePerson: async (context, ctx) => {
|
|
93
|
+
const targetId = targetOf(context);
|
|
94
|
+
const guarded = guard(context, ctx, targetId, true);
|
|
95
|
+
if (!isGuarded(guarded))
|
|
96
|
+
return guarded;
|
|
97
|
+
const { status, stepUpToken } = context.request
|
|
98
|
+
.requestBody;
|
|
99
|
+
return answer(await guarded.directory.updatePerson({
|
|
100
|
+
...guarded,
|
|
101
|
+
targetId,
|
|
102
|
+
stepUpToken,
|
|
103
|
+
status,
|
|
104
|
+
}));
|
|
105
|
+
},
|
|
106
|
+
PeopleOperations_createPasswordReset: async (context, ctx) => {
|
|
107
|
+
const targetId = targetOf(context);
|
|
108
|
+
const guarded = guard(context, ctx, targetId, true);
|
|
109
|
+
if (!isGuarded(guarded))
|
|
110
|
+
return guarded;
|
|
111
|
+
const { stepUpToken } = context.request
|
|
112
|
+
.requestBody;
|
|
113
|
+
return answer(await guarded.directory.createPasswordReset({
|
|
114
|
+
...guarded,
|
|
115
|
+
targetId,
|
|
116
|
+
stepUpToken,
|
|
117
|
+
}));
|
|
118
|
+
},
|
|
119
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PeopleDirectory } from "@remit/auth-service/people";
|
|
2
|
+
/**
|
|
3
|
+
* Register the self-host people directory from the composition root. A host
|
|
4
|
+
* that registers none answers every People operation with 404, which is what
|
|
5
|
+
* keeps better-auth out of any bundle that only serves the mail API.
|
|
6
|
+
*/
|
|
7
|
+
export declare const setPeopleDirectory: (directory: PeopleDirectory | null) => void;
|
|
8
|
+
export declare const getPeopleDirectory: () => PeopleDirectory | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
let registered = null;
|
|
2
|
+
/**
|
|
3
|
+
* Register the self-host people directory from the composition root. A host
|
|
4
|
+
* that registers none answers every People operation with 404, which is what
|
|
5
|
+
* keeps better-auth out of any bundle that only serves the mail API.
|
|
6
|
+
*/
|
|
7
|
+
export const setPeopleDirectory = (directory) => {
|
|
8
|
+
registered = directory;
|
|
9
|
+
};
|
|
10
|
+
export const getPeopleDirectory = () => registered;
|
package/dist/src/types.d.ts
CHANGED
|
@@ -3,10 +3,11 @@ import type { ApiConfig } from "./config/api-config.js";
|
|
|
3
3
|
import type { RemitClient } from "./service/create-remit-client.js";
|
|
4
4
|
import type { QueueName } from "./service/queues.js";
|
|
5
5
|
type MatchPrefix<Prefix extends string, S extends string> = S extends `${Prefix}${infer _}` ? S : never;
|
|
6
|
-
export type OperationIds = "MeOperations_deleteMe" | "MeOperations_listVipSuggestions" | "MeOperations_createExport" | "MeOperations_getExport" | "MeOperations_listQuarantine" | "ConfigOperations_getConfig" | "ConfigOperations_exportConfig" | "ConfigOperations_importConfig" | "SystemOperations_getSystemUpdate" | "SystemOperations_applySystemUpdate" | "AccountOperations_createAccount" | "AccountOperations_testConnection" | "AccountDetailOperations_updateAccount" | "AccountDetailOperations_deleteAccount" | "MicrosoftOAuthOperations_microsoftOAuthStart" | "MicrosoftOAuthOperations_microsoftOAuthCallback" | "MailboxOperations_listMailboxes" | "MailboxOperations_createMailbox" | "MailboxDetailOperations_getMailbox" | "MailboxDetailOperations_renameMailbox" | "MailboxDetailOperations_deleteMailbox" | "FolderRoleOperations_appointFolderRole" | "FilterOperations_listFilters" | "FilterOperations_createFilter" | "FilterDetailOperations_getFilter" | "FilterDetailOperations_updateFilter" | "FilterDetailOperations_deleteFilter" | "LabelOperations_listLabels" | "LabelOperations_createLabel" | "LabelDetailOperations_getLabel" | "LabelDetailOperations_updateLabel" | "LabelDetailOperations_deleteLabel" | "OrganizeOperations_createOrganizeJob" | "OrganizeOperations_previewOrganize" | "OrganizeJobDetailOperations_getOrganizeJob" | "SyncOperations_triggerSync" | "SyncOperations_getSyncStatus" | "ThreadDetailOperations_listThreadMessages" | "UnifiedThreadOperations_listAllThreads" | "ThreadOperations_listThreads" | "ThreadOperations_searchThreads" | "MessageOperations_describeMessage" | "MessageOperations_getRawMessage" | "MessageOperations_updateMessageFlags" | "MessageBulkOperations_deleteMessages" | "MessageBulkOperations_moveMessages" | "MessageBulkOperations_updateFlags" | "MessageBulkOperations_copyMessages" | "MessageBulkOperations_updateMessageLabels" | "MessageBulkOperations_reportSpam" | "MessageBulkOperations_notSpam" | "CalendarOperations_listCalendars" | "CalendarOperations_createCalendar" | "CalendarDetailOperations_getCalendar" | "CalendarDetailOperations_updateCalendar" | "CalendarDetailOperations_deleteCalendar" | "CalendarDetailOperations_getCalendarFeed" | "CalendarDetailOperations_putCalendarFeed" | "CalendarDetailOperations_revokeCalendarFeed" | "CalendarFeedOperations_getCalendarFeedIcal" | "CalendarEventOperations_listCalendarEvents" | "CalendarEventOperations_createCalendarEvent" | "CalendarEventDetailOperations_getCalendarEvent" | "CalendarEventDetailOperations_updateCalendarEvent" | "CalendarEventDetailOperations_deleteCalendarEvent" | "CalendarFreeBusyOperations_listCalendarFreeBusy" | "UserSettingsOperations_getUserSettings" | "UserSettingsOperations_updateUserSettings" | "UserSettingsOperations_clearDefaultInvitationSender" | "CalendarTaskOperations_listCalendarTasks" | "CalendarTaskOperations_createCalendarTask" | "CalendarTaskDetailOperations_getCalendarTask" | "CalendarTaskDetailOperations_updateCalendarTask" | "CalendarTaskDetailOperations_deleteCalendarTask" | "TrashOperations_emptyTrash" | "OutboxOperations_createOutboxMessage" | "OutboxOperations_listOutboxMessages" | "OutboxDetailOperations_getOutboxMessage" | "OutboxDetailOperations_updateOutboxMessage" | "OutboxDetailOperations_deleteOutboxMessage" | "OutboxDetailOperations_sendOutboxMessage" | "OutboxDetailOperations_mintOutboxAttachment" | "OutboxAttachmentOperations_completeOutboxAttachment" | "AddressOperations_searchAddresses" | "AddressDetailOperations_updateAddress" | "CalendarSuggestionOperations_listCalendarSuggestions" | "MessageCalendarSuggestionOperations_listMessageCalendarSuggestions" | "CalendarSuggestionActionOperations_acceptCalendarSuggestion" | "CalendarSuggestionActionOperations_declineCalendarSuggestion" | "CalendarSuggestionActionOperations_dismissCalendarSuggestion" | "CalendarSuggestionActionOperations_reopenCalendarSuggestion";
|
|
6
|
+
export type OperationIds = "MeOperations_deleteMe" | "MeOperations_listVipSuggestions" | "MeOperations_createExport" | "MeOperations_getExport" | "MeOperations_listQuarantine" | "ConfigOperations_getConfig" | "ConfigOperations_exportConfig" | "ConfigOperations_importConfig" | "SystemOperations_getSystemUpdate" | "SystemOperations_applySystemUpdate" | "PeopleOperations_listPeople" | "PeopleOperations_createStepUp" | "PeopleOperations_signOutPerson" | "PeopleOperations_updatePerson" | "PeopleOperations_createPasswordReset" | "AccountOperations_createAccount" | "AccountOperations_testConnection" | "AccountDetailOperations_updateAccount" | "AccountDetailOperations_deleteAccount" | "MicrosoftOAuthOperations_microsoftOAuthStart" | "MicrosoftOAuthOperations_microsoftOAuthCallback" | "MailboxOperations_listMailboxes" | "MailboxOperations_createMailbox" | "MailboxDetailOperations_getMailbox" | "MailboxDetailOperations_renameMailbox" | "MailboxDetailOperations_deleteMailbox" | "FolderRoleOperations_appointFolderRole" | "FilterOperations_listFilters" | "FilterOperations_createFilter" | "FilterDetailOperations_getFilter" | "FilterDetailOperations_updateFilter" | "FilterDetailOperations_deleteFilter" | "LabelOperations_listLabels" | "LabelOperations_createLabel" | "LabelDetailOperations_getLabel" | "LabelDetailOperations_updateLabel" | "LabelDetailOperations_deleteLabel" | "OrganizeOperations_createOrganizeJob" | "OrganizeOperations_previewOrganize" | "OrganizeJobDetailOperations_getOrganizeJob" | "SyncOperations_triggerSync" | "SyncOperations_getSyncStatus" | "ThreadDetailOperations_listThreadMessages" | "UnifiedThreadOperations_listAllThreads" | "ThreadOperations_listThreads" | "ThreadOperations_searchThreads" | "MessageOperations_describeMessage" | "MessageOperations_getRawMessage" | "MessageOperations_updateMessageFlags" | "MessageBulkOperations_deleteMessages" | "MessageBulkOperations_moveMessages" | "MessageBulkOperations_updateFlags" | "MessageBulkOperations_copyMessages" | "MessageBulkOperations_updateMessageLabels" | "MessageBulkOperations_reportSpam" | "MessageBulkOperations_notSpam" | "CalendarOperations_listCalendars" | "CalendarOperations_createCalendar" | "CalendarDetailOperations_getCalendar" | "CalendarDetailOperations_updateCalendar" | "CalendarDetailOperations_deleteCalendar" | "CalendarDetailOperations_getCalendarFeed" | "CalendarDetailOperations_putCalendarFeed" | "CalendarDetailOperations_revokeCalendarFeed" | "CalendarFeedOperations_getCalendarFeedIcal" | "CalendarEventOperations_listCalendarEvents" | "CalendarEventOperations_createCalendarEvent" | "CalendarEventDetailOperations_getCalendarEvent" | "CalendarEventDetailOperations_updateCalendarEvent" | "CalendarEventDetailOperations_deleteCalendarEvent" | "CalendarFreeBusyOperations_listCalendarFreeBusy" | "UserSettingsOperations_getUserSettings" | "UserSettingsOperations_updateUserSettings" | "UserSettingsOperations_clearDefaultInvitationSender" | "CalendarTaskOperations_listCalendarTasks" | "CalendarTaskOperations_createCalendarTask" | "CalendarTaskDetailOperations_getCalendarTask" | "CalendarTaskDetailOperations_updateCalendarTask" | "CalendarTaskDetailOperations_deleteCalendarTask" | "TrashOperations_emptyTrash" | "OutboxOperations_createOutboxMessage" | "OutboxOperations_listOutboxMessages" | "OutboxDetailOperations_getOutboxMessage" | "OutboxDetailOperations_updateOutboxMessage" | "OutboxDetailOperations_deleteOutboxMessage" | "OutboxDetailOperations_sendOutboxMessage" | "OutboxDetailOperations_mintOutboxAttachment" | "OutboxAttachmentOperations_completeOutboxAttachment" | "AddressOperations_searchAddresses" | "AddressDetailOperations_updateAddress" | "CalendarSuggestionOperations_listCalendarSuggestions" | "MessageCalendarSuggestionOperations_listMessageCalendarSuggestions" | "CalendarSuggestionActionOperations_acceptCalendarSuggestion" | "CalendarSuggestionActionOperations_declineCalendarSuggestion" | "CalendarSuggestionActionOperations_dismissCalendarSuggestion" | "CalendarSuggestionActionOperations_reopenCalendarSuggestion";
|
|
7
7
|
export type MeOperationIds = MatchPrefix<"MeOperations_", OperationIds>;
|
|
8
8
|
export type ConfigOperationIds = MatchPrefix<"ConfigOperations_", OperationIds>;
|
|
9
9
|
export type SystemOperationIds = MatchPrefix<"SystemOperations_", OperationIds>;
|
|
10
|
+
export type PeopleOperationIds = MatchPrefix<"PeopleOperations_", OperationIds>;
|
|
10
11
|
export type AccountOperationIds = MatchPrefix<"AccountOperations_", OperationIds>;
|
|
11
12
|
export type AccountDetailOperationIds = MatchPrefix<"AccountDetailOperations_", OperationIds>;
|
|
12
13
|
export type MailboxOperationIds = MatchPrefix<"MailboxOperations_", OperationIds>;
|