@remit/account-worker 0.0.15 → 0.0.16

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/account-worker",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -2,7 +2,6 @@ import { rm } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import {
4
4
  type CascadeDeleter,
5
- createCascadeDeleter,
6
5
  createSqliteCascadeDeleter,
7
6
  } from "@remit/drizzle-service";
8
7
  import type { Logger } from "@remit/logger-lambda";
@@ -30,22 +29,15 @@ const deleteStoragePrefix = async (
30
29
  log.info({ keyPrefix, target }, "Filesystem storage prefix cleanup complete");
31
30
  };
32
31
 
33
- // The Drizzle cascade deleter is opened once, on first use, and reused. On
34
- // Postgres it binds to `PG_CONNECTION_URL`; on SQLite it opens the shared file
35
- // at `SQLITE_DB_PATH` (the native binding loads there, hence async). Built
36
- // lazily so the fanout worker which signs out but never cascade-deletes —
37
- // does not open a database handle it will not use.
32
+ // The Drizzle cascade deleter is opened once, on first use, and reused: it
33
+ // opens the shared file at `SQLITE_DB_PATH` (the native binding loads there,
34
+ // hence async). Built lazily so the fanout worker which signs out but never
35
+ // cascade-deletes does not open a database handle it will not use.
38
36
  let deleterPromise: Promise<CascadeDeleter> | undefined;
39
37
 
40
- const buildDeleter = async (): Promise<CascadeDeleter> => {
41
- if (process.env.DATA_BACKEND === "sqlite") {
42
- return createSqliteCascadeDeleter(env.SQLITE_DB_PATH);
43
- }
44
- return createCascadeDeleter(env.PG_CONNECTION_URL);
45
- };
46
-
47
38
  const getDeleter = (): Promise<CascadeDeleter> => {
48
- if (!deleterPromise) deleterPromise = buildDeleter();
39
+ if (!deleterPromise)
40
+ deleterPromise = createSqliteCascadeDeleter(env.SQLITE_DB_PATH);
49
41
  return deleterPromise;
50
42
  };
51
43
 
@@ -60,7 +52,7 @@ const getDeleter = (): Promise<CascadeDeleter> => {
60
52
  * backend with no response cache (`deploy/vps/caddy/routes.caddy`), so there
61
53
  * is nothing to invalidate.
62
54
  * - `deleteStoragePrefix`: recursive filesystem removal.
63
- * - `cascadeDelete`: the Drizzle cascade over Postgres or SQLite. Message
55
+ * - `cascadeDelete`: the Drizzle cascade over SQLite. Message
64
56
  * subtrees emit `message.removed` outbox rows the search-index worker relays.
65
57
  */
66
58
  export const buildRelationalDeletionCapabilities =
package/src/config.ts CHANGED
@@ -52,10 +52,10 @@ export const graceSeconds = graceSecondsRaw
52
52
  let cascadeServicesPromise: Promise<CascadeServices> | null = null;
53
53
 
54
54
  // Every cascade service is a `RemitClient` repository, so the whole enumeration
55
- // runs on whatever backend `getClient()` selected — DynamoDB (ElectroDB),
56
- // Postgres, or SQLite (Drizzle). Filter/FilterAnchor/Label/MessageLabel (Smart
57
- // Organize, RFC 034) are present on all three backends via the client, so they
58
- // need no backend-specific wiring here.
55
+ // runs on whatever backend `getClient()` resolved — DynamoDB (ElectroDB) or
56
+ // SQLite (Drizzle). Filter/FilterAnchor/Label/MessageLabel (Smart Organize,
57
+ // RFC 034) are present on both via the client, so they need no
58
+ // backend-specific wiring here.
59
59
  export const getCascadeServices = (): Promise<CascadeServices> => {
60
60
  if (!cascadeServicesPromise) {
61
61
  cascadeServicesPromise = getClient().then((remitClient) => ({
@@ -14,12 +14,11 @@ import type { CascadeEntity } from "./cascade.js";
14
14
  * ElectroDB graph and lives outside this shared, open-core module; it is
15
15
  * injected here through `setDeletionCapabilities` so that graph never reaches
16
16
  * the relational tree.
17
- * - `compose-relational.ts` (self-host stack, RFC 035/036), selected by
18
- * `DATA_BACKEND`: no-op sign-out
17
+ * - `compose-relational.ts` (self-host stack, RFC 035/036): no-op sign-out
19
18
  * (deleting the AccountConfig severs the session's data resolution; there is
20
19
  * no CDN to sign out of), no-op invalidation (Caddy proxies `/content/*`
21
20
  * straight to the backend with no cache), filesystem prefix delete, and the
22
- * Drizzle cascade over Postgres or SQLite.
21
+ * Drizzle cascade over SQLite.
23
22
  */
24
23
  export interface DeletionCapabilities {
25
24
  /**
@@ -49,18 +48,12 @@ export interface DeletionCapabilities {
49
48
  deleteStoragePrefix(keyPrefix: string, log: Logger): Promise<void>;
50
49
  /**
51
50
  * Remove the enumerated rows in dependency order (children → parents). AWS:
52
- * DynamoDB `BatchWriteItem`. Relational: Drizzle transaction (Postgres or
53
- * SQLite). Excludes the AccountConfig row, which the caller deletes last
51
+ * DynamoDB `BatchWriteItem`. Relational: a Drizzle transaction. Excludes the AccountConfig row, which the caller deletes last
54
52
  * through its repository as the cascade-in-progress marker.
55
53
  */
56
54
  cascadeDelete(entities: CascadeEntity[], log: Logger): Promise<void>;
57
55
  }
58
56
 
59
- const isRelationalBackend = (): boolean => {
60
- const backend = process.env.DATA_BACKEND;
61
- return backend === "postgres" || backend === "sqlite";
62
- };
63
-
64
57
  let injectedCapabilities: DeletionCapabilities | null = null;
65
58
 
66
59
  /**
@@ -77,18 +70,16 @@ export const setDeletionCapabilities = (
77
70
 
78
71
  const buildDeletionCapabilitiesFromEnv =
79
72
  async (): Promise<DeletionCapabilities> => {
80
- if (isRelationalBackend()) {
73
+ if (injectedCapabilities) return injectedCapabilities;
74
+ if (process.env.SQLITE_DB_PATH) {
81
75
  const { buildRelationalDeletionCapabilities } = await import(
82
76
  "./compose-relational.js"
83
77
  );
84
78
  return buildRelationalDeletionCapabilities();
85
79
  }
86
- if (!injectedCapabilities) {
87
- throw new Error(
88
- "no DynamoDB deletion capabilities registered — register them with setDeletionCapabilities() from your composition root",
89
- );
90
- }
91
- return injectedCapabilities;
80
+ throw new Error(
81
+ "no deletion capabilities registered — register them with setDeletionCapabilities() from your composition root",
82
+ );
92
83
  };
93
84
 
94
85
  let capabilitiesPromise: Promise<DeletionCapabilities> | undefined;
@@ -106,18 +106,18 @@ describe("processAccountDataPurge", () => {
106
106
  );
107
107
  });
108
108
 
109
- it("skips vector deletes on the postgres backend, still enqueuing finalize", async () => {
109
+ it("skips vector deletes on the relational backend, still enqueuing finalize", async () => {
110
110
  const sent: Sent[] = [];
111
111
  await processAccountDataPurge(
112
112
  event,
113
113
  noopLog,
114
- baseDeps(sent, { dataBackend: "postgres" }),
114
+ baseDeps(sent, { dataBackend: "sqlite" }),
115
115
  );
116
116
 
117
117
  assert.equal(
118
118
  sent.some((m) => m.queueUrl === "http://queue/search"),
119
119
  false,
120
- "no search-index enqueue on postgres",
120
+ "no search-index enqueue on the relational backend",
121
121
  );
122
122
  assert.deepEqual(
123
123
  sent
@@ -196,11 +196,11 @@ export const processAccountDataPurge = async (
196
196
 
197
197
  const messageIds = [...new Set(items.map((i) => i.messageId))];
198
198
 
199
- // On Postgres the destructive delete emits a `message.removed` outbox row per
200
- // message, which the pg-index worker relays as a search-index REMOVE; enqueuing
201
- // here too would double the removal. On DynamoDB this fanout is the sole
202
- // producer of the vector deletes (#457).
203
- if (dataBackend !== "postgres") {
199
+ // On the relational backend the destructive delete emits a `message.removed`
200
+ // outbox row per message, which the search-index worker relays as a
201
+ // search-index REMOVE; enqueuing here too would double the removal. On
202
+ // DynamoDB this fanout is the sole producer of the vector deletes (#457).
203
+ if (dataBackend !== "sqlite") {
204
204
  await enqueueVectorDeletes(
205
205
  sqsFor(searchIndexQueueUrl),
206
206
  searchIndexQueueUrl,
package/src/poller.ts CHANGED
@@ -5,7 +5,7 @@ import { fanoutHandler, finalizeHandler } from "./index.js";
5
5
 
6
6
  /**
7
7
  * Production queue poller. No e2e shim exists for account-worker today —
8
- * the deletion cascade is not exercised on the Postgres/compose stack in
8
+ * the deletion cascade is not exercised on the compose stack in
9
9
  * CI (see AGENTS.md worker roster notes). This is the standalone
10
10
  * production entrypoint for the dedicated image.
11
11
  *