@remit/account-worker 0.0.33 → 0.0.35

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/src/process.ts CHANGED
@@ -6,9 +6,18 @@ import type { DeletionCapabilities } from "./deletion-port.js";
6
6
  import type {
7
7
  AccountDataPurgeEvent,
8
8
  AccountDataPurgeFinalizeEvent,
9
+ AccountDeleteEvent,
10
+ AccountDeleteFinalizeEvent,
11
+ AccountExportEvent,
12
+ AccountFinalizeEvent,
9
13
  OrganizeJobEvent,
10
14
  SenderCategoryBackApplyEvent,
11
15
  } from "./events.js";
16
+ import {
17
+ finalizeAccountDelete,
18
+ processAccountDelete,
19
+ } from "./handlers/account-delete.js";
20
+ import { processAccountExport } from "./handlers/account-export.js";
12
21
  import { processAccountDataPurge } from "./handlers/account-purge.js";
13
22
  import { processAccountDataPurgeFinalize } from "./handlers/account-purge-finalize.js";
14
23
  import { processOrganizeJob } from "./handlers/organize-job.js";
@@ -16,7 +25,14 @@ import { processSenderCategoryBackApply } from "./handlers/sender-category-backa
16
25
 
17
26
  export type { CascadeEntity } from "./cascade.js";
18
27
  export type { DeletionCapabilities } from "./deletion-port.js";
19
- export type { AccountDataPurgeEvent, AccountDataPurgeFinalizeEvent };
28
+ export type {
29
+ AccountDataPurgeEvent,
30
+ AccountDataPurgeFinalizeEvent,
31
+ AccountDeleteEvent,
32
+ AccountDeleteFinalizeEvent,
33
+ AccountExportEvent,
34
+ AccountFinalizeEvent,
35
+ };
20
36
 
21
37
  export type ClientFanoutEvent = OrganizeJobEvent | SenderCategoryBackApplyEvent;
22
38
 
@@ -25,12 +41,18 @@ export interface AccountFanoutContext {
25
41
  }
26
42
 
27
43
  export type AccountPurgeEvent =
44
+ | AccountDeleteEvent
45
+ | AccountDeleteFinalizeEvent
28
46
  | AccountDataPurgeEvent
29
47
  | AccountDataPurgeFinalizeEvent;
30
48
 
49
+ export interface AccountExportContext {
50
+ client: RemitClient;
51
+ }
52
+
31
53
  export interface AccountPurgeContext {
32
54
  client: RemitClient;
33
- purgeQueue: GroupedQueueProducer<AccountDataPurgeFinalizeEvent>;
55
+ purgeQueue: GroupedQueueProducer<AccountFinalizeEvent>;
34
56
  capabilities: DeletionCapabilities;
35
57
  }
36
58
 
@@ -48,12 +70,36 @@ export const processAccountFanoutEvent = (
48
70
  }
49
71
  };
50
72
 
73
+ export const processAccountExportEvent = (
74
+ event: AccountExportEvent,
75
+ ctx: AccountExportContext,
76
+ ): Promise<void> =>
77
+ processAccountExport(event, log, {
78
+ services: cascadeServicesOf(ctx.client),
79
+ storageService: ctx.client.storage,
80
+ });
81
+
51
82
  export const processAccountPurgeEvent = (
52
83
  event: AccountPurgeEvent,
53
84
  ctx: AccountPurgeContext,
54
85
  ): Promise<void> => {
55
86
  const services = cascadeServicesOf(ctx.client);
56
87
  switch (event.type) {
88
+ case "AccountDelete":
89
+ return processAccountDelete(event, log, {
90
+ services,
91
+ signOut: ctx.capabilities.signOut,
92
+ enqueueFinalize: (finalizeEvent) =>
93
+ ctx.purgeQueue.send({
94
+ body: finalizeEvent,
95
+ groupId: finalizeEvent.accountConfigId,
96
+ }),
97
+ });
98
+ case "FinalizeAccountDelete":
99
+ return finalizeAccountDelete(event, log, {
100
+ services,
101
+ capabilities: ctx.capabilities,
102
+ });
57
103
  case "AccountDataPurge":
58
104
  return processAccountDataPurge(event, log, {
59
105
  services,
@@ -1,140 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { Readable } from "node:stream";
3
- import { describe, it } from "node:test";
4
- import { noopLogger } from "@remit/logger";
5
- import type { StorageService } from "@remit/storage-service";
6
- import type { CascadeServices } from "../cascade.js";
7
- import type { AccountExportEvent } from "../events.js";
8
- import {
9
- type ProcessAccountExportDeps,
10
- processAccountExport,
11
- } from "./account-export.js";
12
-
13
- interface Update {
14
- state: string;
15
- objectKey?: string;
16
- expiresAt?: number;
17
- errorMessage?: string;
18
- }
19
-
20
- const bodyOf = (text: string): Readable => Readable.from([Buffer.from(text)]);
21
-
22
- const buildDeps = (
23
- updates: Update[],
24
- overrides: {
25
- retrieveMessageBodyStream?: StorageService["retrieveMessageBodyStream"];
26
- storeExportArchiveStream?: StorageService["storeExportArchiveStream"];
27
- } = {},
28
- ): ProcessAccountExportDeps => ({
29
- services: {
30
- accountExportRequestService: {
31
- get: async () => ({ accountExportRequestId: "exp-1" }),
32
- update: async (_id: string, patch: Update) => {
33
- updates.push(patch);
34
- },
35
- },
36
- accountConfigService: {
37
- describe: async () => ({ account: [{ accountId: "acc-1" }] }),
38
- },
39
- accountService: {
40
- describe: async () => ({
41
- mailbox: [{ mailboxId: "mbx-1", fullPath: "INBOX" }],
42
- }),
43
- },
44
- messageService: {
45
- listAllByMailbox: async () => [
46
- { messageId: "msg-1" },
47
- { messageId: "msg-2" },
48
- ],
49
- },
50
- } as unknown as CascadeServices,
51
- storageService: {
52
- retrieveMessageBodyStream:
53
- overrides.retrieveMessageBodyStream ??
54
- (async (_cfg: string, _acc: string, messageId: string) =>
55
- messageId === "msg-2" ? null : bodyOf("raw-eml")),
56
- storeExportArchiveStream:
57
- overrides.storeExportArchiveStream ??
58
- (async (_cfg: string, _req: string, stream: NodeJS.ReadableStream) => {
59
- await new Promise<void>((resolve) => {
60
- stream.on("data", () => {});
61
- stream.on("end", resolve);
62
- });
63
- return "exports/exp-1.zip";
64
- }),
65
- } as unknown as StorageService,
66
- });
67
-
68
- const event: AccountExportEvent = {
69
- type: "AccountExport",
70
- accountConfigId: "cfg-1",
71
- accountExportRequestId: "exp-1",
72
- };
73
-
74
- describe("processAccountExport", () => {
75
- it("drives the request Processing then Ready and stores the archive key", async () => {
76
- const updates: Update[] = [];
77
- await processAccountExport(event, noopLogger, buildDeps(updates));
78
-
79
- assert.deepEqual(
80
- updates.map((u) => u.state),
81
- ["Processing", "Ready"],
82
- );
83
- const ready = updates[1];
84
- assert.equal(ready?.objectKey, "exports/exp-1.zip");
85
- assert.ok(
86
- ready?.expiresAt && ready.expiresAt > Date.now(),
87
- "expiresAt is set in the future",
88
- );
89
- });
90
-
91
- it("skips messages that have no raw body without failing the export", async () => {
92
- const updates: Update[] = [];
93
- let retrieved = 0;
94
- await processAccountExport(
95
- event,
96
- noopLogger,
97
- buildDeps(updates, {
98
- retrieveMessageBodyStream: async (
99
- _cfg: string,
100
- _acc: string,
101
- messageId: string,
102
- ) => {
103
- retrieved += 1;
104
- return messageId === "msg-2" ? null : bodyOf("raw");
105
- },
106
- }),
107
- );
108
-
109
- assert.equal(retrieved, 2, "both messages were consulted");
110
- assert.equal(updates.at(-1)?.state, "Ready");
111
- });
112
-
113
- it("marks the request Failed and rethrows when storage upload rejects", async () => {
114
- const updates: Update[] = [];
115
- await assert.rejects(
116
- processAccountExport(
117
- event,
118
- noopLogger,
119
- buildDeps(updates, {
120
- storeExportArchiveStream: async (
121
- _cfg: string,
122
- _req: string,
123
- stream: NodeJS.ReadableStream,
124
- ) => {
125
- await new Promise<void>((resolve) => {
126
- stream.on("data", () => {});
127
- stream.on("end", resolve);
128
- });
129
- throw new Error("s3 down");
130
- },
131
- }),
132
- ),
133
- /s3 down/,
134
- );
135
-
136
- const failed = updates.at(-1);
137
- assert.equal(failed?.state, "Failed");
138
- assert.equal(failed?.errorMessage, "s3 down");
139
- });
140
- });