@rotorsoft/act-pg 1.4.0 → 1.4.2

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.
@@ -155,14 +155,14 @@ export declare class PostgresStore implements Store {
155
155
  */
156
156
  private readonly _channel;
157
157
  /** Active LISTEN client (one per `notify()` subscription). */
158
- private _listenClient;
158
+ private _listen_client;
159
159
  /**
160
160
  * Notification listener attached to the active LISTEN client. Tracked
161
161
  * separately so the re-subscribe / dispose paths can detach it before
162
162
  * destroying the client — without this, a pool that reused the
163
163
  * connection would re-fire the stale handler.
164
164
  */
165
- private _listenHandler;
165
+ private _listen_handler;
166
166
  /**
167
167
  * Cross-process commit subscription. **Present only when
168
168
  * `config.notify === true`** — the orchestrator's auto-wire path
@@ -192,7 +192,7 @@ export declare class PostgresStore implements Store {
192
192
  * destroying belt-and-braces guards against any future change in
193
193
  * pg-pool semantics that could re-issue a half-clean client).
194
194
  */
195
- private _teardownListen;
195
+ private _teardown_listen;
196
196
  /**
197
197
  * Seed the database with required tables, indexes, and schema for event storage.
198
198
  * @returns Promise that resolves when seeding is complete
@@ -282,7 +282,7 @@ export declare class PostgresStore implements Store {
282
282
  * `WHERE` — callers compose it with any other predicates they need.
283
283
  * Returns an always-true clause (`true`) when the filter is empty.
284
284
  */
285
- private _filterClause;
285
+ private _filter_clause;
286
286
  reset(input: string[] | StreamFilter): Promise<number>;
287
287
  /**
288
288
  * Clear blocked flag (and retry / error / lease state) on streams
@@ -359,13 +359,13 @@ export declare class PostgresStore implements Store {
359
359
  * optional second query (in parallel) for the tail. K rows touched
360
360
  * per query, not N events.
361
361
  */
362
- private _queryStatsHeadsOnly;
362
+ private _query_stats_heads_only;
363
363
  /**
364
364
  * Full-scan path: one CTE-based query computes the per-stream
365
365
  * `COUNT(*)` and `jsonb_object_agg(name, n)` map alongside the head
366
366
  * (and tail when requested). All extras share the single events scan.
367
367
  */
368
- private _queryStatsFullScan;
368
+ private _query_stats_full_scan;
369
369
  /**
370
370
  * Implementation of the optional `Store.notify` hook. Bound onto
371
371
  * `this.notify` in the constructor when `config.notify === true`,
@@ -387,7 +387,7 @@ export declare class PostgresStore implements Store {
387
387
  * @param handler Called for each cross-process commit notification.
388
388
  * @returns Disposer that releases the LISTEN client.
389
389
  */
390
- private _subscribeNotifications;
390
+ private _subscribe_notifications;
391
391
  /**
392
392
  * Atomically truncates streams and seeds each with a snapshot or tombstone.
393
393
  * @param targets - Streams to truncate with optional snapshot state and meta.
@@ -414,6 +414,23 @@ export declare class PostgresStore implements Store {
414
414
  * from 1. `created` is preserved verbatim from the source.
415
415
  */
416
416
  restore(driver: (callback: (event: Committed<Schemas, keyof Schemas>) => Promise<number>) => Promise<void>): Promise<void>;
417
+ /**
418
+ * Wipe the sensitive-data payload for every event on the stream — the
419
+ * physical-erasure side of the sensitive-data epic (#566). Sets
420
+ * `events.pii` to `NULL` for the stream's events; `events.data` and
421
+ * the rest of the row are never touched.
422
+ *
423
+ * Row-level locks (no table lock), bounded by events-per-stream.
424
+ * Idempotent — a second call on an already-wiped stream returns `0`.
425
+ *
426
+ * Disk reclamation is autovacuum-driven; for strict-deletion
427
+ * jurisdictions the production checklist documents `VACUUM FULL` as
428
+ * the operator step.
429
+ *
430
+ * @param stream Target stream
431
+ * @returns Count of events whose `pii` was set to `NULL`
432
+ */
433
+ forget_pii(stream: string): Promise<number>;
417
434
  }
418
435
  export {};
419
436
  //# sourceMappingURL=postgres-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/postgres-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/postgres-store.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -58,10 +58,10 @@ types.setTypeParser(
58
58
  var SAFE_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
59
59
  var PG_UNIQUE_VIOLATION = "23505";
60
60
  var NOTIFY_CHANNEL_PREFIX = "act_commit";
61
- function notifyChannel(schema, table) {
61
+ function notify_channel(schema, table) {
62
62
  return `${NOTIFY_CHANNEL_PREFIX}_${schema}_${table}`;
63
63
  }
64
- function assertSafeIdentifier(value, label) {
64
+ function assert_safe_identifier(value, label) {
65
65
  if (!SAFE_IDENTIFIER.test(value))
66
66
  throw new Error(`Unsafe SQL identifier for ${label}: "${value}"`);
67
67
  }
@@ -94,14 +94,14 @@ var PostgresStore = class {
94
94
  */
95
95
  _channel;
96
96
  /** Active LISTEN client (one per `notify()` subscription). */
97
- _listenClient;
97
+ _listen_client;
98
98
  /**
99
99
  * Notification listener attached to the active LISTEN client. Tracked
100
100
  * separately so the re-subscribe / dispose paths can detach it before
101
101
  * destroying the client — without this, a pool that reused the
102
102
  * connection would re-fire the stale handler.
103
103
  */
104
- _listenHandler;
104
+ _listen_handler;
105
105
  /**
106
106
  * Cross-process commit subscription. **Present only when
107
107
  * `config.notify === true`** — the orchestrator's auto-wire path
@@ -119,15 +119,15 @@ var PostgresStore = class {
119
119
  */
120
120
  constructor(config = {}) {
121
121
  this.config = { ...DEFAULT_CONFIG, ...config };
122
- assertSafeIdentifier(this.config.schema, "schema");
123
- assertSafeIdentifier(this.config.table, "table");
122
+ assert_safe_identifier(this.config.schema, "schema");
123
+ assert_safe_identifier(this.config.table, "table");
124
124
  const { schema: _, table: __, ...poolConfig } = this.config;
125
125
  this._pool = new Pool(poolConfig);
126
126
  this._fqt = `"${this.config.schema}"."${this.config.table}"`;
127
127
  this._fqs = `"${this.config.schema}"."${this.config.table}_streams"`;
128
- this._channel = notifyChannel(this.config.schema, this.config.table);
128
+ this._channel = notify_channel(this.config.schema, this.config.table);
129
129
  if (this.config.notify) {
130
- this.notify = this._subscribeNotifications.bind(this);
130
+ this.notify = this._subscribe_notifications.bind(this);
131
131
  }
132
132
  }
133
133
  /**
@@ -136,7 +136,7 @@ var PostgresStore = class {
136
136
  * @returns Promise that resolves when all connections are closed
137
137
  */
138
138
  async dispose() {
139
- await this._teardownListen();
139
+ await this._teardown_listen();
140
140
  await this._pool.end();
141
141
  }
142
142
  /**
@@ -146,16 +146,16 @@ var PostgresStore = class {
146
146
  * destroying belt-and-braces guards against any future change in
147
147
  * pg-pool semantics that could re-issue a half-clean client).
148
148
  */
149
- async _teardownListen() {
150
- if (!this._listenClient) return;
151
- this._listenClient.removeListener("notification", this._listenHandler);
152
- this._listenHandler = void 0;
149
+ async _teardown_listen() {
150
+ if (!this._listen_client) return;
151
+ this._listen_client.removeListener("notification", this._listen_handler);
152
+ this._listen_handler = void 0;
153
153
  try {
154
- await this._listenClient.query(`UNLISTEN ${this._channel}`);
154
+ await this._listen_client.query(`UNLISTEN ${this._channel}`);
155
155
  } catch {
156
156
  }
157
- this._listenClient.release(true);
158
- this._listenClient = void 0;
157
+ this._listen_client.release(true);
158
+ this._listen_client = void 0;
159
159
  }
160
160
  /**
161
161
  * Seed the database with required tables, indexes, and schema for event storage.
@@ -177,9 +177,13 @@ var PostgresStore = class {
177
177
  stream varchar(100) COLLATE pg_catalog."default" NOT NULL,
178
178
  version int NOT NULL,
179
179
  created timestamptz NOT NULL DEFAULT now(),
180
- meta jsonb
180
+ meta jsonb,
181
+ pii jsonb
181
182
  ) TABLESPACE pg_default;`
182
183
  );
184
+ await client.query(
185
+ `ALTER TABLE ${this._fqt} ADD COLUMN IF NOT EXISTS pii jsonb;`
186
+ );
183
187
  await client.query(
184
188
  `CREATE UNIQUE INDEX IF NOT EXISTS "${this.config.table}_stream_ix"
185
189
  ON ${this._fqt} (stream COLLATE pg_catalog."default", version);`
@@ -370,12 +374,12 @@ var PostgresStore = class {
370
374
  expectedVersion
371
375
  );
372
376
  const committed = [];
373
- for (const { name, data } of msgs) {
377
+ for (const { name, data, pii } of msgs) {
374
378
  version++;
375
379
  const sql = `
376
- INSERT INTO ${this._fqt}(name, data, stream, version, meta)
377
- VALUES($1, $2, $3, $4, $5) RETURNING *`;
378
- const vals = [name, data, stream, version, meta];
380
+ INSERT INTO ${this._fqt}(name, data, pii, stream, version, meta)
381
+ VALUES($1, $2, $3, $4, $5, $6) RETURNING *`;
382
+ const vals = [name, data, pii ?? null, stream, version, meta];
379
383
  try {
380
384
  const { rows } = await client.query(sql, vals);
381
385
  committed.push(rows.at(0));
@@ -430,7 +434,7 @@ var PostgresStore = class {
430
434
  const client = await this._pool.connect();
431
435
  try {
432
436
  await client.query("BEGIN");
433
- const laneClause = lane !== void 0 ? `AND s.lane = $5` : "";
437
+ const lane_clause = lane !== void 0 ? `AND s.lane = $5` : "";
434
438
  const params = lane !== void 0 ? [lagging, leading, by, millis, lane] : [lagging, leading, by, millis];
435
439
  const { rows } = await client.query(
436
440
  `
@@ -439,7 +443,7 @@ var PostgresStore = class {
439
443
  SELECT stream, source, at, priority, lane
440
444
  FROM ${this._fqs} s
441
445
  WHERE blocked = false
442
- ${laneClause}
446
+ ${lane_clause}
443
447
  AND (leased_by IS NULL OR leased_until <= NOW())
444
448
  AND (s.at < 0 OR EXISTS (
445
449
  SELECT 1 FROM ${this._fqt} e
@@ -664,7 +668,7 @@ var PostgresStore = class {
664
668
  * `WHERE` — callers compose it with any other predicates they need.
665
669
  * Returns an always-true clause (`true`) when the filter is empty.
666
670
  */
667
- _filterClause(filter, start) {
671
+ _filter_clause(filter, start) {
668
672
  const conditions = [];
669
673
  const values = [];
670
674
  if (filter.stream !== void 0) {
@@ -694,19 +698,19 @@ var PostgresStore = class {
694
698
  };
695
699
  }
696
700
  async reset(input) {
697
- const setClause = `SET at = -1, retry = 0, blocked = false, error = NULL,
701
+ const set_clause = `SET at = -1, retry = 0, blocked = false, error = NULL,
698
702
  leased_by = NULL, leased_until = NULL`;
699
703
  if (Array.isArray(input)) {
700
704
  if (!input.length) return 0;
701
705
  const { rowCount: rowCount2 } = await this._pool.query(
702
- `UPDATE ${this._fqs} ${setClause} WHERE stream = ANY($1)`,
706
+ `UPDATE ${this._fqs} ${set_clause} WHERE stream = ANY($1)`,
703
707
  [input]
704
708
  );
705
709
  return rowCount2 ?? 0;
706
710
  }
707
- const { clause, values } = this._filterClause(input, 1);
711
+ const { clause, values } = this._filter_clause(input, 1);
708
712
  const { rowCount } = await this._pool.query(
709
- `UPDATE ${this._fqs} ${setClause} WHERE ${clause}`,
713
+ `UPDATE ${this._fqs} ${set_clause} WHERE ${clause}`,
710
714
  values
711
715
  );
712
716
  return rowCount ?? 0;
@@ -727,23 +731,23 @@ var PostgresStore = class {
727
731
  * @returns Count of streams that were actually flipped (were blocked).
728
732
  */
729
733
  async unblock(input) {
730
- const setClause = `SET retry = -1, blocked = false, error = NULL,
734
+ const set_clause = `SET retry = -1, blocked = false, error = NULL,
731
735
  leased_by = NULL, leased_until = NULL`;
732
736
  if (Array.isArray(input)) {
733
737
  if (!input.length) return 0;
734
738
  const { rowCount: rowCount2 } = await this._pool.query(
735
- `UPDATE ${this._fqs} ${setClause}
739
+ `UPDATE ${this._fqs} ${set_clause}
736
740
  WHERE stream = ANY($1) AND blocked = true`,
737
741
  [input]
738
742
  );
739
743
  return rowCount2 ?? 0;
740
744
  }
741
- const { clause, values } = this._filterClause(
745
+ const { clause, values } = this._filter_clause(
742
746
  { ...input, blocked: true },
743
747
  1
744
748
  );
745
749
  const { rowCount } = await this._pool.query(
746
- `UPDATE ${this._fqs} ${setClause} WHERE ${clause}`,
750
+ `UPDATE ${this._fqs} ${set_clause} WHERE ${clause}`,
747
751
  values
748
752
  );
749
753
  return rowCount ?? 0;
@@ -763,7 +767,7 @@ var PostgresStore = class {
763
767
  * @returns Count of streams whose priority changed.
764
768
  */
765
769
  async prioritize(filter, priority) {
766
- const { clause, values } = this._filterClause(filter, 2);
770
+ const { clause, values } = this._filter_clause(filter, 2);
767
771
  const sql = `UPDATE ${this._fqs} SET priority = $1
768
772
  WHERE priority <> $1 AND ${clause}`;
769
773
  const { rowCount } = await this._pool.query(sql, [priority, ...values]);
@@ -870,11 +874,11 @@ var PostgresStore = class {
870
874
  */
871
875
  async query_stats(input, options) {
872
876
  const exclude = options?.exclude ?? [];
873
- const wantTail = options?.tail ?? false;
874
- const wantCount = options?.count ?? false;
875
- const wantNames = options?.names ?? false;
877
+ const want_tail = options?.tail ?? false;
878
+ const want_count = options?.count ?? false;
879
+ const want_names = options?.names ?? false;
876
880
  const before = options?.before;
877
- const fullScan = wantCount || wantNames;
881
+ const full_scan = want_count || want_names;
878
882
  if (Array.isArray(input) && input.length === 0) {
879
883
  return /* @__PURE__ */ new Map();
880
884
  }
@@ -897,29 +901,34 @@ var PostgresStore = class {
897
901
  params.push(before);
898
902
  where.push(`e.id < $${params.length}`);
899
903
  }
900
- const fromClause = `${this._fqt} e`;
901
- const whereClause = `WHERE ${where.length ? where.join(" AND ") : "TRUE"}`;
902
- return fullScan ? this._queryStatsFullScan(
903
- fromClause,
904
- whereClause,
904
+ const from_clause = `${this._fqt} e`;
905
+ const where_clause = `WHERE ${where.length ? where.join(" AND ") : "TRUE"}`;
906
+ return full_scan ? this._query_stats_full_scan(
907
+ from_clause,
908
+ where_clause,
909
+ params,
910
+ want_tail,
911
+ want_count,
912
+ want_names
913
+ ) : this._query_stats_heads_only(
914
+ from_clause,
915
+ where_clause,
905
916
  params,
906
- wantTail,
907
- wantCount,
908
- wantNames
909
- ) : this._queryStatsHeadsOnly(fromClause, whereClause, params, wantTail);
917
+ want_tail
918
+ );
910
919
  }
911
920
  /**
912
921
  * Cheap path: index-only DISTINCT ON for the head per stream, plus an
913
922
  * optional second query (in parallel) for the tail. K rows touched
914
923
  * per query, not N events.
915
924
  */
916
- async _queryStatsHeadsOnly(fromClause, whereClause, params, wantTail) {
925
+ async _query_stats_heads_only(from_clause, where_clause, params, want_tail) {
917
926
  const cols = `e.id, e.stream, e.version, e.name, e.data, e.created, e.meta`;
918
- const headSql = `SELECT DISTINCT ON (e.stream) ${cols} FROM ${fromClause} ${whereClause} ORDER BY e.stream, e.version DESC`;
919
- const tailSql = wantTail ? `SELECT DISTINCT ON (e.stream) ${cols} FROM ${fromClause} ${whereClause} ORDER BY e.stream, e.version ASC` : null;
927
+ const head_sql = `SELECT DISTINCT ON (e.stream) ${cols} FROM ${from_clause} ${where_clause} ORDER BY e.stream, e.version DESC`;
928
+ const tail_sql = want_tail ? `SELECT DISTINCT ON (e.stream) ${cols} FROM ${from_clause} ${where_clause} ORDER BY e.stream, e.version ASC` : null;
920
929
  const [headRes, tailRes] = await Promise.all([
921
- this._pool.query(headSql, params),
922
- tailSql ? this._pool.query(tailSql, params) : Promise.resolve(null)
930
+ this._pool.query(head_sql, params),
931
+ tail_sql ? this._pool.query(tail_sql, params) : Promise.resolve(null)
923
932
  ]);
924
933
  const out = /* @__PURE__ */ new Map();
925
934
  for (const row of headRes.rows) {
@@ -937,16 +946,16 @@ var PostgresStore = class {
937
946
  * `COUNT(*)` and `jsonb_object_agg(name, n)` map alongside the head
938
947
  * (and tail when requested). All extras share the single events scan.
939
948
  */
940
- async _queryStatsFullScan(fromClause, whereClause, params, wantTail, wantCount, wantNames) {
941
- const tailCte = wantTail ? `, tails AS (SELECT DISTINCT ON (stream) * FROM ef ORDER BY stream, version ASC)` : "";
942
- const tailJoin = wantTail ? `LEFT JOIN tails t ON t.stream = h.stream` : "";
943
- const tailCols = wantTail ? `, t.id AS t_id, t.stream AS t_stream, t.version AS t_version,
949
+ async _query_stats_full_scan(from_clause, where_clause, params, want_tail, want_count, want_names) {
950
+ const tail_cte = want_tail ? `, tails AS (SELECT DISTINCT ON (stream) * FROM ef ORDER BY stream, version ASC)` : "";
951
+ const tail_join = want_tail ? `LEFT JOIN tails t ON t.stream = h.stream` : "";
952
+ const tail_cols = want_tail ? `, t.id AS t_id, t.stream AS t_stream, t.version AS t_version,
944
953
  t.name AS t_name, t.data AS t_data, t.created AS t_created, t.meta AS t_meta` : "";
945
954
  const sql = `
946
955
  WITH ef AS (
947
956
  SELECT e.id, e.stream, e.version, e.name, e.data, e.created, e.meta
948
- FROM ${fromClause}
949
- ${whereClause}
957
+ FROM ${from_clause}
958
+ ${where_clause}
950
959
  ),
951
960
  agg AS (
952
961
  SELECT stream,
@@ -962,15 +971,15 @@ var PostgresStore = class {
962
971
  heads AS (
963
972
  SELECT DISTINCT ON (stream) * FROM ef ORDER BY stream, version DESC
964
973
  )
965
- ${tailCte}
974
+ ${tail_cte}
966
975
  SELECT
967
976
  h.id, h.stream, h.version, h.name, h.data, h.created, h.meta,
968
977
  a.cnt AS agg_count,
969
978
  a.names AS agg_names
970
- ${tailCols}
979
+ ${tail_cols}
971
980
  FROM heads h
972
981
  LEFT JOIN agg a ON a.stream = h.stream
973
- ${tailJoin}
982
+ ${tail_join}
974
983
  `;
975
984
  const res = await this._pool.query(sql, params);
976
985
  const out = /* @__PURE__ */ new Map();
@@ -986,7 +995,7 @@ var PostgresStore = class {
986
995
  meta: row.meta
987
996
  }
988
997
  };
989
- if (wantTail && row.t_id !== void 0 && row.t_id !== null) {
998
+ if (want_tail && row.t_id !== void 0 && row.t_id !== null) {
990
999
  stats.tail = {
991
1000
  id: row.t_id,
992
1001
  stream: row.t_stream,
@@ -997,8 +1006,8 @@ var PostgresStore = class {
997
1006
  meta: row.t_meta
998
1007
  };
999
1008
  }
1000
- if (wantCount) stats.count = row.agg_count;
1001
- if (wantNames) stats.names = row.agg_names;
1009
+ if (want_count) stats.count = row.agg_count;
1010
+ if (want_names) stats.names = row.agg_names;
1002
1011
  out.set(row.stream, stats);
1003
1012
  }
1004
1013
  return out;
@@ -1024,10 +1033,10 @@ var PostgresStore = class {
1024
1033
  * @param handler Called for each cross-process commit notification.
1025
1034
  * @returns Disposer that releases the LISTEN client.
1026
1035
  */
1027
- async _subscribeNotifications(handler) {
1028
- await this._teardownListen();
1036
+ async _subscribe_notifications(handler) {
1037
+ await this._teardown_listen();
1029
1038
  const client = await this._pool.connect();
1030
- const onNotification = (msg) => {
1039
+ const on_notification = (msg) => {
1031
1040
  if (msg.channel !== this._channel) return;
1032
1041
  if (!msg.payload) return;
1033
1042
  let parsed;
@@ -1064,19 +1073,19 @@ var PostgresStore = class {
1064
1073
  logger.error(err, "act_commit: handler threw, listener preserved");
1065
1074
  }
1066
1075
  };
1067
- client.on("notification", onNotification);
1076
+ client.on("notification", on_notification);
1068
1077
  try {
1069
1078
  await client.query(`LISTEN ${this._channel}`);
1070
1079
  } catch (err) {
1071
- client.removeListener("notification", onNotification);
1080
+ client.removeListener("notification", on_notification);
1072
1081
  client.release(true);
1073
1082
  throw err;
1074
1083
  }
1075
- this._listenClient = client;
1076
- this._listenHandler = onNotification;
1084
+ this._listen_client = client;
1085
+ this._listen_handler = on_notification;
1077
1086
  return async () => {
1078
- if (this._listenClient !== client) return;
1079
- await this._teardownListen();
1087
+ if (this._listen_client !== client) return;
1088
+ await this._teardown_listen();
1080
1089
  };
1081
1090
  }
1082
1091
  /**
@@ -1147,11 +1156,12 @@ var PostgresStore = class {
1147
1156
  await client.query(`TRUNCATE TABLE ${this._fqs}`);
1148
1157
  await driver(async (event) => {
1149
1158
  const { rows } = await client.query(
1150
- `INSERT INTO ${this._fqt}(name, data, stream, version, created, meta)
1151
- VALUES($1, $2, $3, $4, $5, $6) RETURNING id`,
1159
+ `INSERT INTO ${this._fqt}(name, data, pii, stream, version, created, meta)
1160
+ VALUES($1, $2, $3, $4, $5, $6, $7) RETURNING id`,
1152
1161
  [
1153
1162
  event.name,
1154
1163
  event.data,
1164
+ event.pii ?? null,
1155
1165
  event.stream,
1156
1166
  event.version,
1157
1167
  event.created,
@@ -1169,6 +1179,29 @@ var PostgresStore = class {
1169
1179
  client.release();
1170
1180
  }
1171
1181
  }
1182
+ /**
1183
+ * Wipe the sensitive-data payload for every event on the stream — the
1184
+ * physical-erasure side of the sensitive-data epic (#566). Sets
1185
+ * `events.pii` to `NULL` for the stream's events; `events.data` and
1186
+ * the rest of the row are never touched.
1187
+ *
1188
+ * Row-level locks (no table lock), bounded by events-per-stream.
1189
+ * Idempotent — a second call on an already-wiped stream returns `0`.
1190
+ *
1191
+ * Disk reclamation is autovacuum-driven; for strict-deletion
1192
+ * jurisdictions the production checklist documents `VACUUM FULL` as
1193
+ * the operator step.
1194
+ *
1195
+ * @param stream Target stream
1196
+ * @returns Count of events whose `pii` was set to `NULL`
1197
+ */
1198
+ async forget_pii(stream) {
1199
+ const r = await this._pool.query(
1200
+ `UPDATE ${this._fqt} SET pii = NULL WHERE stream = $1 AND pii IS NOT NULL`,
1201
+ [stream]
1202
+ );
1203
+ return r.rowCount ?? 0;
1204
+ }
1172
1205
  };
1173
1206
  // Annotate the CommonJS export names for ESM import in node:
1174
1207
  0 && (module.exports = {