@hasna/mementos 0.14.69 → 0.14.71

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/index.js CHANGED
@@ -46,6 +46,27 @@ var __export = (target, all) => {
46
46
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
47
  var __require = import.meta.require;
48
48
 
49
+ // src/generated/storage-kit/mode.ts
50
+ function normalizeStorageMode(value) {
51
+ const normalized = value.trim().toLowerCase().replace(/-/g, "_");
52
+ if (normalized === "local")
53
+ return { mode: "local", deprecatedAlias: null };
54
+ if (normalized === "cloud")
55
+ return { mode: "cloud", deprecatedAlias: null };
56
+ if (DEPRECATED_STORAGE_MODE_ALIASES.includes(normalized)) {
57
+ return { mode: "cloud", deprecatedAlias: normalized };
58
+ }
59
+ throw new Error(`Unknown storage mode: ${value}. Use local or cloud.`);
60
+ }
61
+ var DEPRECATED_STORAGE_MODE_ALIASES;
62
+ var init_mode = __esm(() => {
63
+ DEPRECATED_STORAGE_MODE_ALIASES = [
64
+ "remote",
65
+ "hybrid",
66
+ "self_hosted"
67
+ ];
68
+ });
69
+
49
70
  // src/storage.ts
50
71
  import { Database } from "bun:sqlite";
51
72
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -57,6 +78,12 @@ import pg from "pg";
57
78
  function markServerContext() {
58
79
  _serverContext = true;
59
80
  }
81
+ function resetServerContextForTests() {
82
+ if (process.env["NODE_ENV"] !== "test") {
83
+ throw new Error("resetServerContextForTests is only available under NODE_ENV=test");
84
+ }
85
+ _serverContext = false;
86
+ }
60
87
  function isServerContext() {
61
88
  return _serverContext;
62
89
  }
@@ -307,18 +334,20 @@ function warnDeprecatedStorageMode(alias) {
307
334
  warnedDeprecatedModes.add(alias);
308
335
  process.emitWarning(`${MEMENTOS_STORAGE_ENV.mode}="${alias}" is deprecated; use "cloud". ` + `"${alias}" now maps to pure-remote cloud storage. The local<->remote ` + `sync path is deprecated and is not the fleet cutover path.`, { type: "DeprecationWarning", code: "MEMENTOS_STORAGE_MODE_ALIAS" });
309
336
  }
310
- function normalizeStorageMode(value) {
311
- if (!value)
337
+ function normalizeStorageMode2(value, source) {
338
+ if (!value || !value.trim())
312
339
  return null;
313
- const normalized = value.trim().toLowerCase();
314
- if (normalized === "local" || normalized === "cloud") {
315
- return normalized;
340
+ let normalized;
341
+ try {
342
+ normalized = normalizeStorageMode(value);
343
+ } catch (error) {
344
+ const detail = error instanceof Error ? error.message : String(error);
345
+ throw new Error(`mementos: ${source}=${value} is not a valid mode. ${detail}`);
316
346
  }
317
- if (normalized === "remote" || normalized === "hybrid") {
318
- warnDeprecatedStorageMode(normalized);
319
- return "cloud";
347
+ if (normalized.deprecatedAlias) {
348
+ warnDeprecatedStorageMode(normalized.deprecatedAlias);
320
349
  }
321
- return null;
350
+ return normalized.mode;
322
351
  }
323
352
  function readConfigFile() {
324
353
  if (!existsSync(STORAGE_CONFIG_PATH)) {
@@ -357,7 +386,7 @@ function getStorageDatabaseEnvName() {
357
386
  }
358
387
  function getStorageModeOverride() {
359
388
  for (const env of MODE_ENV_NAMES) {
360
- const value = normalizeStorageMode(readEnv(env.name) ?? undefined);
389
+ const value = normalizeStorageMode2(readEnv(env.name) ?? undefined, env.name);
361
390
  if (value)
362
391
  return value;
363
392
  }
@@ -367,7 +396,7 @@ function getStorageConfig() {
367
396
  const fileConfig = readConfigFile();
368
397
  const modeOverride = getStorageModeOverride();
369
398
  const envConnectionString = getConfiguredConnectionString();
370
- const fileMode = normalizeStorageMode(fileConfig.mode);
399
+ const fileMode = normalizeStorageMode2(fileConfig.mode, `${STORAGE_CONFIG_PATH} "mode"`);
371
400
  const merged = {
372
401
  ...DEFAULT_STORAGE_CONFIG,
373
402
  ...fileConfig,
@@ -794,6 +823,7 @@ CREATE TABLE IF NOT EXISTS _sync_meta (
794
823
  direction TEXT DEFAULT 'push'
795
824
  )`;
796
825
  var init_storage = __esm(() => {
826
+ init_mode();
797
827
  PgSyncPool = class PgSyncPool {
798
828
  worker;
799
829
  status;
@@ -1147,7 +1177,24 @@ var init_api_mode = __esm(() => {
1147
1177
  });
1148
1178
 
1149
1179
  // src/db/migrations.ts
1150
- var MIGRATIONS;
1180
+ var MEMORY_VERSION_SNAPSHOT_TRIGGER = `
1181
+ CREATE TRIGGER IF NOT EXISTS memories_version_snapshot
1182
+ BEFORE UPDATE ON memories
1183
+ WHEN NEW.version > OLD.version
1184
+ BEGIN
1185
+ INSERT OR IGNORE INTO memory_versions (
1186
+ id, memory_id, version, value, importance, scope, category, tags,
1187
+ summary, pinned, status, when_to_use, created_at
1188
+ ) VALUES (
1189
+ lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-' ||
1190
+ lower(hex(randomblob(2))) || '-' || lower(hex(randomblob(2))) || '-' ||
1191
+ lower(hex(randomblob(6))),
1192
+ OLD.id, OLD.version, OLD.value, OLD.importance, OLD.scope, OLD.category,
1193
+ OLD.tags, OLD.summary, OLD.pinned, OLD.status, OLD.when_to_use,
1194
+ OLD.updated_at
1195
+ );
1196
+ END;
1197
+ `, MIGRATIONS;
1151
1198
  var init_migrations = __esm(() => {
1152
1199
  MIGRATIONS = [
1153
1200
  `
@@ -2045,6 +2092,10 @@ CREATE INDEX IF NOT EXISTS idx_memory_reflection_lessons_memory ON memory_reflec
2045
2092
  CREATE INDEX IF NOT EXISTS idx_memory_reflection_lessons_kind ON memory_reflection_lessons(kind);
2046
2093
 
2047
2094
  INSERT OR IGNORE INTO _migrations (id) VALUES (35);
2095
+ `,
2096
+ `
2097
+ ${MEMORY_VERSION_SNAPSHOT_TRIGGER}
2098
+ INSERT OR IGNORE INTO _migrations (id) VALUES (36);
2048
2099
  `
2049
2100
  ];
2050
2101
  });
@@ -2059,6 +2110,7 @@ __export(exports_database, {
2059
2110
  now: () => now,
2060
2111
  getDbPath: () => getDbPath,
2061
2112
  getDatabase: () => getDatabase,
2113
+ escapeLikePrefix: () => escapeLikePrefix,
2062
2114
  closeDatabase: () => closeDatabase
2063
2115
  });
2064
2116
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, cpSync } from "fs";
@@ -2233,15 +2285,20 @@ function uuid() {
2233
2285
  function shortUuid() {
2234
2286
  return crypto.randomUUID().slice(0, 8);
2235
2287
  }
2288
+ function escapeLikePrefix(s) {
2289
+ return s.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
2290
+ }
2236
2291
  function resolvePartialId(db, table, partialId) {
2237
2292
  if (!ALLOWED_TABLES.has(table)) {
2238
2293
  throw new Error(`Invalid table name: ${table}`);
2239
2294
  }
2295
+ if (partialId === "")
2296
+ return null;
2240
2297
  if (partialId.length >= 36) {
2241
2298
  const row = db.query(`SELECT id FROM ${table} WHERE id = ?`).get(partialId);
2242
2299
  return row?.id ?? null;
2243
2300
  }
2244
- const rows = db.query(`SELECT id FROM ${table} WHERE id LIKE ?`).all(`${partialId}%`);
2301
+ const rows = db.query(`SELECT id FROM ${table} WHERE id LIKE ? ESCAPE '\\'`).all(`${escapeLikePrefix(partialId)}%`);
2245
2302
  if (rows.length === 1) {
2246
2303
  return rows[0].id;
2247
2304
  }
@@ -49737,33 +49794,19 @@ function updateMemory(id, input, db) {
49737
49794
  const { status, data } = apiJson("PATCH", `/memories/${encodeURIComponent(id)}`, input, { allow404: true });
49738
49795
  if (status === 404)
49739
49796
  throw new MemoryNotFoundError(id);
49797
+ if (data && typeof input.version === "number" && typeof data.version === "number" && data.version <= input.version) {
49798
+ throw new Error(`Update did not persist for memory ${id}: the server returned success but the record is unchanged ` + `(version still ${data.version}). Your data was NOT written. ` + `The server is likely running a build predating the partial-id fix \u2014 pass the full 36-character id as a workaround.`);
49799
+ }
49740
49800
  return data;
49741
49801
  }
49742
49802
  const d = db || getDatabase();
49743
49803
  const existing = getMemory(id, d);
49744
49804
  if (!existing)
49745
49805
  throw new MemoryNotFoundError(id);
49806
+ const memoryId = existing.id;
49746
49807
  if (existing.version !== input.version) {
49747
49808
  throw new VersionConflictError(id, input.version, existing.version);
49748
49809
  }
49749
- try {
49750
- d.run(`INSERT OR IGNORE INTO memory_versions (id, memory_id, version, value, importance, scope, category, tags, summary, pinned, status, when_to_use, created_at)
49751
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
49752
- uuid(),
49753
- existing.id,
49754
- existing.version,
49755
- existing.value,
49756
- existing.importance,
49757
- existing.scope,
49758
- existing.category,
49759
- JSON.stringify(existing.tags),
49760
- existing.summary,
49761
- existing.pinned ? 1 : 0,
49762
- existing.status,
49763
- existing.when_to_use || null,
49764
- existing.updated_at
49765
- ]);
49766
- } catch {}
49767
49810
  const sets = ["version = version + 1", "updated_at = ?"];
49768
49811
  const params = [now()];
49769
49812
  if (input.value !== undefined) {
@@ -49813,15 +49856,18 @@ function updateMemory(id, input, db) {
49813
49856
  if (input.tags !== undefined) {
49814
49857
  sets.push("tags = ?");
49815
49858
  params.push(JSON.stringify(input.tags));
49816
- d.run("DELETE FROM memory_tags WHERE memory_id = ?", [id]);
49859
+ d.run("DELETE FROM memory_tags WHERE memory_id = ?", [memoryId]);
49817
49860
  const insertTag = d.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag) VALUES (?, ?)");
49818
49861
  for (const tag of input.tags) {
49819
- insertTag.run(id, tag);
49862
+ insertTag.run(memoryId, tag);
49820
49863
  }
49821
49864
  }
49822
- params.push(id);
49823
- d.run(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`, params);
49824
- const updated = getMemory(id, d);
49865
+ params.push(memoryId);
49866
+ const result = d.run(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`, params);
49867
+ if (result.changes === 0) {
49868
+ throw new Error(`Update affected no rows for memory ${memoryId}: the record was read but not written. ` + `This is a bug in @hasna/mementos, not a bad argument \u2014 please report it.`);
49869
+ }
49870
+ const updated = getMemory(memoryId, d);
49825
49871
  if (input.value !== undefined) {
49826
49872
  try {
49827
49873
  const oldLinks = getEntityMemoryLinks(undefined, updated.id, d);
@@ -49846,10 +49892,11 @@ function deleteMemory(id, db) {
49846
49892
  return status !== 404;
49847
49893
  }
49848
49894
  const d = db || getDatabase();
49849
- const result = d.run("DELETE FROM memories WHERE id = ?", [id]);
49895
+ const memoryId = resolvePartialId(d, "memories", id) ?? id;
49896
+ const result = d.run("DELETE FROM memories WHERE id = ?", [memoryId]);
49850
49897
  if (result.changes > 0) {
49851
49898
  hookRegistry.runHooks("PostMemoryDelete", {
49852
- memoryId: id,
49899
+ memoryId,
49853
49900
  timestamp: Date.now()
49854
49901
  });
49855
49902
  }
@@ -49863,11 +49910,12 @@ function bulkDeleteMemories(ids, db) {
49863
49910
  return data?.deleted ?? 0;
49864
49911
  }
49865
49912
  const d = db || getDatabase();
49866
- const placeholders = ids.map(() => "?").join(",");
49867
- const countRow = d.query(`SELECT COUNT(*) as c FROM memories WHERE id IN (${placeholders})`).get(...ids);
49913
+ const resolvedIds = ids.map((id) => resolvePartialId(d, "memories", id) ?? id);
49914
+ const placeholders = resolvedIds.map(() => "?").join(",");
49915
+ const countRow = d.query(`SELECT COUNT(*) as c FROM memories WHERE id IN (${placeholders})`).get(...resolvedIds);
49868
49916
  const count = countRow.c;
49869
49917
  if (count > 0) {
49870
- d.run(`DELETE FROM memories WHERE id IN (${placeholders})`, ids);
49918
+ d.run(`DELETE FROM memories WHERE id IN (${placeholders})`, resolvedIds);
49871
49919
  }
49872
49920
  return count;
49873
49921
  }
@@ -50024,7 +50072,7 @@ function getAgent(idOrName, db) {
50024
50072
  row = d.query("SELECT * FROM agents WHERE LOWER(name) = ?").get(idOrName.trim().toLowerCase());
50025
50073
  if (row)
50026
50074
  return parseAgentRow(row);
50027
- const rows = d.query("SELECT * FROM agents WHERE id LIKE ?").all(`${idOrName}%`);
50075
+ const rows = d.query("SELECT * FROM agents WHERE id LIKE ? ESCAPE '\\'").all(`${escapeLikePrefix(idOrName)}%`);
50028
50076
  if (rows.length === 1)
50029
50077
  return parseAgentRow(rows[0]);
50030
50078
  return null;
@@ -53439,6 +53487,32 @@ class AutoMemoryQueue {
53439
53487
  getStats() {
53440
53488
  return { ...this.stats, pending: this.queue.length };
53441
53489
  }
53490
+ async waitForIdleForTests(timeoutMs = 3000) {
53491
+ const start = Date.now();
53492
+ while (Date.now() - start < timeoutMs) {
53493
+ if (this.queue.length === 0 && this.activeCount === 0)
53494
+ return;
53495
+ await new Promise((r) => setTimeout(r, 20));
53496
+ }
53497
+ throw new Error("autoMemoryQueue did not become idle before test reset");
53498
+ }
53499
+ resetForTests(handler) {
53500
+ if (this.activeCount !== 0) {
53501
+ throw new Error("Cannot reset autoMemoryQueue while jobs are processing");
53502
+ }
53503
+ this.queue = [];
53504
+ this.running = false;
53505
+ this.stats = {
53506
+ pending: 0,
53507
+ processing: 0,
53508
+ processed: 0,
53509
+ failed: 0,
53510
+ dropped: 0
53511
+ };
53512
+ if (handler !== undefined) {
53513
+ this.handler = handler;
53514
+ }
53515
+ }
53442
53516
  startLoop() {
53443
53517
  this.running = true;
53444
53518
  this.loop();
@@ -36,6 +36,8 @@ declare class AutoMemoryQueue {
36
36
  */
37
37
  enqueue(job: ExtractionJob): void;
38
38
  getStats(): Readonly<QueueStats>;
39
+ waitForIdleForTests(timeoutMs?: number): Promise<void>;
40
+ resetForTests(handler?: JobHandler | null): void;
39
41
  private startLoop;
40
42
  private loop;
41
43
  private processJob;
@@ -1 +1 @@
1
- {"version":3,"file":"auto-memory-queue.d.ts","sourceRoot":"","sources":["../../src/lib/auto-memory-queue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAKxD,cAAM,eAAe;IACnB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAK;IAExB,OAAO,CAAC,KAAK,CAMX;IAEF,mDAAmD;IACnD,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAKrC;;;OAGG;IACH,OAAO,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAYjC,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC;IAIhC,OAAO,CAAC,SAAS;YAKH,IAAI;YAiBJ,UAAU;CAiBzB;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
1
+ {"version":3,"file":"auto-memory-queue.d.ts","sourceRoot":"","sources":["../../src/lib/auto-memory-queue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAKxD,cAAM,eAAe;IACnB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAK;IAExB,OAAO,CAAC,KAAK,CAMX;IAEF,mDAAmD;IACnD,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAKrC;;;OAGG;IACH,OAAO,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAYjC,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC;IAI1B,mBAAmB,CAAC,SAAS,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1D,aAAa,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAkBhD,OAAO,CAAC,SAAS;YAKH,IAAI;YAiBJ,UAAU;CAiBzB;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
@@ -15,4 +15,5 @@ export declare function processConversationTurn(turn: string, context: Omit<Extr
15
15
  export declare function getAutoMemoryStats(): Readonly<import("./auto-memory-queue.js").QueueStats>;
16
16
  /** Configure the auto-memory pipeline at runtime */
17
17
  export declare function configureAutoMemory(config: Parameters<typeof providerRegistry.configure>[0]): void;
18
+ export declare function resetAutoMemoryForTests(): Promise<void>;
18
19
  //# sourceMappingURL=auto-memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auto-memory.d.ts","sourceRoot":"","sources":["../../src/lib/auto-memory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAgO7E;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW,CAAC,EAClD,MAAM,GAAE,aAAa,CAAC,QAAQ,CAAU,GACvC,IAAI,CAQN;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,0DAEjC;AAED,oDAAoD;AACpD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GACvD,IAAI,CAEN"}
1
+ {"version":3,"file":"auto-memory.d.ts","sourceRoot":"","sources":["../../src/lib/auto-memory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAgO7E;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW,CAAC,EAClD,MAAM,GAAE,aAAa,CAAC,QAAQ,CAAU,GACvC,IAAI,CAQN;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,0DAEjC;AAED,oDAAoD;AACpD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GACvD,IAAI,CAEN;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"built-in-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/built-in-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAwOlD,wBAAgB,kBAAkB,IAAI,IAAI,CAyBzC;AAuBD,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAGD,YAAY,EAAE,QAAQ,EAAE,CAAC"}
1
+ {"version":3,"file":"built-in-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/built-in-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAyOlD,wBAAgB,kBAAkB,IAAI,IAAI,CAyBzC;AAuBD,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAGD,YAAY,EAAE,QAAQ,EAAE,CAAC"}
@@ -12,9 +12,24 @@ export interface GdprErasureResult {
12
12
  }
13
13
  /**
14
14
  * Erase all memories containing the given PII identifier.
15
- * Replaces value, summary, and key with "[REDACTED]".
16
- * Clears tags and metadata that might contain PII.
15
+ *
16
+ * Replaces `value` with "[REDACTED]", clears `summary`, `tags` and `metadata`,
17
+ * and rewrites `key` to `[REDACTED]:<random token>` — per-row, for the reason
18
+ * given at the UPDATE below. Nothing derived from the original key or imported
19
+ * row id is retained.
20
+ *
21
+ * The erase runs in ONE TRANSACTION and is therefore all-or-nothing: a caller
22
+ * never observes a partially-erased subject, and a failed attempt leaves the
23
+ * store fully intact so a retry starts from a clean, still-fully-matching set.
24
+ *
17
25
  * Preserves the audit trail (audit_log entries have hashes, not content).
26
+ *
27
+ * NOTE: an erased memory is no longer reachable by its original key, so a later
28
+ * `save` under that key creates a NEW record rather than merging into the
29
+ * tombstone. That is deliberate: silently resurrecting an erased row and
30
+ * re-associating it with the data subject is precisely what erasure must
31
+ * prevent. Every foreign key into `memories` references `memories(id)` — no
32
+ * relational integrity depends on `key`, which is a human lookup handle only.
18
33
  */
19
34
  export declare function gdprErase(identifier: string, options?: {
20
35
  project_id?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"gdpr.d.ts","sourceRoot":"","sources":["../../src/lib/gdpr.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG1D,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,EACN,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,CAwDnB"}
1
+ {"version":3,"file":"gdpr.d.ts","sourceRoot":"","sources":["../../src/lib/gdpr.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG1D,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,EACN,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,CA8JnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4CpE,0FAA0F;AAC1F,eAAO,IAAI,SAAS,EAAE,SAAS,GAAG,IAAW,CAAC;AAqB9C,wBAAgB,WAAW,IAAI,SAAS,CA2EvC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4CpE,0FAA0F;AAC1F,eAAO,IAAI,SAAS,EAAE,SAAS,GAAG,IAAW,CAAC;AAsB9C,wBAAgB,WAAW,IAAI,SAAS,CA2EvC"}