@remit/imap-worker 0.0.64 → 0.0.65

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remit/imap-worker",
3
- "version": "0.0.64",
3
+ "version": "0.0.65",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -10,6 +10,7 @@ import {
10
10
  buildMailMessage,
11
11
  renderRawMessage,
12
12
  } from "@remit/smtp-service/message-builder";
13
+ import { attemptBudget } from "@remit/sqs-client/attempt-budget";
13
14
  import { isAccountDeleted } from "../account-check.js";
14
15
  import { createConnectionScopeWithCredentials } from "../connection-scope.js";
15
16
  import type { AppendSentMessageEvent } from "../events.js";
@@ -29,23 +30,9 @@ const ROW_SURVIVED_ITS_DELETE =
29
30
  const unfiledAppendRefused = (fullPath: string, error: unknown): string =>
30
31
  `Sent, but not filed: the mail server refused to store a copy in ${fullPath} (${error instanceof Error ? error.message : String(error)}).`;
31
32
 
32
- /**
33
- * Fallback when `APPEND_SENT_MAX_ATTEMPTS` is unset (local dev, unit tests).
34
- * Matches the shared `MAX_RECEIVE_COUNT` every queue's redrive policy uses,
35
- * same pattern as `FLAG_PUSH_MAX_ATTEMPTS` / `BODY_SYNC_MAX_ATTEMPTS`.
36
- */
37
- const DEFAULT_APPEND_SENT_MAX_ATTEMPTS = 3;
38
-
39
33
  export const getAppendSentMaxAttempts = (
40
34
  processEnv: NodeJS.ProcessEnv = process.env,
41
- ): number => {
42
- const raw = processEnv.APPEND_SENT_MAX_ATTEMPTS;
43
- if (!raw) return DEFAULT_APPEND_SENT_MAX_ATTEMPTS;
44
- const parsed = Number.parseInt(raw, 10);
45
- return Number.isFinite(parsed) && parsed > 0
46
- ? parsed
47
- : DEFAULT_APPEND_SENT_MAX_ATTEMPTS;
48
- };
35
+ ): number => attemptBudget("APPEND_SENT_MAX_ATTEMPTS", 3, processEnv);
49
36
 
50
37
  export const APPEND_SENT_MAX_ATTEMPTS = getAppendSentMaxAttempts();
51
38
 
@@ -8,6 +8,7 @@ import {
8
8
  MailboxCursorPausedError,
9
9
  resolveExhaustedFlagPushFailure,
10
10
  } from "@remit/mailbox-service";
11
+ import { attemptBudget } from "@remit/sqs-client/attempt-budget";
11
12
  import { isAccountDeleted } from "../account-check.js";
12
13
  import { createConnectionScopeWithCredentials } from "../connection-scope.js";
13
14
  import type { FlagPushEvent } from "../events.js";
@@ -15,24 +16,9 @@ import { isNotFoundError } from "../is-not-found.js";
15
16
  import { withOAuthLifecycle } from "../with-oauth-lifecycle.js";
16
17
  import { buildLifecycleDeps } from "../with-oauth-lifecycle-deps.js";
17
18
 
18
- /**
19
- * Fallback when `FLAG_PUSH_MAX_ATTEMPTS` is unset (local dev, unit tests).
20
- * Matches the shared `MAX_RECEIVE_COUNT` every queue's redrive policy uses
21
- * (`infra/stacks/dev/stacks/remit-queue-stack.ts`), same pattern as
22
- * `BODY_SYNC_MAX_ATTEMPTS` (#1270) / `PLACEMENT_MOVE_MAX_ATTEMPTS` (#1289).
23
- */
24
- const DEFAULT_FLAG_PUSH_MAX_ATTEMPTS = 3;
25
-
26
19
  export const getFlagPushMaxAttempts = (
27
20
  processEnv: NodeJS.ProcessEnv = process.env,
28
- ): number => {
29
- const raw = processEnv.FLAG_PUSH_MAX_ATTEMPTS;
30
- if (!raw) return DEFAULT_FLAG_PUSH_MAX_ATTEMPTS;
31
- const parsed = Number.parseInt(raw, 10);
32
- return Number.isFinite(parsed) && parsed > 0
33
- ? parsed
34
- : DEFAULT_FLAG_PUSH_MAX_ATTEMPTS;
35
- };
21
+ ): number => attemptBudget("FLAG_PUSH_MAX_ATTEMPTS", 3, processEnv);
36
22
 
37
23
  export const FLAG_PUSH_MAX_ATTEMPTS = getFlagPushMaxAttempts();
38
24
 
@@ -9,6 +9,7 @@ import {
9
9
  MailboxCursorPausedError,
10
10
  reconcileStaleMessage,
11
11
  } from "@remit/mailbox-service";
12
+ import { attemptBudget } from "@remit/sqs-client/attempt-budget";
12
13
  import { isAccountDeleted } from "../account-check.js";
13
14
  import { createConnectionScopeWithCredentials } from "../connection-scope.js";
14
15
  import type { MessageCopyEvent } from "../events.js";
@@ -31,24 +32,9 @@ const defaultDeps: MessageCopyDeps = {
31
32
  createConnectionScope: createConnectionScopeWithCredentials,
32
33
  };
33
34
 
34
- /**
35
- * Fallback when `MESSAGE_COPY_MAX_ATTEMPTS` is unset (local dev, unit tests).
36
- * Matches the `maxReceiveCount` the message queue's redrive policy uses
37
- * (`remit-messages.fifo`, `deploy/vps/queues.json`), same pattern as
38
- * `MESSAGE_MOVE_MAX_ATTEMPTS`.
39
- */
40
- const DEFAULT_MESSAGE_COPY_MAX_ATTEMPTS = 3;
41
-
42
35
  export const getMessageCopyMaxAttempts = (
43
36
  processEnv: NodeJS.ProcessEnv = process.env,
44
- ): number => {
45
- const raw = processEnv.MESSAGE_COPY_MAX_ATTEMPTS;
46
- if (!raw) return DEFAULT_MESSAGE_COPY_MAX_ATTEMPTS;
47
- const parsed = Number.parseInt(raw, 10);
48
- return Number.isFinite(parsed) && parsed > 0
49
- ? parsed
50
- : DEFAULT_MESSAGE_COPY_MAX_ATTEMPTS;
51
- };
37
+ ): number => attemptBudget("MESSAGE_COPY_MAX_ATTEMPTS", 3, processEnv);
52
38
 
53
39
  export const MESSAGE_COPY_MAX_ATTEMPTS = getMessageCopyMaxAttempts();
54
40
 
@@ -14,6 +14,7 @@ import {
14
14
  isMessageGoneFromOpenMailbox,
15
15
  MailboxCursorPausedError,
16
16
  } from "@remit/mailbox-service";
17
+ import { attemptBudget } from "@remit/sqs-client/attempt-budget";
17
18
  import { isAccountDeleted } from "../account-check.js";
18
19
  import { createConnectionScopeWithCredentials } from "../connection-scope.js";
19
20
  import { emitEvent } from "../emit.js";
@@ -28,24 +29,9 @@ import {
28
29
  buildThreadMessageTrashUpdate,
29
30
  } from "./thread-message-rows.js";
30
31
 
31
- /**
32
- * Fallback when `MESSAGE_DELETE_MAX_ATTEMPTS` is unset (local dev, unit tests).
33
- * Matches the `maxReceiveCount` the redrive policy of the queue `emit.ts`
34
- * routes MESSAGE_DELETE onto uses (`remit-message-mgmt`,
35
- * `deploy/vps/queues.json`), same pattern as `MESSAGE_MOVE_MAX_ATTEMPTS`.
36
- */
37
- const DEFAULT_MESSAGE_DELETE_MAX_ATTEMPTS = 3;
38
-
39
32
  export const getMessageDeleteMaxAttempts = (
40
33
  processEnv: NodeJS.ProcessEnv = process.env,
41
- ): number => {
42
- const raw = processEnv.MESSAGE_DELETE_MAX_ATTEMPTS;
43
- if (!raw) return DEFAULT_MESSAGE_DELETE_MAX_ATTEMPTS;
44
- const parsed = Number.parseInt(raw, 10);
45
- return Number.isFinite(parsed) && parsed > 0
46
- ? parsed
47
- : DEFAULT_MESSAGE_DELETE_MAX_ATTEMPTS;
48
- };
34
+ ): number => attemptBudget("MESSAGE_DELETE_MAX_ATTEMPTS", 3, processEnv);
49
35
 
50
36
  export const MESSAGE_DELETE_MAX_ATTEMPTS = getMessageDeleteMaxAttempts();
51
37
 
@@ -10,6 +10,7 @@ import {
10
10
  isPlacementUnsettled,
11
11
  MailboxCursorPausedError,
12
12
  } from "@remit/mailbox-service";
13
+ import { attemptBudget } from "@remit/sqs-client/attempt-budget";
13
14
  import { isAccountDeleted } from "../account-check.js";
14
15
  import { createConnectionScopeWithCredentials } from "../connection-scope.js";
15
16
  import { emitEvent } from "../emit.js";
@@ -19,24 +20,9 @@ import { withOAuthLifecycle } from "../with-oauth-lifecycle.js";
19
20
  import { buildLifecycleDeps } from "../with-oauth-lifecycle-deps.js";
20
21
  import { resolveExhaustedMessageMoveFailure } from "./message-move-terminal.js";
21
22
 
22
- /**
23
- * Fallback when `MESSAGE_MOVE_MAX_ATTEMPTS` is unset (local dev, unit tests).
24
- * Matches the `maxReceiveCount` the message queue's redrive policy uses
25
- * (`remit-messages.fifo`, `deploy/vps/queues.json`), same pattern as
26
- * `FLAG_PUSH_MAX_ATTEMPTS` and `PLACEMENT_MOVE_MAX_ATTEMPTS`.
27
- */
28
- const DEFAULT_MESSAGE_MOVE_MAX_ATTEMPTS = 3;
29
-
30
23
  export const getMessageMoveMaxAttempts = (
31
24
  processEnv: NodeJS.ProcessEnv = process.env,
32
- ): number => {
33
- const raw = processEnv.MESSAGE_MOVE_MAX_ATTEMPTS;
34
- if (!raw) return DEFAULT_MESSAGE_MOVE_MAX_ATTEMPTS;
35
- const parsed = Number.parseInt(raw, 10);
36
- return Number.isFinite(parsed) && parsed > 0
37
- ? parsed
38
- : DEFAULT_MESSAGE_MOVE_MAX_ATTEMPTS;
39
- };
25
+ ): number => attemptBudget("MESSAGE_MOVE_MAX_ATTEMPTS", 3, processEnv);
40
26
 
41
27
  export const MESSAGE_MOVE_MAX_ATTEMPTS = getMessageMoveMaxAttempts();
42
28
 
@@ -10,6 +10,7 @@ import {
10
10
  reconcileStaleMessage,
11
11
  resolveExhaustedPlacementMoveFailure,
12
12
  } from "@remit/mailbox-service";
13
+ import { attemptBudget } from "@remit/sqs-client/attempt-budget";
13
14
  import { isAccountDeleted } from "../account-check.js";
14
15
  import { createConnectionScopeWithCredentials } from "../connection-scope.js";
15
16
  import { emitEvent } from "../emit.js";
@@ -23,24 +24,9 @@ import {
23
24
  searchMailboxByMessageId,
24
25
  } from "./message-move.js";
25
26
 
26
- /**
27
- * Fallback when `PLACEMENT_MOVE_MAX_ATTEMPTS` is unset (local dev, unit
28
- * tests). Matches the placement-move queue's own `MAX_RECEIVE_COUNT` default
29
- * (`infra/stacks/dev/stacks/remit-queue-stack.ts`), same pattern as
30
- * `BODY_SYNC_MAX_ATTEMPTS` (#1270).
31
- */
32
- const DEFAULT_PLACEMENT_MOVE_MAX_ATTEMPTS = 3;
33
-
34
27
  export const getPlacementMoveMaxAttempts = (
35
28
  processEnv: NodeJS.ProcessEnv = process.env,
36
- ): number => {
37
- const raw = processEnv.PLACEMENT_MOVE_MAX_ATTEMPTS;
38
- if (!raw) return DEFAULT_PLACEMENT_MOVE_MAX_ATTEMPTS;
39
- const parsed = Number.parseInt(raw, 10);
40
- return Number.isFinite(parsed) && parsed > 0
41
- ? parsed
42
- : DEFAULT_PLACEMENT_MOVE_MAX_ATTEMPTS;
43
- };
29
+ ): number => attemptBudget("PLACEMENT_MOVE_MAX_ATTEMPTS", 3, processEnv);
44
30
 
45
31
  export const PLACEMENT_MOVE_MAX_ATTEMPTS = getPlacementMoveMaxAttempts();
46
32
 
@@ -11,6 +11,7 @@ import {
11
11
  QuarantineService,
12
12
  resolveExhaustedBodySyncFailures,
13
13
  } from "@remit/mailbox-service";
14
+ import { attemptBudget } from "@remit/sqs-client/attempt-budget";
14
15
  import { env } from "expect-env";
15
16
  import { isAccountDeleted } from "../account-check.js";
16
17
  import { isBodySyncEnabled } from "../body-sync-gate.js";
@@ -27,37 +28,9 @@ import { workerVersion } from "../worker-version.js";
27
28
 
28
29
  const bodySyncEnabledParameterName = env.BODY_SYNC_ENABLED_PARAMETER_NAME;
29
30
 
30
- /**
31
- * Fallback when `BODY_SYNC_MAX_ATTEMPTS` is unset (local dev, unit tests).
32
- * Matches the body queue's own `MAX_RECEIVE_COUNT` default
33
- * (`infra/stacks/dev/stacks/remit-queue-stack.ts`) so an environment that
34
- * never injects the var still behaves like production.
35
- */
36
- const DEFAULT_BODY_SYNC_MAX_ATTEMPTS = 3;
37
-
38
- /**
39
- * Reads the redelivery-budget-exhaustion threshold. CDK derives
40
- * `BODY_SYNC_MAX_ATTEMPTS` from the body queue's own `MAX_RECEIVE_COUNT`
41
- * (`remit-worker-stack.ts`) so the two constants can't drift apart — a
42
- * hand-copied duplicate here previously risked the worker resolving
43
- * "last attempt" on a different delivery than the queue's redrive policy
44
- * actually uses (issue #1270). SQS's own `ApproximateReceiveCount` is the
45
- * source of truth for how many times a record has been delivered; once it
46
- * reaches this value, the current invocation is the last attempt before the
47
- * queue's own redrive would DLQ the record, so retry exhaustion is resolved
48
- * here (see `resolveExhaustedBodySyncFailures`) instead of letting the
49
- * record dead-letter with no diagnosis.
50
- */
51
31
  export const getBodySyncMaxAttempts = (
52
32
  processEnv: NodeJS.ProcessEnv = process.env,
53
- ): number => {
54
- const raw = processEnv.BODY_SYNC_MAX_ATTEMPTS;
55
- if (!raw) return DEFAULT_BODY_SYNC_MAX_ATTEMPTS;
56
- const parsed = Number.parseInt(raw, 10);
57
- return Number.isFinite(parsed) && parsed > 0
58
- ? parsed
59
- : DEFAULT_BODY_SYNC_MAX_ATTEMPTS;
60
- };
33
+ ): number => attemptBudget("BODY_SYNC_MAX_ATTEMPTS", 3, processEnv);
61
34
 
62
35
  export const BODY_SYNC_MAX_ATTEMPTS = getBodySyncMaxAttempts();
63
36