@remit/data-ports 0.0.83 → 0.0.85
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/account-settings.d.ts +371 -0
- package/dist/account-settings.js +114 -0
- package/dist/conformance/account.d.ts +3 -0
- package/dist/conformance/account.js +118 -0
- package/dist/conformance/calendar-collection.d.ts +3 -0
- package/dist/conformance/calendar-collection.js +251 -0
- package/dist/conformance/calendar-event-index.d.ts +3 -0
- package/dist/conformance/calendar-event-index.js +114 -0
- package/dist/conformance/calendar-feed-token.d.ts +3 -0
- package/dist/conformance/calendar-feed-token.js +97 -0
- package/dist/conformance/calendar-object.d.ts +3 -0
- package/dist/conformance/calendar-object.js +156 -0
- package/dist/conformance/calendar-suggestion.d.ts +3 -0
- package/dist/conformance/calendar-suggestion.js +255 -0
- package/{src/conformance/harness.ts → dist/conformance/harness.d.ts} +4 -4
- package/dist/conformance/harness.js +1 -0
- package/dist/conformance/index.js +8 -0
- package/dist/conformance/label.d.ts +3 -0
- package/dist/conformance/label.js +92 -0
- package/dist/conformance/sender-signer-standing.d.ts +3 -0
- package/dist/conformance/sender-signer-standing.js +81 -0
- package/dist/display-name.d.ts +1 -0
- package/dist/display-name.js +26 -0
- package/dist/errors.d.ts +150 -0
- package/dist/errors.js +181 -0
- package/dist/filter-ttl.d.ts +7 -0
- package/{src/filter-ttl.ts → dist/filter-ttl.js} +8 -11
- package/dist/folder-role.d.ts +239 -0
- package/dist/folder-role.js +276 -0
- package/dist/id.d.ts +124 -0
- package/{src/id.ts → dist/id.js} +41 -127
- package/dist/index.d.ts +37 -0
- package/dist/index.js +5 -0
- package/dist/interfaces/account-config.d.ts +15 -0
- package/dist/interfaces/account-config.js +1 -0
- package/dist/interfaces/account-export-request.d.ts +10 -0
- package/dist/interfaces/account-export-request.js +1 -0
- package/dist/interfaces/account-setting.d.ts +8 -0
- package/dist/interfaces/account-setting.js +1 -0
- package/dist/interfaces/account.d.ts +29 -0
- package/dist/interfaces/account.js +1 -0
- package/dist/interfaces/address.d.ts +70 -0
- package/dist/interfaces/address.js +1 -0
- package/dist/interfaces/calendar-collection.d.ts +38 -0
- package/dist/interfaces/calendar-collection.js +1 -0
- package/dist/interfaces/calendar-event-index.d.ts +19 -0
- package/dist/interfaces/calendar-event-index.js +1 -0
- package/dist/interfaces/calendar-feed-token.d.ts +31 -0
- package/dist/interfaces/calendar-feed-token.js +1 -0
- package/dist/interfaces/calendar-object.d.ts +36 -0
- package/dist/interfaces/calendar-object.js +1 -0
- package/dist/interfaces/calendar-store.d.ts +93 -0
- package/dist/interfaces/calendar-store.js +1 -0
- package/dist/interfaces/calendar-suggestion.d.ts +62 -0
- package/dist/interfaces/calendar-suggestion.js +1 -0
- package/dist/interfaces/config-import.d.ts +8 -0
- package/dist/interfaces/config-import.js +1 -0
- package/dist/interfaces/envelope.d.ts +24 -0
- package/dist/interfaces/envelope.js +1 -0
- package/dist/interfaces/filter.d.ts +28 -0
- package/dist/interfaces/filter.js +1 -0
- package/dist/interfaces/label.d.ts +17 -0
- package/dist/interfaces/label.js +1 -0
- package/dist/interfaces/mailbox-lock.d.ts +12 -0
- package/dist/interfaces/mailbox-lock.js +1 -0
- package/dist/interfaces/mailbox-special-use.d.ts +54 -0
- package/dist/interfaces/mailbox-special-use.js +1 -0
- package/dist/interfaces/mailbox.d.ts +79 -0
- package/dist/interfaces/mailbox.js +1 -0
- package/dist/interfaces/message-flag-push.d.ts +9 -0
- package/dist/interfaces/message-flag-push.js +1 -0
- package/dist/interfaces/message-flag.d.ts +14 -0
- package/dist/interfaces/message-flag.js +1 -0
- package/dist/interfaces/message-label.d.ts +21 -0
- package/dist/interfaces/message-label.js +1 -0
- package/dist/interfaces/message-placement-move.d.ts +8 -0
- package/dist/interfaces/message-placement-move.js +1 -0
- package/dist/interfaces/message.d.ts +60 -0
- package/dist/interfaces/message.js +1 -0
- package/dist/interfaces/organize-job-request.d.ts +10 -0
- package/dist/interfaces/organize-job-request.js +1 -0
- package/dist/interfaces/outbox-attachment.d.ts +101 -0
- package/dist/interfaces/outbox-attachment.js +7 -0
- package/dist/interfaces/outbox-message.d.ts +70 -0
- package/dist/interfaces/outbox-message.js +20 -0
- package/dist/interfaces/quarantine.d.ts +20 -0
- package/dist/interfaces/quarantine.js +1 -0
- package/dist/interfaces/sender-signer-standing.d.ts +26 -0
- package/dist/interfaces/sender-signer-standing.js +1 -0
- package/dist/interfaces/sync-warning.d.ts +11 -0
- package/dist/interfaces/sync-warning.js +1 -0
- package/dist/interfaces/thread-message.d.ts +202 -0
- package/dist/interfaces/thread-message.js +1 -0
- package/dist/mailbox-name.d.ts +35 -0
- package/dist/mailbox-name.js +68 -0
- package/dist/message-parts.d.ts +22 -0
- package/dist/message-parts.js +18 -0
- package/dist/message-settlement.d.ts +35 -0
- package/{src/message-settlement.ts → dist/message-settlement.js} +5 -19
- package/dist/mutation-events.d.ts +19 -0
- package/{src/mutation-events.ts → dist/mutation-events.js} +2 -5
- package/dist/sender-mute.d.ts +26 -0
- package/{src/sender-mute.ts → dist/sender-mute.js} +12 -34
- package/dist/sync-warning-state.d.ts +3 -0
- package/dist/sync-warning-state.js +5 -0
- package/dist/types.d.ts +491 -0
- package/dist/types.js +1 -0
- package/dist/update-manifest.d.ts +24 -0
- package/dist/update-manifest.js +20 -0
- package/dist/virtual-copy.d.ts +8 -0
- package/{src/virtual-copy.ts → dist/virtual-copy.js} +10 -15
- package/dist/wellknown.d.ts +47 -0
- package/{src/wellknown.ts → dist/wellknown.js} +26 -49
- package/package.json +44 -79
- package/src/account-settings.ts +0 -194
- package/src/conformance/account.ts +0 -104
- package/src/conformance/calendar-collection.ts +0 -342
- package/src/conformance/calendar-event-index.ts +0 -203
- package/src/conformance/calendar-feed-token.ts +0 -148
- package/src/conformance/calendar-object.ts +0 -269
- package/src/conformance/calendar-suggestion.ts +0 -490
- package/src/conformance/label.ts +0 -136
- package/src/conformance/sender-signer-standing.ts +0 -117
- package/src/display-name.test.ts +0 -101
- package/src/display-name.ts +0 -40
- package/src/errors.ts +0 -244
- package/src/folder-role.test.ts +0 -422
- package/src/folder-role.ts +0 -447
- package/src/id.test.ts +0 -352
- package/src/index.ts +0 -170
- package/src/interfaces/account-config.ts +0 -25
- package/src/interfaces/account-export-request.ts +0 -21
- package/src/interfaces/account-setting.ts +0 -14
- package/src/interfaces/account.ts +0 -43
- package/src/interfaces/address.ts +0 -122
- package/src/interfaces/calendar-collection.ts +0 -60
- package/src/interfaces/calendar-event-index.ts +0 -34
- package/src/interfaces/calendar-feed-token.ts +0 -38
- package/src/interfaces/calendar-object.ts +0 -58
- package/src/interfaces/calendar-suggestion.ts +0 -93
- package/src/interfaces/calendar-unit-of-work.ts +0 -47
- package/src/interfaces/config-import.ts +0 -16
- package/src/interfaces/envelope.ts +0 -32
- package/src/interfaces/filter-anchor-transaction.ts +0 -23
- package/src/interfaces/filter-anchor.ts +0 -11
- package/src/interfaces/filter.ts +0 -41
- package/src/interfaces/label.ts +0 -30
- package/src/interfaces/mailbox-lock.ts +0 -32
- package/src/interfaces/mailbox-special-use.ts +0 -60
- package/src/interfaces/mailbox.ts +0 -115
- package/src/interfaces/message-flag-push.ts +0 -17
- package/src/interfaces/message-flag.ts +0 -15
- package/src/interfaces/message-label.ts +0 -25
- package/src/interfaces/message-placement-move.ts +0 -15
- package/src/interfaces/message.ts +0 -65
- package/src/interfaces/organize-job-request.ts +0 -19
- package/src/interfaces/outbox-attachment.ts +0 -132
- package/src/interfaces/outbox-message.ts +0 -106
- package/src/interfaces/quarantine.ts +0 -22
- package/src/interfaces/sender-signer-standing.ts +0 -37
- package/src/interfaces/thread-message.ts +0 -264
- package/src/interfaces/unit-of-work.ts +0 -28
- package/src/mailbox-name.test.ts +0 -106
- package/src/mailbox-name.ts +0 -90
- package/src/mailbox-state-doors.test.ts +0 -104
- package/src/message-placement-doors.test.ts +0 -100
- package/src/message-settlement.test.ts +0 -132
- package/src/sender-mute.test.ts +0 -76
- package/src/types.ts +0 -820
- package/src/update-manifest.test.ts +0 -130
- package/src/update-manifest.ts +0 -22
- package/src/virtual-copy.test.ts +0 -34
- package/tsconfig.json +0 -8
- /package/{src/conformance/index.ts → dist/conformance/index.d.ts} +0 -0
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { after, before, describe, test } from "node:test";
|
|
3
|
-
import {
|
|
4
|
-
CalendarInviteMethod,
|
|
5
|
-
CalendarSuggestionSource,
|
|
6
|
-
CalendarSuggestionState,
|
|
7
|
-
ZoneCertainty,
|
|
8
|
-
} from "@remit/domain-enums";
|
|
9
|
-
import { deriveCalendarSuggestionId } from "../id.js";
|
|
10
|
-
import type { ICalendarSuggestionRepository } from "../interfaces/calendar-suggestion.js";
|
|
11
|
-
import type { PutCalendarSuggestionInput } from "../types.js";
|
|
12
|
-
import type { RepositoryConformanceHarness } from "./harness.js";
|
|
13
|
-
|
|
14
|
-
const suggestion = (
|
|
15
|
-
accountConfigId: string,
|
|
16
|
-
messageId: string,
|
|
17
|
-
bodyPartId: string,
|
|
18
|
-
icalUid: string,
|
|
19
|
-
overrides: Partial<PutCalendarSuggestionInput> = {},
|
|
20
|
-
): PutCalendarSuggestionInput => ({
|
|
21
|
-
accountConfigId,
|
|
22
|
-
messageId,
|
|
23
|
-
bodyPartId,
|
|
24
|
-
icalUid,
|
|
25
|
-
sequence: 0,
|
|
26
|
-
method: CalendarInviteMethod.Request,
|
|
27
|
-
source: CalendarSuggestionSource.IcalendarPart,
|
|
28
|
-
summary: "Design review",
|
|
29
|
-
dtStart: "2026-09-01T10:00:00+02:00",
|
|
30
|
-
dtEnd: "2026-09-01T11:00:00+02:00",
|
|
31
|
-
endsAtUtc: "2026-09-01T09:00:00Z",
|
|
32
|
-
allDay: false,
|
|
33
|
-
location: "",
|
|
34
|
-
organizer: "organizer@example.test",
|
|
35
|
-
zoneCertainty: ZoneCertainty.Explicit,
|
|
36
|
-
icalData: "BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n",
|
|
37
|
-
...overrides,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const EARLIEST_INSTANT = "1970-01-01T00:00:00.000Z";
|
|
41
|
-
|
|
42
|
-
export function calendarSuggestionRepositoryConformance(
|
|
43
|
-
harness: RepositoryConformanceHarness<ICalendarSuggestionRepository>,
|
|
44
|
-
): void {
|
|
45
|
-
describe("ICalendarSuggestionRepository conformance", () => {
|
|
46
|
-
let repo: ICalendarSuggestionRepository;
|
|
47
|
-
|
|
48
|
-
before(async () => {
|
|
49
|
-
repo = await harness.createRepository();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
after(() => harness.teardown());
|
|
53
|
-
|
|
54
|
-
test("put writes a Pending suggestion under its derived id", async () => {
|
|
55
|
-
const accountConfigId = harness.makeId();
|
|
56
|
-
const messageId = harness.makeId();
|
|
57
|
-
const bodyPartId = harness.makeId();
|
|
58
|
-
|
|
59
|
-
const written = await repo.put(
|
|
60
|
-
suggestion(accountConfigId, messageId, bodyPartId, "uid-1"),
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
assert.equal(
|
|
64
|
-
written.suggestionId,
|
|
65
|
-
deriveCalendarSuggestionId(messageId, bodyPartId, "uid-1"),
|
|
66
|
-
);
|
|
67
|
-
assert.equal(written.state, CalendarSuggestionState.Pending);
|
|
68
|
-
assert.equal(written.acceptedCalendarObjectId, "");
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test("put re-reading the same message converges on one row", async () => {
|
|
72
|
-
const accountConfigId = harness.makeId();
|
|
73
|
-
const messageId = harness.makeId();
|
|
74
|
-
const bodyPartId = harness.makeId();
|
|
75
|
-
|
|
76
|
-
await repo.put(
|
|
77
|
-
suggestion(accountConfigId, messageId, bodyPartId, "uid-1"),
|
|
78
|
-
);
|
|
79
|
-
await repo.put(
|
|
80
|
-
suggestion(accountConfigId, messageId, bodyPartId, "uid-1", {
|
|
81
|
-
summary: "Design review, moved",
|
|
82
|
-
}),
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
const rows = await repo.listByMessage(accountConfigId, messageId);
|
|
86
|
-
assert.equal(rows.length, 1);
|
|
87
|
-
assert.equal(rows[0]?.summary, "Design review, moved");
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("put leaves an answered suggestion answered", async () => {
|
|
91
|
-
// A re-sync must never walk a decision back to Pending: the user
|
|
92
|
-
// already added this event to a calendar, and a producer write is not
|
|
93
|
-
// allowed to un-decide that.
|
|
94
|
-
const accountConfigId = harness.makeId();
|
|
95
|
-
const messageId = harness.makeId();
|
|
96
|
-
const bodyPartId = harness.makeId();
|
|
97
|
-
|
|
98
|
-
const written = await repo.put(
|
|
99
|
-
suggestion(accountConfigId, messageId, bodyPartId, "uid-1"),
|
|
100
|
-
);
|
|
101
|
-
await repo.settle(accountConfigId, written.suggestionId, {
|
|
102
|
-
state: CalendarSuggestionState.Accepted,
|
|
103
|
-
acceptedCalendarObjectId: "cal-object-1",
|
|
104
|
-
});
|
|
105
|
-
await repo.put(
|
|
106
|
-
suggestion(accountConfigId, messageId, bodyPartId, "uid-1"),
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
110
|
-
assert.equal(reread.state, CalendarSuggestionState.Accepted);
|
|
111
|
-
assert.equal(reread.acceptedCalendarObjectId, "cal-object-1");
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test("get rejects a suggestion that is not there", async () => {
|
|
115
|
-
const accountConfigId = harness.makeId();
|
|
116
|
-
await assert.rejects(
|
|
117
|
-
() => repo.get(accountConfigId, harness.makeId()),
|
|
118
|
-
(error: unknown) => harness.isNotFoundError(error),
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test("get scopes to the account config", async () => {
|
|
123
|
-
const accountConfigId = harness.makeId();
|
|
124
|
-
const written = await repo.put(
|
|
125
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
await assert.rejects(
|
|
129
|
-
() => repo.get(harness.makeId(), written.suggestionId),
|
|
130
|
-
(error: unknown) => harness.isNotFoundError(error),
|
|
131
|
-
);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test("listByMessage returns every suggestion one message produced", async () => {
|
|
135
|
-
const accountConfigId = harness.makeId();
|
|
136
|
-
const messageId = harness.makeId();
|
|
137
|
-
const other = harness.makeId();
|
|
138
|
-
|
|
139
|
-
await repo.put(
|
|
140
|
-
suggestion(accountConfigId, messageId, harness.makeId(), "uid-a"),
|
|
141
|
-
);
|
|
142
|
-
await repo.put(
|
|
143
|
-
suggestion(accountConfigId, messageId, harness.makeId(), "uid-b"),
|
|
144
|
-
);
|
|
145
|
-
await repo.put(
|
|
146
|
-
suggestion(accountConfigId, other, harness.makeId(), "uid-c"),
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const rows = await repo.listByMessage(accountConfigId, messageId);
|
|
150
|
-
assert.deepEqual(rows.map((row) => row.icalUid).sort(), [
|
|
151
|
-
"uid-a",
|
|
152
|
-
"uid-b",
|
|
153
|
-
]);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test("listByState returns only the state asked for", async () => {
|
|
157
|
-
const accountConfigId = harness.makeId();
|
|
158
|
-
const pending = await repo.put(
|
|
159
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "p"),
|
|
160
|
-
);
|
|
161
|
-
const declined = await repo.put(
|
|
162
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "d"),
|
|
163
|
-
);
|
|
164
|
-
await repo.settle(accountConfigId, declined.suggestionId, {
|
|
165
|
-
state: CalendarSuggestionState.Declined,
|
|
166
|
-
acceptedCalendarObjectId: "",
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const page = await repo.listByState(
|
|
170
|
-
accountConfigId,
|
|
171
|
-
CalendarSuggestionState.Pending,
|
|
172
|
-
{ endsAfter: EARLIEST_INSTANT },
|
|
173
|
-
);
|
|
174
|
-
assert.deepEqual(
|
|
175
|
-
page.items.map((row) => row.suggestionId),
|
|
176
|
-
[pending.suggestionId],
|
|
177
|
-
);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test("listByState drops a suggestion that ended before endsAfter, comparing instants across offsets", async () => {
|
|
181
|
-
const accountConfigId = harness.makeId();
|
|
182
|
-
await repo.put(
|
|
183
|
-
suggestion(
|
|
184
|
-
accountConfigId,
|
|
185
|
-
harness.makeId(),
|
|
186
|
-
harness.makeId(),
|
|
187
|
-
"ended",
|
|
188
|
-
{
|
|
189
|
-
dtEnd: "2026-10-06T23:00:00+14:00",
|
|
190
|
-
endsAtUtc: "2026-10-06T09:00:00Z",
|
|
191
|
-
},
|
|
192
|
-
),
|
|
193
|
-
);
|
|
194
|
-
const running = await repo.put(
|
|
195
|
-
suggestion(
|
|
196
|
-
accountConfigId,
|
|
197
|
-
harness.makeId(),
|
|
198
|
-
harness.makeId(),
|
|
199
|
-
"running",
|
|
200
|
-
{
|
|
201
|
-
dtEnd: "2026-10-06T01:00:00-12:00",
|
|
202
|
-
endsAtUtc: "2026-10-06T13:00:00Z",
|
|
203
|
-
},
|
|
204
|
-
),
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
const page = await repo.listByState(
|
|
208
|
-
accountConfigId,
|
|
209
|
-
CalendarSuggestionState.Pending,
|
|
210
|
-
{ endsAfter: "2026-10-06T10:00:00Z" },
|
|
211
|
-
);
|
|
212
|
-
assert.deepEqual(
|
|
213
|
-
page.items.map((row) => row.suggestionId),
|
|
214
|
-
[running.suggestionId],
|
|
215
|
-
);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
test("listByState keeps a suggestion ending exactly at endsAfter", async () => {
|
|
219
|
-
const accountConfigId = harness.makeId();
|
|
220
|
-
const boundary = await repo.put(
|
|
221
|
-
suggestion(
|
|
222
|
-
accountConfigId,
|
|
223
|
-
harness.makeId(),
|
|
224
|
-
harness.makeId(),
|
|
225
|
-
"edge",
|
|
226
|
-
{
|
|
227
|
-
endsAtUtc: "2026-10-06T10:00:00Z",
|
|
228
|
-
},
|
|
229
|
-
),
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const page = await repo.listByState(
|
|
233
|
-
accountConfigId,
|
|
234
|
-
CalendarSuggestionState.Pending,
|
|
235
|
-
{ endsAfter: "2026-10-06T10:00:00Z" },
|
|
236
|
-
);
|
|
237
|
-
assert.deepEqual(
|
|
238
|
-
page.items.map((row) => row.suggestionId),
|
|
239
|
-
[boundary.suggestionId],
|
|
240
|
-
);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
test("listByState scopes to the account config", async () => {
|
|
244
|
-
const accountConfigId = harness.makeId();
|
|
245
|
-
await repo.put(
|
|
246
|
-
suggestion(harness.makeId(), harness.makeId(), harness.makeId(), "x"),
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
const page = await repo.listByState(
|
|
250
|
-
accountConfigId,
|
|
251
|
-
CalendarSuggestionState.Pending,
|
|
252
|
-
{ endsAfter: EARLIEST_INSTANT },
|
|
253
|
-
);
|
|
254
|
-
assert.equal(page.items.length, 0);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
test("listByState pages, and the token resumes where the page stopped", async () => {
|
|
258
|
-
const accountConfigId = harness.makeId();
|
|
259
|
-
for (const uid of ["a", "b", "c"]) {
|
|
260
|
-
await repo.put(
|
|
261
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), uid),
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const first = await repo.listByState(
|
|
266
|
-
accountConfigId,
|
|
267
|
-
CalendarSuggestionState.Pending,
|
|
268
|
-
{ endsAfter: EARLIEST_INSTANT, limit: 2 },
|
|
269
|
-
);
|
|
270
|
-
assert.equal(first.items.length, 2);
|
|
271
|
-
assert.ok(first.continuationToken);
|
|
272
|
-
|
|
273
|
-
const second = await repo.listByState(
|
|
274
|
-
accountConfigId,
|
|
275
|
-
CalendarSuggestionState.Pending,
|
|
276
|
-
{
|
|
277
|
-
endsAfter: EARLIEST_INSTANT,
|
|
278
|
-
limit: 2,
|
|
279
|
-
continuationToken: first.continuationToken,
|
|
280
|
-
},
|
|
281
|
-
);
|
|
282
|
-
const seen = [...first.items, ...second.items].map(
|
|
283
|
-
(row) => row.suggestionId,
|
|
284
|
-
);
|
|
285
|
-
assert.equal(new Set(seen).size, 3);
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
test("listByAcceptedCalendarObjects returns, in one read, the account's suggestions answered into any of the resources", async () => {
|
|
289
|
-
const accountConfigId = harness.makeId();
|
|
290
|
-
const first = await repo.put(
|
|
291
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
292
|
-
);
|
|
293
|
-
const second = await repo.put(
|
|
294
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
295
|
-
);
|
|
296
|
-
const elsewhere = await repo.put(
|
|
297
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
298
|
-
);
|
|
299
|
-
const unasked = await repo.put(
|
|
300
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
301
|
-
);
|
|
302
|
-
const stranger = harness.makeId();
|
|
303
|
-
const strangers = await repo.put(
|
|
304
|
-
suggestion(stranger, harness.makeId(), harness.makeId(), "uid"),
|
|
305
|
-
);
|
|
306
|
-
for (const [owner, row, objectId] of [
|
|
307
|
-
[accountConfigId, first, "cal-object-1"],
|
|
308
|
-
[accountConfigId, second, "cal-object-1"],
|
|
309
|
-
[accountConfigId, elsewhere, "cal-object-2"],
|
|
310
|
-
[accountConfigId, unasked, "cal-object-3"],
|
|
311
|
-
[stranger, strangers, "cal-object-1"],
|
|
312
|
-
] as const) {
|
|
313
|
-
await repo.settle(owner, row.suggestionId, {
|
|
314
|
-
state: CalendarSuggestionState.Accepted,
|
|
315
|
-
acceptedCalendarObjectId: objectId,
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const rows = await repo.listByAcceptedCalendarObjects(accountConfigId, [
|
|
320
|
-
"cal-object-1",
|
|
321
|
-
"cal-object-2",
|
|
322
|
-
]);
|
|
323
|
-
|
|
324
|
-
assert.deepEqual(
|
|
325
|
-
rows.map((row) => row.suggestionId).sort(),
|
|
326
|
-
[
|
|
327
|
-
first.suggestionId,
|
|
328
|
-
second.suggestionId,
|
|
329
|
-
elsewhere.suggestionId,
|
|
330
|
-
].sort(),
|
|
331
|
-
);
|
|
332
|
-
assert.deepEqual(
|
|
333
|
-
await repo.listByAcceptedCalendarObjects(accountConfigId, []),
|
|
334
|
-
[],
|
|
335
|
-
);
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
test("settle records the accepted resource", async () => {
|
|
339
|
-
const accountConfigId = harness.makeId();
|
|
340
|
-
const written = await repo.put(
|
|
341
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
342
|
-
);
|
|
343
|
-
|
|
344
|
-
const settled = await repo.settle(accountConfigId, written.suggestionId, {
|
|
345
|
-
state: CalendarSuggestionState.Accepted,
|
|
346
|
-
acceptedCalendarObjectId: "cal-object-9",
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
assert.equal(settled.state, CalendarSuggestionState.Accepted);
|
|
350
|
-
assert.equal(settled.acceptedCalendarObjectId, "cal-object-9");
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
test("supersedeIfPending retires a card still waiting on the user", async () => {
|
|
354
|
-
const accountConfigId = harness.makeId();
|
|
355
|
-
const written = await repo.put(
|
|
356
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
const newerMessageId = harness.makeId();
|
|
360
|
-
const retired = await repo.supersedeIfPending(
|
|
361
|
-
accountConfigId,
|
|
362
|
-
written.suggestionId,
|
|
363
|
-
newerMessageId,
|
|
364
|
-
);
|
|
365
|
-
|
|
366
|
-
assert.equal(retired?.state, CalendarSuggestionState.Superseded);
|
|
367
|
-
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
368
|
-
assert.equal(reread.supersededByMessageId, newerMessageId);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
test("a re-read of the retired message keeps the revision that retired it", async () => {
|
|
372
|
-
const accountConfigId = harness.makeId();
|
|
373
|
-
const input = suggestion(
|
|
374
|
-
accountConfigId,
|
|
375
|
-
harness.makeId(),
|
|
376
|
-
harness.makeId(),
|
|
377
|
-
"uid",
|
|
378
|
-
);
|
|
379
|
-
const written = await repo.put(input);
|
|
380
|
-
const newerMessageId = harness.makeId();
|
|
381
|
-
await repo.supersedeIfPending(
|
|
382
|
-
accountConfigId,
|
|
383
|
-
written.suggestionId,
|
|
384
|
-
newerMessageId,
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
const rewritten = await repo.put(input);
|
|
388
|
-
|
|
389
|
-
assert.equal(rewritten.state, CalendarSuggestionState.Superseded);
|
|
390
|
-
assert.equal(rewritten.supersededByMessageId, newerMessageId);
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
test("supersedeIfPending leaves an answered card alone and says so", async () => {
|
|
394
|
-
// The producer reads the pending set and writes to it in two steps. A
|
|
395
|
-
// person accepting in between must keep their acceptance — and the
|
|
396
|
-
// link to the event it put in their calendar.
|
|
397
|
-
const accountConfigId = harness.makeId();
|
|
398
|
-
const written = await repo.put(
|
|
399
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
400
|
-
);
|
|
401
|
-
await repo.settle(accountConfigId, written.suggestionId, {
|
|
402
|
-
state: CalendarSuggestionState.Accepted,
|
|
403
|
-
acceptedCalendarObjectId: "cal-object-7",
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
const retired = await repo.supersedeIfPending(
|
|
407
|
-
accountConfigId,
|
|
408
|
-
written.suggestionId,
|
|
409
|
-
harness.makeId(),
|
|
410
|
-
);
|
|
411
|
-
|
|
412
|
-
assert.equal(retired, null);
|
|
413
|
-
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
414
|
-
assert.equal(reread.state, CalendarSuggestionState.Accepted);
|
|
415
|
-
assert.equal(reread.supersededByMessageId, "");
|
|
416
|
-
assert.equal(reread.acceptedCalendarObjectId, "cal-object-7");
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
test("supersedeIfPending scopes to the account config", async () => {
|
|
420
|
-
const accountConfigId = harness.makeId();
|
|
421
|
-
const written = await repo.put(
|
|
422
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
423
|
-
);
|
|
424
|
-
|
|
425
|
-
assert.equal(
|
|
426
|
-
await repo.supersedeIfPending(
|
|
427
|
-
harness.makeId(),
|
|
428
|
-
written.suggestionId,
|
|
429
|
-
harness.makeId(),
|
|
430
|
-
),
|
|
431
|
-
null,
|
|
432
|
-
);
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
test("repointSuperseded moves a retired card to a later revision", async () => {
|
|
436
|
-
const accountConfigId = harness.makeId();
|
|
437
|
-
const written = await repo.put(
|
|
438
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
439
|
-
);
|
|
440
|
-
await repo.supersedeIfPending(
|
|
441
|
-
accountConfigId,
|
|
442
|
-
written.suggestionId,
|
|
443
|
-
harness.makeId(),
|
|
444
|
-
);
|
|
445
|
-
const newest = harness.makeId();
|
|
446
|
-
|
|
447
|
-
const repointed = await repo.repointSuperseded(
|
|
448
|
-
accountConfigId,
|
|
449
|
-
written.suggestionId,
|
|
450
|
-
newest,
|
|
451
|
-
);
|
|
452
|
-
|
|
453
|
-
assert.equal(repointed?.supersededByMessageId, newest);
|
|
454
|
-
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
455
|
-
assert.equal(reread.state, CalendarSuggestionState.Superseded);
|
|
456
|
-
assert.equal(reread.supersededByMessageId, newest);
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
test("repointSuperseded leaves a card that is not superseded alone", async () => {
|
|
460
|
-
const accountConfigId = harness.makeId();
|
|
461
|
-
const written = await repo.put(
|
|
462
|
-
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
463
|
-
);
|
|
464
|
-
|
|
465
|
-
assert.equal(
|
|
466
|
-
await repo.repointSuperseded(
|
|
467
|
-
accountConfigId,
|
|
468
|
-
written.suggestionId,
|
|
469
|
-
harness.makeId(),
|
|
470
|
-
),
|
|
471
|
-
null,
|
|
472
|
-
);
|
|
473
|
-
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
474
|
-
assert.equal(reread.state, CalendarSuggestionState.Pending);
|
|
475
|
-
assert.equal(reread.supersededByMessageId, "");
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
test("settle rejects a suggestion that is not there", async () => {
|
|
479
|
-
const accountConfigId = harness.makeId();
|
|
480
|
-
await assert.rejects(
|
|
481
|
-
() =>
|
|
482
|
-
repo.settle(accountConfigId, harness.makeId(), {
|
|
483
|
-
state: CalendarSuggestionState.Declined,
|
|
484
|
-
acceptedCalendarObjectId: "",
|
|
485
|
-
}),
|
|
486
|
-
(error: unknown) => harness.isNotFoundError(error),
|
|
487
|
-
);
|
|
488
|
-
});
|
|
489
|
-
});
|
|
490
|
-
}
|
package/src/conformance/label.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { after, before, describe, test } from "node:test";
|
|
3
|
-
import { LabelColor } from "@remit/domain-enums";
|
|
4
|
-
import type { ILabelRepository } from "../interfaces/label.js";
|
|
5
|
-
import type { RepositoryConformanceHarness } from "./harness.js";
|
|
6
|
-
|
|
7
|
-
export function labelRepositoryConformance(
|
|
8
|
-
harness: RepositoryConformanceHarness<ILabelRepository>,
|
|
9
|
-
): void {
|
|
10
|
-
describe("ILabelRepository conformance", () => {
|
|
11
|
-
let repo: ILabelRepository;
|
|
12
|
-
|
|
13
|
-
before(async () => {
|
|
14
|
-
repo = await harness.createRepository();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
after(() => harness.teardown());
|
|
18
|
-
|
|
19
|
-
test("create derives normalizedName and defaults color", async () => {
|
|
20
|
-
const accountConfigId = harness.makeId();
|
|
21
|
-
|
|
22
|
-
const label = await repo.create({
|
|
23
|
-
accountConfigId,
|
|
24
|
-
name: " Receipts ",
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
assert.equal(label.name, " Receipts ");
|
|
28
|
-
assert.equal(label.normalizedName, "receipts");
|
|
29
|
-
assert.equal(label.color, LabelColor.Default);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("get throws a not-found error for a missing label", async () => {
|
|
33
|
-
await assert.rejects(
|
|
34
|
-
repo.get(harness.makeId(), harness.makeId()),
|
|
35
|
-
(error) => harness.isNotFoundError(error),
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("update re-derives normalizedName when the name changes", async () => {
|
|
40
|
-
const accountConfigId = harness.makeId();
|
|
41
|
-
const label = await repo.create({ accountConfigId, name: "Old Name" });
|
|
42
|
-
|
|
43
|
-
const updated = await repo.update(accountConfigId, label.labelId, {
|
|
44
|
-
name: "New Name",
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
assert.equal(updated.name, "New Name");
|
|
48
|
-
assert.equal(updated.normalizedName, "new name");
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("update throws a not-found error for a missing label", async () => {
|
|
52
|
-
await assert.rejects(
|
|
53
|
-
repo.update(harness.makeId(), harness.makeId(), { name: "x" }),
|
|
54
|
-
(error) => harness.isNotFoundError(error),
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("listByAccountConfig scopes to the account", async () => {
|
|
59
|
-
const accountConfigId = harness.makeId();
|
|
60
|
-
const other = harness.makeId();
|
|
61
|
-
|
|
62
|
-
const mine = await repo.create({ accountConfigId, name: "Mine" });
|
|
63
|
-
await repo.create({ accountConfigId: other, name: "Foreign" });
|
|
64
|
-
|
|
65
|
-
const labels = await repo.listByAccountConfig(accountConfigId);
|
|
66
|
-
assert.equal(labels.length, 1);
|
|
67
|
-
assert.equal(labels[0]?.labelId, mine.labelId);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("findByNormalizedName dedupes case- and whitespace-insensitively", async () => {
|
|
71
|
-
const accountConfigId = harness.makeId();
|
|
72
|
-
const label = await repo.create({ accountConfigId, name: "Work" });
|
|
73
|
-
|
|
74
|
-
const found = await repo.findByNormalizedName(accountConfigId, "WORK");
|
|
75
|
-
assert.equal(found?.labelId, label.labelId);
|
|
76
|
-
|
|
77
|
-
const missing = await repo.findByNormalizedName(
|
|
78
|
-
accountConfigId,
|
|
79
|
-
"nonexistent",
|
|
80
|
-
);
|
|
81
|
-
assert.equal(missing, null);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("listPageByAccountConfig pages through an account's labels, scoped to the account", async () => {
|
|
85
|
-
const accountConfigId = harness.makeId();
|
|
86
|
-
const other = harness.makeId();
|
|
87
|
-
|
|
88
|
-
// Created concurrently so their `createdAt` millisecond can tie (as it
|
|
89
|
-
// reliably does against the synchronous sqlite driver): the keyset's
|
|
90
|
-
// `labelId` tiebreak then decides order, so this asserts pagination is
|
|
91
|
-
// exhaustive and duplicate-free rather than a specific creation order.
|
|
92
|
-
const created = await Promise.all([
|
|
93
|
-
repo.create({ accountConfigId, name: "First" }),
|
|
94
|
-
repo.create({ accountConfigId, name: "Second" }),
|
|
95
|
-
]);
|
|
96
|
-
await repo.create({ accountConfigId: other, name: "Foreign" });
|
|
97
|
-
|
|
98
|
-
const page1 = await repo.listPageByAccountConfig(accountConfigId, {
|
|
99
|
-
limit: 1,
|
|
100
|
-
});
|
|
101
|
-
assert.equal(page1.items.length, 1);
|
|
102
|
-
assert.ok(page1.continuationToken);
|
|
103
|
-
|
|
104
|
-
const page2 = await repo.listPageByAccountConfig(accountConfigId, {
|
|
105
|
-
limit: 1,
|
|
106
|
-
continuationToken: page1.continuationToken,
|
|
107
|
-
});
|
|
108
|
-
assert.equal(page2.items.length, 1);
|
|
109
|
-
assert.equal(page2.continuationToken, undefined);
|
|
110
|
-
|
|
111
|
-
const seen = new Set([
|
|
112
|
-
...page1.items.map((label) => label.labelId),
|
|
113
|
-
...page2.items.map((label) => label.labelId),
|
|
114
|
-
]);
|
|
115
|
-
assert.equal(
|
|
116
|
-
seen.size,
|
|
117
|
-
created.length,
|
|
118
|
-
"every label is paged exactly once",
|
|
119
|
-
);
|
|
120
|
-
for (const label of created) {
|
|
121
|
-
assert.ok(seen.has(label.labelId));
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("delete removes the row", async () => {
|
|
126
|
-
const accountConfigId = harness.makeId();
|
|
127
|
-
const label = await repo.create({ accountConfigId, name: "Gone" });
|
|
128
|
-
|
|
129
|
-
await repo.delete(accountConfigId, label.labelId);
|
|
130
|
-
|
|
131
|
-
await assert.rejects(repo.get(accountConfigId, label.labelId), (error) =>
|
|
132
|
-
harness.isNotFoundError(error),
|
|
133
|
-
);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
}
|