@remit/backend 0.0.60 → 0.0.62
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/package.json
CHANGED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { afterEach, describe, it } from "node:test";
|
|
3
|
+
import type { AddressItem, ResultList } from "@remit/data-ports";
|
|
4
|
+
import type { APIGatewayProxyEvent } from "aws-lambda";
|
|
5
|
+
import type { Context } from "openapi-backend";
|
|
6
|
+
import { deriveAccountConfigId } from "../auth.js";
|
|
7
|
+
import {
|
|
8
|
+
_resetForTest,
|
|
9
|
+
type RemitClient,
|
|
10
|
+
setClient,
|
|
11
|
+
} from "../service/data-client.js";
|
|
12
|
+
import { AddressOperations } from "./address.js";
|
|
13
|
+
|
|
14
|
+
const searchAddresses =
|
|
15
|
+
AddressOperations.AddressOperations_searchAddresses as unknown as (
|
|
16
|
+
context: Context,
|
|
17
|
+
event: APIGatewayProxyEvent,
|
|
18
|
+
) => Promise<ResultList<AddressItem>>;
|
|
19
|
+
|
|
20
|
+
const SUB = "cognito-sub-704";
|
|
21
|
+
const ACCOUNT_CONFIG_ID = deriveAccountConfigId(SUB);
|
|
22
|
+
|
|
23
|
+
const eventFor = (sub: string): APIGatewayProxyEvent =>
|
|
24
|
+
({
|
|
25
|
+
requestContext: { authorizer: { claims: { sub } } },
|
|
26
|
+
}) as unknown as APIGatewayProxyEvent;
|
|
27
|
+
|
|
28
|
+
const contextFor = (query: { q: string; limit?: number }): Context =>
|
|
29
|
+
({ request: { query } }) as unknown as Context;
|
|
30
|
+
|
|
31
|
+
const address = (over: Partial<AddressItem>): AddressItem =>
|
|
32
|
+
({
|
|
33
|
+
addressId: "addr-1",
|
|
34
|
+
accountConfigId: ACCOUNT_CONFIG_ID,
|
|
35
|
+
localPart: "amsterdam",
|
|
36
|
+
domain: "pocahondas.nl",
|
|
37
|
+
normalizedEmail: "amsterdam@pocahondas.nl",
|
|
38
|
+
normalizedCompound: "pocahondas locatie amsterdam amsterdam@pocahondas.nl",
|
|
39
|
+
displayName: "Pocahondas locatie amsterdam",
|
|
40
|
+
flags: {},
|
|
41
|
+
inboundCount: 4,
|
|
42
|
+
outboundCount: 1,
|
|
43
|
+
replyCount: 2,
|
|
44
|
+
lastInboundAt: 1_000,
|
|
45
|
+
lastReplyAt: 900,
|
|
46
|
+
createdAt: 100,
|
|
47
|
+
updatedAt: 200,
|
|
48
|
+
...over,
|
|
49
|
+
}) as AddressItem;
|
|
50
|
+
|
|
51
|
+
interface Listing {
|
|
52
|
+
accountConfigId: string;
|
|
53
|
+
search?: string;
|
|
54
|
+
limit?: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const clientReturning = (items: AddressItem[], seen: Listing[]): RemitClient =>
|
|
58
|
+
({
|
|
59
|
+
address: {
|
|
60
|
+
listByAccountConfig: async (
|
|
61
|
+
input: Listing,
|
|
62
|
+
): Promise<ResultList<AddressItem>> => {
|
|
63
|
+
seen.push(input);
|
|
64
|
+
return { items, continuationToken: undefined };
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}) as unknown as RemitClient;
|
|
68
|
+
|
|
69
|
+
afterEach(() => {
|
|
70
|
+
_resetForTest();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("AddressOperations_searchAddresses", () => {
|
|
74
|
+
it("looks a partial term up against the caller's own addresses (#704)", async () => {
|
|
75
|
+
const seen: Listing[] = [];
|
|
76
|
+
setClient(clientReturning([address({})], seen));
|
|
77
|
+
|
|
78
|
+
const response = await searchAddresses(
|
|
79
|
+
contextFor({ q: "Po", limit: 8 }),
|
|
80
|
+
eventFor(SUB),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
assert.deepEqual(seen, [
|
|
84
|
+
{ accountConfigId: ACCOUNT_CONFIG_ID, search: "po", limit: 8 },
|
|
85
|
+
]);
|
|
86
|
+
assert.deepEqual(
|
|
87
|
+
response.items.map((item) => item.normalizedEmail),
|
|
88
|
+
["amsterdam@pocahondas.nl"],
|
|
89
|
+
);
|
|
90
|
+
assert.equal(response.items[0].displayName, "Pocahondas locatie amsterdam");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("hands the suggestion list back in the order it was ranked", async () => {
|
|
94
|
+
const seen: Listing[] = [];
|
|
95
|
+
setClient(
|
|
96
|
+
clientReturning(
|
|
97
|
+
[
|
|
98
|
+
address({
|
|
99
|
+
addressId: "addr-frequent",
|
|
100
|
+
normalizedEmail: "zoe@pocahondas.nl",
|
|
101
|
+
}),
|
|
102
|
+
address({
|
|
103
|
+
addressId: "addr-stranger",
|
|
104
|
+
normalizedEmail: "aaron@pocahondas.nl",
|
|
105
|
+
inboundCount: 0,
|
|
106
|
+
replyCount: 0,
|
|
107
|
+
}),
|
|
108
|
+
],
|
|
109
|
+
seen,
|
|
110
|
+
),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const response = await searchAddresses(
|
|
114
|
+
contextFor({ q: "po" }),
|
|
115
|
+
eventFor(SUB),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
assert.deepEqual(
|
|
119
|
+
response.items.map((item) => item.addressId),
|
|
120
|
+
["addr-frequent", "addr-stranger"],
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("asks for a suggestion-sized window when the caller names no limit", async () => {
|
|
125
|
+
const seen: Listing[] = [];
|
|
126
|
+
setClient(clientReturning([], seen));
|
|
127
|
+
|
|
128
|
+
await searchAddresses(contextFor({ q: "po" }), eventFor(SUB));
|
|
129
|
+
|
|
130
|
+
assert.equal(seen[0].limit, 10);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
OutboxAttachmentRepo,
|
|
26
26
|
OutboxMessageRepo,
|
|
27
27
|
QuarantineRepo,
|
|
28
|
+
SenderSignerStandingRepo,
|
|
28
29
|
} from "@remit/drizzle-service";
|
|
29
30
|
import { env } from "expect-env";
|
|
30
31
|
import {
|
|
@@ -73,6 +74,7 @@ export const buildSqliteClient = async (): Promise<RemitClient> => {
|
|
|
73
74
|
filterAnchorTransaction: new DrizzleFilterAnchorTransaction(genericDb),
|
|
74
75
|
label: new LabelRepo(genericDb),
|
|
75
76
|
messageLabel: new MessageLabelRepo(genericDb),
|
|
77
|
+
senderSignerStanding: new SenderSignerStandingRepo(genericDb),
|
|
76
78
|
unitOfWork: new DrizzleUnitOfWork(messageDataDb),
|
|
77
79
|
};
|
|
78
80
|
|
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
IOutboxAttachmentRepository,
|
|
22
22
|
IOutboxMessageRepository,
|
|
23
23
|
IQuarantineRepository,
|
|
24
|
+
ISenderSignerStandingRepository,
|
|
24
25
|
IThreadMessageRepository,
|
|
25
26
|
IUnitOfWork,
|
|
26
27
|
} from "@remit/data-ports";
|
|
@@ -102,6 +103,12 @@ export interface RemitClient {
|
|
|
102
103
|
label: ILabelRepository;
|
|
103
104
|
messageLabel: IMessageLabelRepository;
|
|
104
105
|
|
|
106
|
+
// How often a sender has been seen arriving under one DKIM signing identity,
|
|
107
|
+
// per account. Read by the authenticity derivation to tell a familiar
|
|
108
|
+
// third-party signer from a first sighting; written once per message by
|
|
109
|
+
// body-sync, which is its only writer.
|
|
110
|
+
senderSignerStanding: ISenderSignerStandingRepository;
|
|
111
|
+
|
|
105
112
|
// Atomic write set for a message save. Present on the relational backend (real
|
|
106
113
|
// transaction); absent on DynamoDB, where callers fall back to per-repo
|
|
107
114
|
// writes with that backend's own (non-transactional) guarantees.
|
|
@@ -182,6 +189,7 @@ export interface RemitClientRepositories {
|
|
|
182
189
|
filterAnchorTransaction: IFilterAnchorTransaction;
|
|
183
190
|
label: ILabelRepository;
|
|
184
191
|
messageLabel: IMessageLabelRepository;
|
|
192
|
+
senderSignerStanding: ISenderSignerStandingRepository;
|
|
185
193
|
unitOfWork?: IUnitOfWork;
|
|
186
194
|
}
|
|
187
195
|
|
|
@@ -403,6 +411,7 @@ export const createRemitClient = (deps: RemitClientDeps): RemitClient => {
|
|
|
403
411
|
filterAnchorTransaction: repositories.filterAnchorTransaction,
|
|
404
412
|
label: repositories.label,
|
|
405
413
|
messageLabel: repositories.messageLabel,
|
|
414
|
+
senderSignerStanding: repositories.senderSignerStanding,
|
|
406
415
|
unitOfWork: repositories.unitOfWork,
|
|
407
416
|
|
|
408
417
|
storage,
|