@remit/backend 0.0.1
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/.env.test +7 -0
- package/dev-server/content-auth.test.ts +113 -0
- package/dev-server/content-auth.ts +54 -0
- package/dev-server/content-handler.test.ts +105 -0
- package/dev-server/content-handler.ts +79 -0
- package/dev-server/content-path.test.ts +37 -0
- package/dev-server/content-path.ts +27 -0
- package/dev-server/cors.test.ts +48 -0
- package/dev-server/cors.ts +25 -0
- package/dev-server/lambda-helpers.ts +69 -0
- package/dev-server/server.ts +289 -0
- package/package.json +82 -0
- package/src/auth.ts +92 -0
- package/src/config/msoauth.ts +60 -0
- package/src/data-backend.test.ts +25 -0
- package/src/data-backend.ts +20 -0
- package/src/derive/autoMoved.ts +28 -0
- package/src/derive/contentSignature.test.ts +153 -0
- package/src/derive/contentSignature.ts +139 -0
- package/src/derive/contentUrl.test.ts +156 -0
- package/src/derive/contentUrl.ts +70 -0
- package/src/derive/enrichThreadRows.ts +155 -0
- package/src/derive/filterThreadCriteria.test.ts +119 -0
- package/src/derive/filterThreadCriteria.ts +60 -0
- package/src/derive/pendingMoveCounts.ts +90 -0
- package/src/derive/senderTrust.test.ts +67 -0
- package/src/derive/senderTrust.ts +23 -0
- package/src/error.ts +55 -0
- package/src/handlers/account-guards.ts +137 -0
- package/src/handlers/account-oauth.test.ts +383 -0
- package/src/handlers/account-oauth.ts +452 -0
- package/src/handlers/account-overrides.test.ts +69 -0
- package/src/handlers/account-overrides.ts +286 -0
- package/src/handlers/account-ownership.ts +25 -0
- package/src/handlers/account-signature.ts +129 -0
- package/src/handlers/account.ts +524 -0
- package/src/handlers/address.ts +136 -0
- package/src/handlers/config.test.ts +184 -0
- package/src/handlers/config.ts +219 -0
- package/src/handlers/ensure-account-config.ts +30 -0
- package/src/handlers/filter.ts +294 -0
- package/src/handlers/folder-role-appointments.test.ts +250 -0
- package/src/handlers/folder-role-appointments.ts +272 -0
- package/src/handlers/folder-role.ts +76 -0
- package/src/handlers/index.ts +48 -0
- package/src/handlers/mailbox.ts +411 -0
- package/src/handlers/me.ts +190 -0
- package/src/handlers/message.ts +886 -0
- package/src/handlers/organize.test.ts +43 -0
- package/src/handlers/organize.ts +196 -0
- package/src/handlers/outbox.ts +218 -0
- package/src/handlers/search.test.ts +182 -0
- package/src/handlers/search.ts +105 -0
- package/src/handlers/sync-progress.test.ts +158 -0
- package/src/handlers/sync-progress.ts +64 -0
- package/src/handlers/sync.test.ts +146 -0
- package/src/handlers/sync.ts +119 -0
- package/src/handlers/thread.ts +361 -0
- package/src/handlers/unified-threads.ts +196 -0
- package/src/handlers/vip-suggestions.ts +21 -0
- package/src/index.ts +170 -0
- package/src/json.ts +11 -0
- package/src/jwt-auth.test.ts +89 -0
- package/src/jwt-auth.ts +95 -0
- package/src/request-context.test.ts +61 -0
- package/src/request-context.ts +29 -0
- package/src/request.ts +10 -0
- package/src/response.test.ts +107 -0
- package/src/response.ts +80 -0
- package/src/service/compose-postgres.ts +72 -0
- package/src/service/compose-sqlite.ts +80 -0
- package/src/service/create-remit-client.ts +358 -0
- package/src/service/dynamodb.test.ts +100 -0
- package/src/service/dynamodb.ts +58 -0
- package/src/service/filter.ts +55 -0
- package/src/service/fire-and-forget.test.ts +126 -0
- package/src/service/fire-and-forget.ts +79 -0
- package/src/service/localhost-env-config.test.ts +40 -0
- package/src/service/organize.test.ts +384 -0
- package/src/service/organize.ts +354 -0
- package/src/service/semantic-capability.test.ts +64 -0
- package/src/service/semantic-capability.ts +62 -0
- package/src/service/sqs.ts +4 -0
- package/src/service/trigger-sync.test.ts +211 -0
- package/src/service/trigger-sync.ts +102 -0
- package/src/types.ts +161 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { SendMessageCommand, type SQSClient } from "@aws-sdk/client-sqs";
|
|
3
|
+
|
|
4
|
+
interface SyncMailboxesEvent {
|
|
5
|
+
type: "SYNC_MAILBOXES";
|
|
6
|
+
eventId: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
accountId: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface TriggerAccountSyncInput {
|
|
12
|
+
sqsClient: SQSClient;
|
|
13
|
+
queueUrl: string;
|
|
14
|
+
accountId: string;
|
|
15
|
+
/**
|
|
16
|
+
* Override the FIFO `MessageDeduplicationId`. Defaults to a time-bucketed
|
|
17
|
+
* manual-trigger id (`buildManualSyncDedupId`) shared by every manual call
|
|
18
|
+
* site (POST /sync, OAuth connect, config load, pull-to-refresh, the
|
|
19
|
+
* client's online-poll) so a rapid double-tap collapses into one enqueue,
|
|
20
|
+
* while distinct triggers a bucket or more apart always pass through.
|
|
21
|
+
*
|
|
22
|
+
* The scheduled-sync tick (#1247) must NOT share that namespace: pass
|
|
23
|
+
* `buildScheduledSyncDedupId()` here instead, so the two paths can never
|
|
24
|
+
* suppress each other.
|
|
25
|
+
*/
|
|
26
|
+
dedupId?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isFifoQueue = (queueUrl: string): boolean => queueUrl.endsWith(".fifo");
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Bucket window for the manual-trigger dedup id. SQS FIFO's own dedup window
|
|
33
|
+
* is 5 minutes; a static per-account id (the pre-#1250 behaviour) collided
|
|
34
|
+
* with the client's 5-minute online poll and swallowed a pull-to-refresh
|
|
35
|
+
* within 5 minutes of any prior trigger. Bucketing to ~60s keeps a rapid
|
|
36
|
+
* double-tap deduped while letting distinct polls a minute or more apart
|
|
37
|
+
* always enqueue.
|
|
38
|
+
*/
|
|
39
|
+
const MANUAL_DEDUP_BUCKET_MS = 60_000;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Build the manual-trigger dedup id (POST /sync, OAuth connect, config load,
|
|
43
|
+
* pull-to-refresh, client online-poll), bucketed so consecutive triggers a
|
|
44
|
+
* bucket apart never collide — see `dedupId` above.
|
|
45
|
+
*/
|
|
46
|
+
export const buildManualSyncDedupId = (
|
|
47
|
+
accountId: string,
|
|
48
|
+
now: number,
|
|
49
|
+
bucketMs: number = MANUAL_DEDUP_BUCKET_MS,
|
|
50
|
+
): string => {
|
|
51
|
+
const bucket = Math.floor(now / bucketMs);
|
|
52
|
+
return `SYNC_MAILBOXES:manual:${accountId}:${bucket}`;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Build the scheduler's own dedup namespace, bucketed by tick interval so
|
|
57
|
+
* consecutive ticks each get a fresh id (never colliding with each other)
|
|
58
|
+
* while still deduping a genuine double-invocation of the same tick (e.g. a
|
|
59
|
+
* retried Lambda) — see `dedupId` above.
|
|
60
|
+
*/
|
|
61
|
+
export const buildScheduledSyncDedupId = (
|
|
62
|
+
accountId: string,
|
|
63
|
+
now: number,
|
|
64
|
+
bucketMs: number,
|
|
65
|
+
): string => {
|
|
66
|
+
const bucket = Math.floor(now / bucketMs);
|
|
67
|
+
return `SYNC_MAILBOXES:scheduled:${accountId}:${bucket}`;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const buildSyncMailboxesCommand = (
|
|
71
|
+
input: TriggerAccountSyncInput,
|
|
72
|
+
): SendMessageCommand => {
|
|
73
|
+
const { queueUrl, accountId, dedupId } = input;
|
|
74
|
+
const event: SyncMailboxesEvent = {
|
|
75
|
+
type: "SYNC_MAILBOXES",
|
|
76
|
+
eventId: randomUUID(),
|
|
77
|
+
timestamp: Date.now(),
|
|
78
|
+
accountId,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const useFifo = isFifoQueue(queueUrl);
|
|
82
|
+
|
|
83
|
+
return new SendMessageCommand({
|
|
84
|
+
QueueUrl: queueUrl,
|
|
85
|
+
MessageBody: JSON.stringify(event),
|
|
86
|
+
...(useFifo && {
|
|
87
|
+
MessageGroupId: accountId,
|
|
88
|
+
MessageDeduplicationId:
|
|
89
|
+
dedupId ?? buildManualSyncDedupId(accountId, event.timestamp),
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const triggerAccountSync = async (
|
|
95
|
+
input: TriggerAccountSyncInput,
|
|
96
|
+
): Promise<{ eventId: string }> => {
|
|
97
|
+
const command = buildSyncMailboxesCommand(input);
|
|
98
|
+
await input.sqsClient.send(command);
|
|
99
|
+
const body = command.input.MessageBody ?? "{}";
|
|
100
|
+
const parsed = JSON.parse(body) as SyncMailboxesEvent;
|
|
101
|
+
return { eventId: parsed.eventId };
|
|
102
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { Context } from "openapi-backend";
|
|
2
|
+
|
|
3
|
+
type MatchPrefix<
|
|
4
|
+
Prefix extends string,
|
|
5
|
+
S extends string,
|
|
6
|
+
> = S extends `${Prefix}${infer _}` ? S : never;
|
|
7
|
+
|
|
8
|
+
export type OperationIds =
|
|
9
|
+
| "MeOperations_deleteMe"
|
|
10
|
+
| "MeOperations_listVipSuggestions"
|
|
11
|
+
| "MeOperations_createExport"
|
|
12
|
+
| "MeOperations_getExport"
|
|
13
|
+
| "ConfigOperations_getConfig"
|
|
14
|
+
| "AccountOperations_createAccount"
|
|
15
|
+
| "AccountOperations_testConnection"
|
|
16
|
+
| "AccountDetailOperations_updateAccount"
|
|
17
|
+
| "AccountDetailOperations_deleteAccount"
|
|
18
|
+
| "MicrosoftOAuthOperations_microsoftOAuthStart"
|
|
19
|
+
| "MicrosoftOAuthOperations_microsoftOAuthCallback"
|
|
20
|
+
| "MailboxOperations_listMailboxes"
|
|
21
|
+
| "MailboxOperations_createMailbox"
|
|
22
|
+
| "MailboxDetailOperations_getMailbox"
|
|
23
|
+
| "MailboxDetailOperations_renameMailbox"
|
|
24
|
+
| "MailboxDetailOperations_deleteMailbox"
|
|
25
|
+
| "FolderRoleOperations_appointFolderRole"
|
|
26
|
+
| "FilterOperations_listFilters"
|
|
27
|
+
| "FilterOperations_createFilter"
|
|
28
|
+
| "FilterDetailOperations_getFilter"
|
|
29
|
+
| "FilterDetailOperations_updateFilter"
|
|
30
|
+
| "FilterDetailOperations_deleteFilter"
|
|
31
|
+
| "OrganizeOperations_createOrganizeJob"
|
|
32
|
+
| "OrganizeOperations_previewOrganize"
|
|
33
|
+
| "OrganizeJobDetailOperations_getOrganizeJob"
|
|
34
|
+
| "SyncOperations_triggerSync"
|
|
35
|
+
| "SyncOperations_getSyncStatus"
|
|
36
|
+
| "SemanticSearchOperations_semanticSearch"
|
|
37
|
+
| "ThreadDetailOperations_listThreadMessages"
|
|
38
|
+
| "UnifiedThreadOperations_listAllThreads"
|
|
39
|
+
| "ThreadOperations_listThreads"
|
|
40
|
+
| "ThreadOperations_searchThreads"
|
|
41
|
+
| "MessageOperations_describeMessage"
|
|
42
|
+
| "MessageOperations_getRawMessage"
|
|
43
|
+
| "MessageOperations_updateMessageFlags"
|
|
44
|
+
| "MessageBulkOperations_deleteMessages"
|
|
45
|
+
| "MessageBulkOperations_moveMessages"
|
|
46
|
+
| "MessageBulkOperations_updateFlags"
|
|
47
|
+
| "MessageBulkOperations_copyMessages"
|
|
48
|
+
| "TrashOperations_emptyTrash"
|
|
49
|
+
| "OutboxOperations_createOutboxMessage"
|
|
50
|
+
| "OutboxOperations_listOutboxMessages"
|
|
51
|
+
| "OutboxDetailOperations_getOutboxMessage"
|
|
52
|
+
| "OutboxDetailOperations_updateOutboxMessage"
|
|
53
|
+
| "OutboxDetailOperations_deleteOutboxMessage"
|
|
54
|
+
| "OutboxDetailOperations_sendOutboxMessage"
|
|
55
|
+
| "AddressOperations_searchAddresses"
|
|
56
|
+
| "AddressDetailOperations_updateAddress";
|
|
57
|
+
|
|
58
|
+
export type MeOperationIds = MatchPrefix<"MeOperations_", OperationIds>;
|
|
59
|
+
|
|
60
|
+
export type ConfigOperationIds = MatchPrefix<"ConfigOperations_", OperationIds>;
|
|
61
|
+
|
|
62
|
+
export type AccountOperationIds = MatchPrefix<
|
|
63
|
+
"AccountOperations_",
|
|
64
|
+
OperationIds
|
|
65
|
+
>;
|
|
66
|
+
|
|
67
|
+
export type AccountDetailOperationIds = MatchPrefix<
|
|
68
|
+
"AccountDetailOperations_",
|
|
69
|
+
OperationIds
|
|
70
|
+
>;
|
|
71
|
+
|
|
72
|
+
export type MailboxOperationIds = MatchPrefix<
|
|
73
|
+
"MailboxOperations_",
|
|
74
|
+
OperationIds
|
|
75
|
+
>;
|
|
76
|
+
|
|
77
|
+
export type MailboxDetailOperationIds = MatchPrefix<
|
|
78
|
+
"MailboxDetailOperations_",
|
|
79
|
+
OperationIds
|
|
80
|
+
>;
|
|
81
|
+
|
|
82
|
+
export type FolderRoleOperationIds = MatchPrefix<
|
|
83
|
+
"FolderRoleOperations_",
|
|
84
|
+
OperationIds
|
|
85
|
+
>;
|
|
86
|
+
|
|
87
|
+
export type FilterOperationIds = MatchPrefix<"FilterOperations_", OperationIds>;
|
|
88
|
+
|
|
89
|
+
export type FilterDetailOperationIds = MatchPrefix<
|
|
90
|
+
"FilterDetailOperations_",
|
|
91
|
+
OperationIds
|
|
92
|
+
>;
|
|
93
|
+
|
|
94
|
+
export type OrganizeOperationIds = MatchPrefix<
|
|
95
|
+
"OrganizeOperations_",
|
|
96
|
+
OperationIds
|
|
97
|
+
>;
|
|
98
|
+
|
|
99
|
+
export type OrganizeJobDetailOperationIds = MatchPrefix<
|
|
100
|
+
"OrganizeJobDetailOperations_",
|
|
101
|
+
OperationIds
|
|
102
|
+
>;
|
|
103
|
+
|
|
104
|
+
export type SyncOperationIds = MatchPrefix<"SyncOperations_", OperationIds>;
|
|
105
|
+
|
|
106
|
+
export type ThreadDetailOperationIds = MatchPrefix<
|
|
107
|
+
"ThreadDetailOperations_",
|
|
108
|
+
OperationIds
|
|
109
|
+
>;
|
|
110
|
+
|
|
111
|
+
export type UnifiedThreadOperationIds = MatchPrefix<
|
|
112
|
+
"UnifiedThreadOperations_",
|
|
113
|
+
OperationIds
|
|
114
|
+
>;
|
|
115
|
+
|
|
116
|
+
export type ThreadOperationIds = MatchPrefix<"ThreadOperations_", OperationIds>;
|
|
117
|
+
|
|
118
|
+
export type SemanticSearchOperationIds = MatchPrefix<
|
|
119
|
+
"SemanticSearchOperations_",
|
|
120
|
+
OperationIds
|
|
121
|
+
>;
|
|
122
|
+
|
|
123
|
+
export type MessageOperationIds = MatchPrefix<
|
|
124
|
+
"MessageOperations_",
|
|
125
|
+
OperationIds
|
|
126
|
+
>;
|
|
127
|
+
|
|
128
|
+
export type MessageBulkOperationIds = MatchPrefix<
|
|
129
|
+
"MessageBulkOperations_",
|
|
130
|
+
OperationIds
|
|
131
|
+
>;
|
|
132
|
+
|
|
133
|
+
export type TrashOperationIds = MatchPrefix<"TrashOperations_", OperationIds>;
|
|
134
|
+
|
|
135
|
+
export type OutboxOperationIds = MatchPrefix<"OutboxOperations_", OperationIds>;
|
|
136
|
+
|
|
137
|
+
export type OutboxDetailOperationIds = MatchPrefix<
|
|
138
|
+
"OutboxDetailOperations_",
|
|
139
|
+
OperationIds
|
|
140
|
+
>;
|
|
141
|
+
|
|
142
|
+
export type AddressOperationIds = MatchPrefix<
|
|
143
|
+
"AddressOperations_",
|
|
144
|
+
OperationIds
|
|
145
|
+
>;
|
|
146
|
+
|
|
147
|
+
export type AddressDetailOperationIds = MatchPrefix<
|
|
148
|
+
"AddressDetailOperations_",
|
|
149
|
+
OperationIds
|
|
150
|
+
>;
|
|
151
|
+
|
|
152
|
+
export type MicrosoftOAuthOperationIds = MatchPrefix<
|
|
153
|
+
"MicrosoftOAuthOperations_",
|
|
154
|
+
OperationIds
|
|
155
|
+
>;
|
|
156
|
+
|
|
157
|
+
// biome-ignore lint/suspicious/noExplicitAny: handler responses vary by operation
|
|
158
|
+
type HandlerResponse = Record<string, any>;
|
|
159
|
+
export type OperationHandler<_T extends OperationIds = OperationIds> = (
|
|
160
|
+
context: Context,
|
|
161
|
+
) => Promise<HandlerResponse>;
|