@remit/backend 0.0.144 → 0.0.146
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/api.d.ts +0 -2
- package/dist/src/api.js +9 -80
- package/dist/src/auth.d.ts +13 -19
- package/dist/src/auth.js +51 -43
- package/dist/src/config/api-config.d.ts +20 -0
- package/dist/src/config/api-config.js +1 -0
- package/dist/src/config/from-env.d.ts +2 -0
- package/dist/src/config/from-env.js +65 -0
- package/dist/src/config/msoauth-secrets-manager.d.ts +2 -0
- package/dist/src/config/msoauth-secrets-manager.js +28 -0
- package/dist/src/config/msoauth.d.ts +18 -29
- package/dist/src/config/msoauth.js +4 -28
- package/dist/src/derive/contentSignature.d.ts +3 -4
- package/dist/src/derive/contentSignature.js +4 -13
- package/dist/src/derive/contentUrl.d.ts +0 -13
- package/dist/src/derive/contentUrl.js +0 -19
- package/dist/src/handlers/account-oauth.d.ts +9 -3
- package/dist/src/handlers/account-oauth.js +197 -250
- package/dist/src/handlers/account.d.ts +13 -4
- package/dist/src/handlers/account.js +26 -39
- package/dist/src/handlers/address.d.ts +11 -3
- package/dist/src/handlers/address.js +11 -19
- package/dist/src/handlers/calendar-event.js +18 -26
- package/dist/src/handlers/calendar-feed.d.ts +2 -2
- package/dist/src/handlers/calendar-feed.js +24 -32
- package/dist/src/handlers/calendar-suggestion.js +18 -26
- package/dist/src/handlers/calendar.d.ts +1 -1
- package/dist/src/handlers/calendar.js +15 -22
- package/dist/src/handlers/config.d.ts +16 -6
- package/dist/src/handlers/config.js +23 -35
- package/dist/src/handlers/filter.d.ts +16 -3
- package/dist/src/handlers/filter.js +17 -32
- package/dist/src/handlers/folder-role.js +3 -6
- package/dist/src/handlers/index.d.ts +187 -2
- package/dist/src/handlers/index.js +6 -4
- package/dist/src/handlers/label.js +15 -22
- package/dist/src/handlers/mailbox.d.ts +20 -4
- package/dist/src/handlers/mailbox.js +18 -26
- package/dist/src/handlers/me.d.ts +10 -2
- package/dist/src/handlers/me.js +26 -47
- package/dist/src/handlers/message.d.ts +78 -6
- package/dist/src/handlers/message.js +34 -46
- package/dist/src/handlers/organize.d.ts +10 -4
- package/dist/src/handlers/organize.js +11 -20
- package/dist/src/handlers/outbox-attachment.d.ts +6 -5
- package/dist/src/handlers/outbox-attachment.js +11 -15
- package/dist/src/handlers/outbox.d.ts +25 -4
- package/dist/src/handlers/outbox.js +27 -35
- package/dist/src/handlers/sync.d.ts +19 -6
- package/dist/src/handlers/sync.js +13 -22
- package/dist/src/handlers/system-update.js +14 -27
- package/dist/src/handlers/thread.js +9 -14
- package/dist/src/handlers/unified-threads.js +3 -6
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.js +18 -2
- package/dist/src/jwt-auth.d.ts +9 -12
- package/dist/src/jwt-auth.js +19 -71
- package/dist/src/lambda.d.ts +13 -0
- package/dist/src/lambda.js +33 -0
- package/dist/src/request.d.ts +8 -2
- package/dist/src/request.js +16 -6
- package/dist/src/response.d.ts +20 -3
- package/dist/src/response.js +15 -22
- package/dist/src/serve.d.ts +31 -0
- package/dist/src/serve.js +117 -0
- package/dist/src/service/account-deletion.d.ts +2 -4
- package/dist/src/service/account-deletion.js +3 -9
- package/dist/src/service/compose-sqlite.d.ts +2 -1
- package/dist/src/service/compose-sqlite.js +5 -3
- package/dist/src/service/create-remit-client.d.ts +25 -11
- package/dist/src/service/create-remit-client.js +97 -116
- package/dist/src/service/data-client.js +3 -5
- package/dist/src/service/export-identity.d.ts +2 -1
- package/dist/src/service/export-identity.js +4 -6
- package/dist/src/service/fire-and-forget.js +1 -2
- package/dist/src/service/organize.d.ts +7 -10
- package/dist/src/service/organize.js +10 -27
- package/dist/src/service/queues.d.ts +12 -0
- package/dist/src/service/queues.js +1 -0
- package/dist/src/service/shared-deps.d.ts +6 -0
- package/dist/src/service/shared-deps.js +26 -0
- package/dist/src/service/trigger-sync.d.ts +11 -5
- package/dist/src/service/trigger-sync.js +10 -18
- package/dist/src/types.d.ts +24 -1
- package/package.json +24 -8
- package/dist/src/data-backend.d.ts +0 -12
- package/dist/src/data-backend.js +0 -12
- package/dist/src/request-context.d.ts +0 -9
- package/dist/src/request-context.js +0 -22
- package/dist/src/service/sqs.d.ts +0 -1
- package/dist/src/service/sqs.js +0 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RenameMailboxInput } from "@remit/api-openapi-types";
|
|
2
2
|
import type { IAccountSettingRepository, MailboxItem } from "@remit/data-ports";
|
|
3
3
|
import { type FolderPathDeps } from "@remit/mailbox-service";
|
|
4
|
-
import type {
|
|
4
|
+
import type { HandlerContext } from "../types.js";
|
|
5
5
|
/**
|
|
6
6
|
* The mute flag and the display-name override are user preferences that live
|
|
7
7
|
* in per-mailbox AccountSetting rows (RFC 032), not on the Mailbox entity.
|
|
@@ -18,6 +18,22 @@ export type MailboxPatchClient = FolderPathDeps & {
|
|
|
18
18
|
accountSetting: Pick<IAccountSettingRepository, "get" | "upsert" | "delete">;
|
|
19
19
|
};
|
|
20
20
|
export declare const applyMailboxPatch: (client: MailboxPatchClient, accountConfigId: string, mailboxId: string, accountId: string, body: RenameMailboxInput) => Promise<MailboxItem>;
|
|
21
|
-
export declare const MailboxOperations:
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
export declare const MailboxOperations: {
|
|
22
|
+
MailboxOperations_listMailboxes: (context: import("openapi-backend").Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext) => Promise<{
|
|
23
|
+
items: import("@remit/api-openapi-types").Components.Schemas.MailboxResponse[];
|
|
24
|
+
continuationToken: string | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
MailboxOperations_createMailbox: (context: import("openapi-backend").Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<import("@remit/api-openapi-types").Components.Schemas.MailboxResponse>;
|
|
27
|
+
};
|
|
28
|
+
export declare const MailboxDetailOperations: {
|
|
29
|
+
MailboxDetailOperations_getMailbox: (context: import("openapi-backend").Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext) => Promise<import("@remit/api-openapi-types").Components.Schemas.MailboxResponse>;
|
|
30
|
+
MailboxDetailOperations_renameMailbox: (context: import("openapi-backend").Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<import("@remit/api-openapi-types").Components.Schemas.MailboxResponse>;
|
|
31
|
+
MailboxDetailOperations_deleteMailbox: (context: import("openapi-backend").Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<{
|
|
32
|
+
statusCode: number;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
export declare const TrashOperations: {
|
|
36
|
+
TrashOperations_emptyTrash: (context: import("openapi-backend").Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<{
|
|
37
|
+
deletedCount: number;
|
|
38
|
+
}>;
|
|
39
|
+
};
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { BadRequestError, ConflictError } from "@remit/data-ports/errors";
|
|
2
2
|
import { MessageSystemFlag } from "@remit/domain-enums";
|
|
3
3
|
import { changeFolderPath, createFolder, folderInAccount, folderInFlight, ownedAccount, ownedFolder, } from "@remit/mailbox-service";
|
|
4
|
-
import { getAccountConfigIdFromEvent } from "../auth.js";
|
|
5
4
|
import { applyPendingMoveCountPrediction, } from "../derive/pendingMoveCounts.js";
|
|
6
|
-
import { getClient } from "../service/data-client.js";
|
|
7
5
|
import { unwrap } from "../service/refusal.js";
|
|
8
6
|
import { applyMailboxOverrideChanges, loadMailboxOverrides, loadMailboxOverridesForConfig, } from "./account-overrides.js";
|
|
9
7
|
import { assertNoBindings, loadMailboxBindings } from "./mailbox-bindings.js";
|
|
@@ -100,12 +98,11 @@ const toMailboxResponse = (mailbox, overrides = {}) => ({
|
|
|
100
98
|
updatedAt: mailbox.updatedAt,
|
|
101
99
|
});
|
|
102
100
|
export const MailboxOperations = {
|
|
103
|
-
MailboxOperations_listMailboxes: async (context,
|
|
104
|
-
const
|
|
105
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
101
|
+
MailboxOperations_listMailboxes: async (context, ctx) => {
|
|
102
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
106
103
|
const { accountId } = context.request.params;
|
|
107
104
|
const { continuationToken } = context.request.query;
|
|
108
|
-
const client =
|
|
105
|
+
const client = ctx.client;
|
|
109
106
|
const account = await client.account.get(accountId);
|
|
110
107
|
unwrap(ownedAccount(account, accountConfigId, "read"));
|
|
111
108
|
const result = await client.mailbox.listByAccount(accountId, {
|
|
@@ -129,13 +126,12 @@ export const MailboxOperations = {
|
|
|
129
126
|
continuationToken: result.continuationToken,
|
|
130
127
|
};
|
|
131
128
|
},
|
|
132
|
-
MailboxOperations_createMailbox: async (context,
|
|
133
|
-
const
|
|
134
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
129
|
+
MailboxOperations_createMailbox: async (context, ctx) => {
|
|
130
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
135
131
|
const { accountId } = context.request.params;
|
|
136
132
|
const { namespaceType, fullPath } = context.request
|
|
137
133
|
.requestBody;
|
|
138
|
-
const created = await createFolder(
|
|
134
|
+
const created = await createFolder(ctx.client, accountConfigId, {
|
|
139
135
|
accountId,
|
|
140
136
|
namespaceType,
|
|
141
137
|
fullPath,
|
|
@@ -148,11 +144,10 @@ export const MailboxOperations = {
|
|
|
148
144
|
},
|
|
149
145
|
};
|
|
150
146
|
export const MailboxDetailOperations = {
|
|
151
|
-
MailboxDetailOperations_getMailbox: async (context,
|
|
152
|
-
const
|
|
153
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
147
|
+
MailboxDetailOperations_getMailbox: async (context, ctx) => {
|
|
148
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
154
149
|
const { accountId, mailboxId } = context.request.params;
|
|
155
|
-
const client =
|
|
150
|
+
const client = ctx.client;
|
|
156
151
|
const account = await client.account.get(accountId);
|
|
157
152
|
unwrap(ownedAccount(account, accountConfigId, "read"));
|
|
158
153
|
const mailbox = await client.mailbox.get(accountId, mailboxId);
|
|
@@ -166,21 +161,19 @@ export const MailboxDetailOperations = {
|
|
|
166
161
|
const adjusted = applyPendingMoveCountPrediction([mailbox], pendingMoves, pendingUnseenFlagPushes)[0] ?? mailbox;
|
|
167
162
|
return toMailboxResponse(adjusted, overrides);
|
|
168
163
|
},
|
|
169
|
-
MailboxDetailOperations_renameMailbox: async (context,
|
|
170
|
-
const
|
|
171
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
164
|
+
MailboxDetailOperations_renameMailbox: async (context, ctx) => {
|
|
165
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
172
166
|
const { accountId, mailboxId } = context.request.params;
|
|
173
167
|
const body = context.request.requestBody;
|
|
174
|
-
const client =
|
|
168
|
+
const client = ctx.client;
|
|
175
169
|
const mailbox = await applyMailboxPatch(client, accountConfigId, mailboxId, accountId, body);
|
|
176
170
|
const overrides = await loadMailboxOverrides(client.accountSetting, accountConfigId, mailboxId);
|
|
177
171
|
return toMailboxResponse(mailbox, overrides);
|
|
178
172
|
},
|
|
179
|
-
MailboxDetailOperations_deleteMailbox: async (context,
|
|
180
|
-
const
|
|
181
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
173
|
+
MailboxDetailOperations_deleteMailbox: async (context, ctx) => {
|
|
174
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
182
175
|
const { accountId, mailboxId } = context.request.params;
|
|
183
|
-
const client =
|
|
176
|
+
const client = ctx.client;
|
|
184
177
|
const account = await client.account.get(accountId);
|
|
185
178
|
unwrap(ownedAccount(account, accountConfigId, "act"));
|
|
186
179
|
const mailbox = await client.mailbox.get(accountId, mailboxId);
|
|
@@ -203,11 +196,10 @@ export const MailboxDetailOperations = {
|
|
|
203
196
|
},
|
|
204
197
|
};
|
|
205
198
|
export const TrashOperations = {
|
|
206
|
-
TrashOperations_emptyTrash: async (context,
|
|
207
|
-
const
|
|
208
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
199
|
+
TrashOperations_emptyTrash: async (context, ctx) => {
|
|
200
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
209
201
|
const { accountId } = context.request.params;
|
|
210
|
-
const client =
|
|
202
|
+
const client = ctx.client;
|
|
211
203
|
const account = await client.account.get(accountId);
|
|
212
204
|
unwrap(ownedAccount(account, accountConfigId, "act"));
|
|
213
205
|
// The service resolves Trash, marks the rows and counts them, all off one
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { AccountExportRequestResponse, CreateExportResponse, DeleteAccountConfigResponse, QuarantineListResponse, VipSuggestionsResponse } from "@remit/api-openapi-types";
|
|
2
|
+
import type { Context } from "openapi-backend";
|
|
3
|
+
import type { HandlerContext } from "../types.js";
|
|
4
|
+
export declare const MeOperations: {
|
|
5
|
+
MeOperations_listVipSuggestions: (_context: Context, ctx: HandlerContext) => Promise<VipSuggestionsResponse>;
|
|
6
|
+
MeOperations_listQuarantine: (_context: Context, ctx: HandlerContext) => Promise<QuarantineListResponse>;
|
|
7
|
+
MeOperations_deleteMe: (context: Context, ctx: HandlerContext<"accountFanout">) => Promise<DeleteAccountConfigResponse>;
|
|
8
|
+
MeOperations_createExport: (_context: Context, ctx: HandlerContext<"accountFanout">) => Promise<CreateExportResponse>;
|
|
9
|
+
MeOperations_getExport: (context: Context, ctx: HandlerContext) => Promise<AccountExportRequestResponse>;
|
|
10
|
+
};
|
package/dist/src/handlers/me.js
CHANGED
|
@@ -1,26 +1,19 @@
|
|
|
1
|
-
import { SendMessageCommand } from "@aws-sdk/client-sqs";
|
|
2
1
|
import { BadRequestError, NotFoundError } from "@remit/data-ports/errors";
|
|
3
2
|
import { SYNC_WARNING_SURFACE_ATTEMPTS } from "@remit/data-ports/sync-warning-state";
|
|
4
3
|
import { logger } from "@remit/logger";
|
|
5
|
-
import { env } from "expect-env";
|
|
6
|
-
import { getAccountConfigIdFromEvent, getSubFromEvent } from "../auth.js";
|
|
7
|
-
import { getClient } from "../service/data-client.js";
|
|
8
|
-
import { sqsClient } from "../service/sqs.js";
|
|
9
4
|
import { toVipSuggestionEntry } from "./vip-suggestions.js";
|
|
10
5
|
const DOWNLOAD_URL_TTL_SECONDS = 60 * 60;
|
|
11
6
|
const SURFACED_WARNING_CAP = 200;
|
|
12
7
|
export const MeOperations = {
|
|
13
|
-
MeOperations_listVipSuggestions: async (_context,
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const { address } = await getClient();
|
|
8
|
+
MeOperations_listVipSuggestions: async (_context, ctx) => {
|
|
9
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
10
|
+
const { address } = ctx.client;
|
|
17
11
|
const items = await address.listSuggestedVips({ accountConfigId });
|
|
18
12
|
return { suggestions: items.map(toVipSuggestionEntry) };
|
|
19
13
|
},
|
|
20
|
-
MeOperations_listQuarantine: async (_context,
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const { quarantine, syncWarning } = await getClient();
|
|
14
|
+
MeOperations_listQuarantine: async (_context, ctx) => {
|
|
15
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
16
|
+
const { quarantine, syncWarning } = ctx.client;
|
|
24
17
|
const [entries, warnings] = await Promise.all([
|
|
25
18
|
quarantine.listByAccountConfigId(accountConfigId),
|
|
26
19
|
syncWarning.listSurfacedByAccountConfigId(accountConfigId, SYNC_WARNING_SURFACE_ATTEMPTS, SURFACED_WARNING_CAP),
|
|
@@ -31,21 +24,18 @@ export const MeOperations = {
|
|
|
31
24
|
warningsTotal: warnings.total,
|
|
32
25
|
};
|
|
33
26
|
},
|
|
34
|
-
MeOperations_deleteMe: async (
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const callerEmail =
|
|
27
|
+
MeOperations_deleteMe: async (context, ctx) => {
|
|
28
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
29
|
+
const { confirmEmail } = context.request
|
|
30
|
+
.requestBody;
|
|
31
|
+
const callerEmail = ctx.identity.email;
|
|
39
32
|
if (typeof confirmEmail !== "string" || confirmEmail.trim() === "") {
|
|
40
33
|
throw new BadRequestError("confirmEmail is required");
|
|
41
34
|
}
|
|
42
|
-
if (!callerEmail) {
|
|
43
|
-
throw new BadRequestError("Account email claim missing from token");
|
|
44
|
-
}
|
|
45
35
|
if (confirmEmail.toLowerCase() !== callerEmail.toLowerCase()) {
|
|
46
36
|
throw new BadRequestError("confirmEmail does not match your account email");
|
|
47
37
|
}
|
|
48
|
-
const { accountConfig } =
|
|
38
|
+
const { accountConfig } = ctx.client;
|
|
49
39
|
try {
|
|
50
40
|
await accountConfig.update(accountConfigId, {
|
|
51
41
|
state: "deleting",
|
|
@@ -64,14 +54,9 @@ export const MeOperations = {
|
|
|
64
54
|
}
|
|
65
55
|
throw err;
|
|
66
56
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
MessageBody: JSON.stringify({
|
|
71
|
-
type: "AccountDelete",
|
|
72
|
-
accountConfigId,
|
|
73
|
-
}),
|
|
74
|
-
}));
|
|
57
|
+
await ctx.client.queues.accountFanout.send({
|
|
58
|
+
body: { type: "AccountDelete", accountConfigId },
|
|
59
|
+
});
|
|
75
60
|
// biome-ignore lint/plugin/no-logger-info: account deletion is an audit-grade signal
|
|
76
61
|
logger.info({ accountConfigId }, "Account deletion initiated");
|
|
77
62
|
return {
|
|
@@ -79,27 +64,22 @@ export const MeOperations = {
|
|
|
79
64
|
message: "Account deletion initiated",
|
|
80
65
|
};
|
|
81
66
|
},
|
|
82
|
-
MeOperations_createExport: async (_context,
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
if (!userId) {
|
|
87
|
-
throw new Error("Missing Cognito `sub`: cannot attribute an export request to a user");
|
|
88
|
-
}
|
|
89
|
-
const { accountExportRequest } = await getClient();
|
|
67
|
+
MeOperations_createExport: async (_context, ctx) => {
|
|
68
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
69
|
+
const userId = ctx.identity.sub;
|
|
70
|
+
const { accountExportRequest } = ctx.client;
|
|
90
71
|
const exportRequest = await accountExportRequest.create({
|
|
91
72
|
accountConfigId,
|
|
92
73
|
userId,
|
|
93
74
|
state: "Pending",
|
|
94
75
|
});
|
|
95
|
-
await
|
|
96
|
-
|
|
97
|
-
MessageBody: JSON.stringify({
|
|
76
|
+
await ctx.client.queues.accountFanout.send({
|
|
77
|
+
body: {
|
|
98
78
|
type: "AccountExport",
|
|
99
79
|
accountConfigId,
|
|
100
80
|
accountExportRequestId: exportRequest.accountExportRequestId,
|
|
101
|
-
}
|
|
102
|
-
})
|
|
81
|
+
},
|
|
82
|
+
});
|
|
103
83
|
// biome-ignore lint/plugin/no-logger-info: account export is an audit-grade signal
|
|
104
84
|
logger.info({
|
|
105
85
|
accountConfigId,
|
|
@@ -110,11 +90,10 @@ export const MeOperations = {
|
|
|
110
90
|
exportId: exportRequest.accountExportRequestId,
|
|
111
91
|
};
|
|
112
92
|
},
|
|
113
|
-
MeOperations_getExport: async (context,
|
|
114
|
-
const
|
|
115
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
93
|
+
MeOperations_getExport: async (context, ctx) => {
|
|
94
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
116
95
|
const exportId = context.request.params.exportId;
|
|
117
|
-
const { accountExportRequest, storage } =
|
|
96
|
+
const { accountExportRequest, storage } = ctx.client;
|
|
118
97
|
const exportRequest = await accountExportRequest.get(exportId);
|
|
119
98
|
if (exportRequest.accountConfigId !== accountConfigId) {
|
|
120
99
|
throw new NotFoundError(`Export not found: ${exportId}`);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BodyPartResponse } from "@remit/api-openapi-types";
|
|
2
|
+
import type { Context } from "openapi-backend";
|
|
2
3
|
import { type ContentSigner } from "../derive/contentSignature.js";
|
|
3
|
-
import type {
|
|
4
|
+
import type { HandlerContext } from "../types.js";
|
|
4
5
|
export declare const isStorageNotFoundError: (error: unknown) => boolean;
|
|
5
6
|
/**
|
|
6
7
|
* Decode the raw `.eml` bytes into a string for inspection. RFC822/MIME
|
|
@@ -26,9 +27,7 @@ export declare const extractAccountIdsFromBodyKey: (uri: string) => {
|
|
|
26
27
|
* populating `contentUrl` from the CloudFront distribution domain. Pure
|
|
27
28
|
* function so the URL-construction contract can be pinned in tests without
|
|
28
29
|
* standing up the full handler. The contract requires every `contentUrl`
|
|
29
|
-
* to be a real URL (#299)
|
|
30
|
-
* Lambda env is missing the domain, and this function expects a non-empty
|
|
31
|
-
* string from the caller.
|
|
30
|
+
* to be a real URL (#299), so the API refuses to start without the domain.
|
|
32
31
|
*/
|
|
33
32
|
export interface BodyPartLike {
|
|
34
33
|
bodyPartId: string;
|
|
@@ -80,5 +79,78 @@ export declare const GENERIC_FAILURE_REASON = "This message could not be process
|
|
|
80
79
|
* regardless of batch size.
|
|
81
80
|
*/
|
|
82
81
|
export declare const settleSpamReportBulk: (messageIds: string[], run: (messageId: string) => Promise<void>) => Promise<SpamReportBulkOutcome>;
|
|
83
|
-
export declare const MessageOperations:
|
|
84
|
-
|
|
82
|
+
export declare const MessageOperations: {
|
|
83
|
+
MessageOperations_describeMessage: (context: Context, ctx: HandlerContext<"sync" | "messageManagement" | "body">) => Promise<{
|
|
84
|
+
message: {
|
|
85
|
+
spamReport?: {
|
|
86
|
+
reportedAt: number;
|
|
87
|
+
} | undefined;
|
|
88
|
+
labels?: {
|
|
89
|
+
labelId: string;
|
|
90
|
+
name: string;
|
|
91
|
+
color: "Default" | "Red" | "Orange" | "Yellow" | "Green" | "Teal" | "Blue" | "Purple" | "Gray";
|
|
92
|
+
}[] | undefined;
|
|
93
|
+
autoMoved?: import("@remit/api-openapi-types").Components.Schemas.AutoMovedInfo | undefined;
|
|
94
|
+
messageId: string;
|
|
95
|
+
mailboxId: string;
|
|
96
|
+
uid: number;
|
|
97
|
+
rfc822Size: number;
|
|
98
|
+
internalDate: number;
|
|
99
|
+
messageIdHeader: string | undefined;
|
|
100
|
+
authenticity: {
|
|
101
|
+
fromDomain: string;
|
|
102
|
+
dkimMismatch: boolean;
|
|
103
|
+
dkimDomain?: string | undefined;
|
|
104
|
+
displayNameCorrespondence?: "Corresponds" | "Lookalike" | "ForeignAddress" | "Unrelated" | "NoClaim" | undefined;
|
|
105
|
+
offDomainLinkDomains?: string[] | undefined;
|
|
106
|
+
signerDomain?: string | undefined;
|
|
107
|
+
envelopeDomain?: string | undefined;
|
|
108
|
+
signerMessageCount?: number | undefined;
|
|
109
|
+
signerFirstSeenAt?: number | undefined;
|
|
110
|
+
} | undefined;
|
|
111
|
+
status: "active" | "deleting" | "deleted" | "moving";
|
|
112
|
+
syncStatus: "failed" | "synced" | "pending" | "abandoned";
|
|
113
|
+
abandonedMutation: "none" | "move" | "delete" | "copy";
|
|
114
|
+
};
|
|
115
|
+
envelope: import("@remit/api-openapi-types").Components.Schemas.EnvelopeResponse;
|
|
116
|
+
flags: string[];
|
|
117
|
+
bodyParts: import("@remit/api-openapi-types").Components.Schemas.BodyPartResponse[];
|
|
118
|
+
references: {
|
|
119
|
+
messageIdValue: string;
|
|
120
|
+
referenceType: string;
|
|
121
|
+
referenceOrder: number;
|
|
122
|
+
}[];
|
|
123
|
+
}>;
|
|
124
|
+
MessageOperations_getRawMessage: (context: Context, ctx: HandlerContext<"sync" | "messageManagement">) => Promise<{
|
|
125
|
+
raw: string;
|
|
126
|
+
}>;
|
|
127
|
+
MessageOperations_updateMessageFlags: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<{
|
|
128
|
+
messageId: string;
|
|
129
|
+
isRead: boolean;
|
|
130
|
+
isStarred: boolean;
|
|
131
|
+
}>;
|
|
132
|
+
};
|
|
133
|
+
export declare const MessageBulkOperations: {
|
|
134
|
+
MessageBulkOperations_updateFlags: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<{
|
|
135
|
+
successCount: number;
|
|
136
|
+
failureCount: number;
|
|
137
|
+
}>;
|
|
138
|
+
MessageBulkOperations_deleteMessages: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<{
|
|
139
|
+
successCount: number;
|
|
140
|
+
failureCount: number;
|
|
141
|
+
}>;
|
|
142
|
+
MessageBulkOperations_moveMessages: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<{
|
|
143
|
+
successCount: number;
|
|
144
|
+
failureCount: number;
|
|
145
|
+
}>;
|
|
146
|
+
MessageBulkOperations_copyMessages: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<{
|
|
147
|
+
successCount: number;
|
|
148
|
+
failureCount: number;
|
|
149
|
+
}>;
|
|
150
|
+
MessageBulkOperations_updateMessageLabels: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext) => Promise<{
|
|
151
|
+
successCount: number;
|
|
152
|
+
failureCount: number;
|
|
153
|
+
}>;
|
|
154
|
+
MessageBulkOperations_reportSpam: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<SpamReportBulkOutcome>;
|
|
155
|
+
MessageBulkOperations_notSpam: (context: Context<any, any, any, any, any, import("openapi-backend").Document>, ctx: HandlerContext<"sync">) => Promise<SpamReportBulkOutcome>;
|
|
156
|
+
};
|
|
@@ -4,12 +4,10 @@ import { ContentDisposition, MediaType, MessageCategory, SenderTrust, } from "@r
|
|
|
4
4
|
import { logger } from "@remit/logger";
|
|
5
5
|
import { guardConnectionCursor, isCursorRebuildNeeded, isMessageBodySyncBroken, MailboxCursorPausedError, MoveNotSettledError, materializeBodyParts, NoJunkMailboxError, ownedMessages, resolveFolderPlacement, settledFolder, } from "@remit/mailbox-service";
|
|
6
6
|
import { isStorageNotFoundError as isStorageNotFoundErrorFromService, parseStorageUri, } from "@remit/storage-service";
|
|
7
|
-
import { getAccountConfigIdFromEvent, getSubFromEvent } from "../auth.js";
|
|
8
7
|
import { deriveAutoMoved } from "../derive/autoMoved.js";
|
|
9
8
|
import { getContentSigner, } from "../derive/contentSignature.js";
|
|
10
|
-
import { buildContentUrl
|
|
9
|
+
import { buildContentUrl } from "../derive/contentUrl.js";
|
|
11
10
|
import { deriveSenderTrust } from "../derive/senderTrust.js";
|
|
12
|
-
import { getClient } from "../service/data-client.js";
|
|
13
11
|
import { unwrap } from "../service/refusal.js";
|
|
14
12
|
export const isStorageNotFoundError = (error) => isStorageNotFoundErrorFromService(error);
|
|
15
13
|
/**
|
|
@@ -144,11 +142,10 @@ export const settleSpamReportBulk = async (messageIds, run) => {
|
|
|
144
142
|
};
|
|
145
143
|
};
|
|
146
144
|
export const MessageOperations = {
|
|
147
|
-
MessageOperations_describeMessage: async (context,
|
|
148
|
-
const
|
|
149
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
145
|
+
MessageOperations_describeMessage: async (context, ctx) => {
|
|
146
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
150
147
|
const { messageId } = context.request.params;
|
|
151
|
-
const client =
|
|
148
|
+
const client = ctx.client;
|
|
152
149
|
const ownedAccountId = unwrap(await ownedMessages(client, [messageId], accountConfigId, "read"));
|
|
153
150
|
const description = await client.message.describe(messageId);
|
|
154
151
|
const message = description.message[0];
|
|
@@ -335,11 +332,11 @@ export const MessageOperations = {
|
|
|
335
332
|
logger,
|
|
336
333
|
});
|
|
337
334
|
const bodyParts = buildBodyPartResponses(bodyPartRows, {
|
|
338
|
-
contentDeliveryDomain:
|
|
335
|
+
contentDeliveryDomain: ctx.config.contentDeliveryDomain,
|
|
339
336
|
accountConfigId,
|
|
340
337
|
accountId,
|
|
341
338
|
messageId,
|
|
342
|
-
sign: getContentSigner(),
|
|
339
|
+
sign: getContentSigner(ctx.config),
|
|
343
340
|
});
|
|
344
341
|
const references = description.messageReference.map((ref) => ({
|
|
345
342
|
messageIdValue: ref.messageIdValue,
|
|
@@ -354,11 +351,10 @@ export const MessageOperations = {
|
|
|
354
351
|
references,
|
|
355
352
|
};
|
|
356
353
|
},
|
|
357
|
-
MessageOperations_getRawMessage: async (context,
|
|
358
|
-
const
|
|
359
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
354
|
+
MessageOperations_getRawMessage: async (context, ctx) => {
|
|
355
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
360
356
|
const { messageId } = context.request.params;
|
|
361
|
-
const client =
|
|
357
|
+
const client = ctx.client;
|
|
362
358
|
// Cross-tenant ownership guard. Returning raw RFC822 bytes is sensitive,
|
|
363
359
|
// so resolve the owning account and prove the caller owns it BEFORE any
|
|
364
360
|
// storage read or backfill. `read` mode throws NotFoundError (→ 404) on a
|
|
@@ -421,12 +417,11 @@ export const MessageOperations = {
|
|
|
421
417
|
const body = await client.storage.retrieve(stored.bodyStorageKey);
|
|
422
418
|
return { raw: decodeRawEml(body) };
|
|
423
419
|
},
|
|
424
|
-
MessageOperations_updateMessageFlags: async (context,
|
|
425
|
-
const
|
|
426
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
420
|
+
MessageOperations_updateMessageFlags: async (context, ctx) => {
|
|
421
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
427
422
|
const { messageId } = context.request.params;
|
|
428
423
|
const { isRead, isStarred, starColor } = context.request.requestBody;
|
|
429
|
-
const client =
|
|
424
|
+
const client = ctx.client;
|
|
430
425
|
const accountId = unwrap(await ownedMessages(client, [messageId], accountConfigId, "act"));
|
|
431
426
|
// FlagQueueService handles: MessageFlag + ThreadMessage updates + SQS event
|
|
432
427
|
const result = await client.flagQueue.updateFlags(accountConfigId, messageId, accountId, {
|
|
@@ -442,15 +437,14 @@ export const MessageOperations = {
|
|
|
442
437
|
},
|
|
443
438
|
};
|
|
444
439
|
export const MessageBulkOperations = {
|
|
445
|
-
MessageBulkOperations_updateFlags: async (context,
|
|
446
|
-
const
|
|
447
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
440
|
+
MessageBulkOperations_updateFlags: async (context, ctx) => {
|
|
441
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
448
442
|
const { messageIds, isRead, isStarred, starColor } = context.request
|
|
449
443
|
.requestBody;
|
|
450
444
|
if (messageIds.length === 0) {
|
|
451
445
|
return { successCount: 0, failureCount: 0 };
|
|
452
446
|
}
|
|
453
|
-
const client =
|
|
447
|
+
const client = ctx.client;
|
|
454
448
|
const accountId = unwrap(await ownedMessages(client, messageIds, accountConfigId, "act"));
|
|
455
449
|
// FlagQueueService handles: MessageFlag + ThreadMessage updates + SQS events
|
|
456
450
|
// Process each message individually (same pattern as moveMessages)
|
|
@@ -466,14 +460,13 @@ export const MessageBulkOperations = {
|
|
|
466
460
|
failureCount: 0,
|
|
467
461
|
};
|
|
468
462
|
},
|
|
469
|
-
MessageBulkOperations_deleteMessages: async (context,
|
|
470
|
-
const
|
|
471
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
463
|
+
MessageBulkOperations_deleteMessages: async (context, ctx) => {
|
|
464
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
472
465
|
const { messageIds, permanent } = context.request.requestBody;
|
|
473
466
|
if (messageIds.length === 0) {
|
|
474
467
|
return { successCount: 0, failureCount: 0 };
|
|
475
468
|
}
|
|
476
|
-
const client =
|
|
469
|
+
const client = ctx.client;
|
|
477
470
|
const accountId = unwrap(await ownedMessages(client, messageIds, accountConfigId, "act"));
|
|
478
471
|
// MessageMoveService handles: Message + ThreadMessage updates + SQS events
|
|
479
472
|
const { refusedMessageIds } = await client.messageMove.deleteMessages(accountConfigId, messageIds, accountId, {
|
|
@@ -489,15 +482,14 @@ export const MessageBulkOperations = {
|
|
|
489
482
|
failureCount: refusedMessageIds.length,
|
|
490
483
|
};
|
|
491
484
|
},
|
|
492
|
-
MessageBulkOperations_moveMessages: async (context,
|
|
493
|
-
const
|
|
494
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
485
|
+
MessageBulkOperations_moveMessages: async (context, ctx) => {
|
|
486
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
495
487
|
const { messageIds, destinationMailboxId } = context.request
|
|
496
488
|
.requestBody;
|
|
497
489
|
if (messageIds.length === 0) {
|
|
498
490
|
return { successCount: 0, failureCount: 0 };
|
|
499
491
|
}
|
|
500
|
-
const client =
|
|
492
|
+
const client = ctx.client;
|
|
501
493
|
const accountId = unwrap(await ownedMessages(client, messageIds, accountConfigId, "act"));
|
|
502
494
|
// Destination must belong to the same (caller-owned) account, and must be
|
|
503
495
|
// a folder the mail server has settled: the row records the destination
|
|
@@ -515,15 +507,14 @@ export const MessageBulkOperations = {
|
|
|
515
507
|
failureCount: 0,
|
|
516
508
|
};
|
|
517
509
|
},
|
|
518
|
-
MessageBulkOperations_copyMessages: async (context,
|
|
519
|
-
const
|
|
520
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
510
|
+
MessageBulkOperations_copyMessages: async (context, ctx) => {
|
|
511
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
521
512
|
const { messageIds, destinationMailboxId } = context.request
|
|
522
513
|
.requestBody;
|
|
523
514
|
if (messageIds.length === 0) {
|
|
524
515
|
return { successCount: 0, failureCount: 0 };
|
|
525
516
|
}
|
|
526
|
-
const client =
|
|
517
|
+
const client = ctx.client;
|
|
527
518
|
const accountId = unwrap(await ownedMessages(client, messageIds, accountConfigId, "act"));
|
|
528
519
|
// Destination must belong to the same (caller-owned) account, and must be
|
|
529
520
|
// a folder the mail server has settled: the row records the destination
|
|
@@ -541,14 +532,13 @@ export const MessageBulkOperations = {
|
|
|
541
532
|
failureCount: 0,
|
|
542
533
|
};
|
|
543
534
|
},
|
|
544
|
-
MessageBulkOperations_updateMessageLabels: async (context,
|
|
545
|
-
const
|
|
546
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
535
|
+
MessageBulkOperations_updateMessageLabels: async (context, ctx) => {
|
|
536
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
547
537
|
const { messageIds, labelId, action } = context.request.requestBody;
|
|
548
538
|
if (messageIds.length === 0) {
|
|
549
539
|
return { successCount: 0, failureCount: 0 };
|
|
550
540
|
}
|
|
551
|
-
const client =
|
|
541
|
+
const client = ctx.client;
|
|
552
542
|
unwrap(await ownedMessages(client, messageIds, accountConfigId, "act"));
|
|
553
543
|
// Scoped by accountConfigId (RFC 030) — a foreign labelId 404s here rather
|
|
554
544
|
// than silently applying to messages under someone else's label.
|
|
@@ -574,17 +564,16 @@ export const MessageBulkOperations = {
|
|
|
574
564
|
failureCount: 0,
|
|
575
565
|
};
|
|
576
566
|
},
|
|
577
|
-
MessageBulkOperations_reportSpam: async (context,
|
|
578
|
-
const
|
|
579
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
567
|
+
MessageBulkOperations_reportSpam: async (context, ctx) => {
|
|
568
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
580
569
|
const { messageIds: requestedIds } = context.request.requestBody;
|
|
581
570
|
const messageIds = [...new Set(requestedIds)];
|
|
582
571
|
if (messageIds.length === 0) {
|
|
583
572
|
return { successCount: 0, failureCount: 0 };
|
|
584
573
|
}
|
|
585
|
-
const client =
|
|
574
|
+
const client = ctx.client;
|
|
586
575
|
const accountId = unwrap(await ownedMessages(client, messageIds, accountConfigId, "act"));
|
|
587
|
-
const setBy =
|
|
576
|
+
const setBy = ctx.identity.sub;
|
|
588
577
|
return settleSpamReportBulk(messageIds, (messageId) => client.spamReport.reportSpam({
|
|
589
578
|
accountConfigId,
|
|
590
579
|
accountId,
|
|
@@ -592,15 +581,14 @@ export const MessageBulkOperations = {
|
|
|
592
581
|
setBy,
|
|
593
582
|
}));
|
|
594
583
|
},
|
|
595
|
-
MessageBulkOperations_notSpam: async (context,
|
|
596
|
-
const
|
|
597
|
-
const accountConfigId = getAccountConfigIdFromEvent(event);
|
|
584
|
+
MessageBulkOperations_notSpam: async (context, ctx) => {
|
|
585
|
+
const accountConfigId = ctx.identity.accountConfigId;
|
|
598
586
|
const { messageIds: requestedIds } = context.request.requestBody;
|
|
599
587
|
const messageIds = [...new Set(requestedIds)];
|
|
600
588
|
if (messageIds.length === 0) {
|
|
601
589
|
return { successCount: 0, failureCount: 0 };
|
|
602
590
|
}
|
|
603
|
-
const client =
|
|
591
|
+
const client = ctx.client;
|
|
604
592
|
const accountId = unwrap(await ownedMessages(client, messageIds, accountConfigId, "act"));
|
|
605
593
|
return settleSpamReportBulk(messageIds, (messageId) => client.spamReport.notSpam({ accountConfigId, accountId, messageId }));
|
|
606
594
|
},
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import type { OrganizeInput } from "@remit/api-openapi-types";
|
|
1
|
+
import type { CreateOrganizeJobResponse, OrganizeInput, OrganizeJobResponse, OrganizePreviewResponse } from "@remit/api-openapi-types";
|
|
2
|
+
import type { Context } from "openapi-backend";
|
|
2
3
|
import { type OrganizePredicate } from "../service/organize.js";
|
|
3
|
-
import type {
|
|
4
|
+
import type { HandlerContext } from "../types.js";
|
|
4
5
|
/**
|
|
5
6
|
* Normalize the request body into the flattened predicate the job row and the
|
|
6
7
|
* matcher share.
|
|
7
8
|
*/
|
|
8
9
|
export declare const predicateFromInput: (input: OrganizeInput) => OrganizePredicate;
|
|
9
|
-
export declare const OrganizeOperations:
|
|
10
|
-
|
|
10
|
+
export declare const OrganizeOperations: {
|
|
11
|
+
OrganizeOperations_createOrganizeJob: (context: Context, ctx: HandlerContext<"accountFanout">) => Promise<CreateOrganizeJobResponse>;
|
|
12
|
+
OrganizeOperations_previewOrganize: (context: Context, ctx: HandlerContext) => Promise<OrganizePreviewResponse>;
|
|
13
|
+
};
|
|
14
|
+
export declare const OrganizeJobDetailOperations: {
|
|
15
|
+
OrganizeJobDetailOperations_getOrganizeJob: (context: Context, ctx: HandlerContext) => Promise<OrganizeJobResponse>;
|
|
16
|
+
};
|