@anuma/sdk 7.6.1 → 8.0.1

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.
@@ -16919,16 +16919,19 @@ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
16919
16919
  } catch {
16920
16920
  return null;
16921
16921
  }
16922
+ const address = ctx.walletAddress;
16922
16923
  await ctx.database.write(async () => {
16924
+ const key = await resolveMessageEmbeddingKey(address, message.content);
16925
+ const storedVector = await serializeMessageEmbedding(key, vector);
16923
16926
  await message.update((msg) => {
16924
- msg._setRaw("vector", JSON.stringify(vector));
16927
+ msg._setRaw("vector", storedVector);
16925
16928
  if (msg.origin === "chunks_discarded" && vector.length > 0) {
16926
16929
  msg._setRaw("origin", "message");
16927
16930
  }
16928
16931
  msg._setRaw("embedding_model", embeddingModel);
16929
16932
  });
16930
16933
  });
16931
- return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
16934
+ return messageToStored(message, ctx.walletAddress);
16932
16935
  }
16933
16936
  async function updateMessageChunksOp(ctx, uniqueId, chunks, embeddingModel) {
16934
16937
  let message;
@@ -16938,16 +16941,123 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks, embeddingModel) {
16938
16941
  return null;
16939
16942
  }
16940
16943
  const storedChunks = chunks.map(({ text: _text, ...rest }) => rest);
16944
+ const address = ctx.walletAddress;
16941
16945
  await ctx.database.write(async () => {
16946
+ const key = await resolveMessageEmbeddingKey(address, message.content);
16947
+ const serializedChunks = await serializeMessageEmbedding(key, storedChunks);
16942
16948
  await message.update((msg) => {
16943
- msg._setRaw("chunks", JSON.stringify(storedChunks));
16949
+ msg._setRaw("chunks", serializedChunks);
16944
16950
  if (msg.origin === "chunks_discarded" && storedChunks.length > 0 && storedChunks.every((chunk) => chunk.vector.length > 0)) {
16945
16951
  msg._setRaw("origin", "message");
16946
16952
  }
16947
16953
  msg._setRaw("embedding_model", embeddingModel);
16948
16954
  });
16949
16955
  });
16950
- return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
16956
+ return messageToStored(message, ctx.walletAddress);
16957
+ }
16958
+ async function resolveMessageEmbeddingKey(address, content) {
16959
+ if (!address || !isEncrypted(content)) return null;
16960
+ const key = await getEncryptionKey(address, "v3");
16961
+ const contentKey = content.startsWith("enc:v2:") ? await getEncryptionKey(address, "v2") : key;
16962
+ try {
16963
+ await decryptDataWithKey(content.slice("enc:vN:".length), contentKey);
16964
+ } catch {
16965
+ throw new Error("Cannot decrypt the message with the cached wallet key");
16966
+ }
16967
+ return key;
16968
+ }
16969
+ async function serializeMessageEmbedding(key, value) {
16970
+ const json4 = JSON.stringify(value);
16971
+ return key ? `enc:v3:${await encryptDataWithKey(json4, key)}` : json4;
16972
+ }
16973
+ async function decryptMessageEmbeddingFields(raw, walletAddress) {
16974
+ const result = { ...raw };
16975
+ for (const column of ["vector", "chunks"]) {
16976
+ const value = raw[column];
16977
+ if (typeof value !== "string" || !value.startsWith("enc:")) continue;
16978
+ const decrypted = walletAddress ? await decryptField(value, walletAddress) : value;
16979
+ result[column] = decrypted.startsWith("enc:") ? void 0 : decrypted;
16980
+ }
16981
+ return result;
16982
+ }
16983
+ async function sealLegacyMessageEmbeddingsOp(ctx) {
16984
+ if (!ctx.walletAddress) return 0;
16985
+ const candidateIds = await ctx.messagesCollection.query(
16986
+ import_watermelondb2.Q.where("content", import_watermelondb2.Q.like("enc:%")),
16987
+ import_watermelondb2.Q.or(
16988
+ ...["vector", "chunks"].map(
16989
+ (column) => import_watermelondb2.Q.and(
16990
+ import_watermelondb2.Q.where(column, import_watermelondb2.Q.notEq(null)),
16991
+ import_watermelondb2.Q.where(column, import_watermelondb2.Q.notEq("")),
16992
+ import_watermelondb2.Q.where(column, import_watermelondb2.Q.notLike("enc:%"))
16993
+ )
16994
+ )
16995
+ )
16996
+ ).fetchIds();
16997
+ let sealed = 0;
16998
+ let undecryptable = 0;
16999
+ for (let start = 0; start < candidateIds.length; start += 50) {
17000
+ const pageIds = candidateIds.slice(start, start + 50);
17001
+ await ctx.database.write(async () => {
17002
+ const pageMessages = await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(pageIds))).fetch();
17003
+ for (const message of pageMessages) {
17004
+ if (!isEncrypted(message.content)) continue;
17005
+ const content = await decryptFieldDetailed(message.content, ctx.walletAddress);
17006
+ if (content.status === "key_missing") {
17007
+ throw new Error("Cannot decrypt the message with the cached wallet key");
17008
+ }
17009
+ if (content.status !== "ok") {
17010
+ undecryptable++;
17011
+ continue;
17012
+ }
17013
+ const plaintext = content.value;
17014
+ const key = await resolveMessageEmbeddingKey(ctx.walletAddress, message.content);
17015
+ const updates = {};
17016
+ for (const column of ["vector", "chunks"]) {
17017
+ const value = message._getRaw(column);
17018
+ if (typeof value !== "string" || value.startsWith("enc:") || !value) continue;
17019
+ let parsed;
17020
+ try {
17021
+ parsed = JSON.parse(value);
17022
+ } catch {
17023
+ updates[column] = null;
17024
+ continue;
17025
+ }
17026
+ if (!Array.isArray(parsed)) {
17027
+ updates[column] = null;
17028
+ continue;
17029
+ }
17030
+ if (column === "chunks") {
17031
+ const chunks = parsed;
17032
+ if (chunks.some(
17033
+ (chunk) => !chunk || !Number.isInteger(chunk.startOffset) || !Number.isInteger(chunk.endOffset) || chunk.startOffset < 0 || chunk.endOffset <= chunk.startOffset || chunk.endOffset > plaintext.length
17034
+ )) {
17035
+ updates.chunks = null;
17036
+ updates.vector = null;
17037
+ updates.origin = message.origin === "tool_result" ? "tool_result" : "chunks_discarded";
17038
+ break;
17039
+ }
17040
+ parsed = chunks.map(({ text: _text, ...rest }) => rest);
17041
+ }
17042
+ updates[column] = await serializeMessageEmbedding(key, parsed);
17043
+ }
17044
+ if (Object.keys(updates).length === 0) continue;
17045
+ const updatedAt = Number(message._getRaw("updated_at"));
17046
+ const discarded = updates.origin !== void 0;
17047
+ await message.update((msg) => {
17048
+ for (const [column, value] of Object.entries(updates)) msg._setRaw(column, value);
17049
+ msg._setRaw("updated_at", discarded ? Math.max(Date.now(), updatedAt + 1) : updatedAt);
17050
+ });
17051
+ sealed++;
17052
+ }
17053
+ });
17054
+ }
17055
+ if (undecryptable > 0) {
17056
+ getLogger().warn(
17057
+ `Skipped ${undecryptable} message embeddings that the cached wallet key cannot decrypt`
17058
+ );
17059
+ }
17060
+ return sealed;
16951
17061
  }
16952
17062
  var RAW_REPAIR_PAGE_SIZE = 100;
16953
17063
  function chunksWithoutText(raw) {
@@ -37806,6 +37916,7 @@ async function preprocessFiles(files, options = {}) {
37806
37916
 
37807
37917
  // src/server/pg-adapter.ts
37808
37918
  var import_stepsForMigration = __toESM(require_stepsForMigration());
37919
+ import { createHash } from "crypto";
37809
37920
  function makeQualify(pgSchema) {
37810
37921
  if (pgSchema === "public") {
37811
37922
  return (table) => `"${table}"`;
@@ -37821,7 +37932,7 @@ function paramList(params, values) {
37821
37932
  }
37822
37933
  var operators = {
37823
37934
  eq: "=",
37824
- notEq: "!=",
37935
+ notEq: "is distinct from",
37825
37936
  gt: ">",
37826
37937
  gte: ">=",
37827
37938
  weakGt: ">",
@@ -37872,6 +37983,11 @@ function encodeWhere(params, table, associations, clause) {
37872
37983
  throw new Error(`Unknown clause type: ${clause.type}`);
37873
37984
  }
37874
37985
  }
37986
+ function hasSql(clauses) {
37987
+ return clauses.some(
37988
+ (clause) => clause.type === "sql" || "conditions" in clause && hasSql(clause.conditions)
37989
+ );
37990
+ }
37875
37991
  function encodeQuery(query, qualify, countMode = false, idsOnly = false) {
37876
37992
  const { table, description, associations } = query;
37877
37993
  if (description.sql) {
@@ -37954,7 +38070,7 @@ function schemaToCreateSQL(schema, pgSchema = "public") {
37954
38070
  const def = ` default ${columnDefault(col)}`;
37955
38071
  cols.push(`"${col.name}" ${pgType}${nullable}${def}`);
37956
38072
  if (col.isIndexed) {
37957
- const indexName = pgSchema === "public" ? `"${tableName}_${col.name}"` : `"${pgSchema}_${tableName}_${col.name}"`;
38073
+ const indexName = `"${tableName}_${col.name}"`;
37958
38074
  indexes.push(
37959
38075
  `create index if not exists ${indexName} on ${qualify(tableName)} ("${col.name}");`
37960
38076
  );
@@ -37981,14 +38097,73 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
37981
38097
  this.dbName = options.dbName;
37982
38098
  this.migrations = options.migrations;
37983
38099
  this.pool = options.pool;
37984
- this._pgSchema = options.pgSchema ?? "public";
38100
+ this._pgSchema = `anuma_${createHash("sha256").update(JSON.stringify([options.pgSchema ?? "public", this.dbName])).digest("hex").slice(0, 48)}`;
37985
38101
  this.qualify = makeQualify(this._pgSchema);
37986
- this.initialized = this._initialize();
38102
+ this.initialized = this._initialize(
38103
+ options.pgSchema ?? "public",
38104
+ options.migrateLegacySchema ?? false
38105
+ );
37987
38106
  }
37988
- async _initialize() {
37989
- if (this._pgSchema !== "public") {
37990
- await this.pool.query(`create schema if not exists "${this._pgSchema}"`);
38107
+ async _hasLegacyData(pgSchema, executor) {
38108
+ const legacyStorage = `"${pgSchema.replace(/"/g, '""')}"."local_storage"`;
38109
+ const { rows } = await executor.query(
38110
+ "select to_regclass($1) as legacy, to_regclass($2) as isolated",
38111
+ [legacyStorage, this.qualify("local_storage")]
38112
+ );
38113
+ if (!rows[0]?.legacy) return false;
38114
+ if (rows[0].isolated) {
38115
+ const { rows: version2 } = await executor.query(
38116
+ `select "value" from ${this.qualify("local_storage")} where "key" = $1`,
38117
+ [_PostgreSQLAdapter.SCHEMA_VERSION_KEY]
38118
+ );
38119
+ if (Number(version2[0]?.value) > 0) return false;
37991
38120
  }
38121
+ const { rows: version } = await executor.query(
38122
+ `select "value" from ${legacyStorage} where "key" = $1`,
38123
+ [_PostgreSQLAdapter.SCHEMA_VERSION_KEY]
38124
+ );
38125
+ return Number(version[0]?.value) > 0;
38126
+ }
38127
+ async _upgradeLegacySchema(pgSchema, migrateLegacySchema) {
38128
+ if (!migrateLegacySchema) {
38129
+ if (await this._hasLegacyData(pgSchema, this.pool)) {
38130
+ throw new Error(
38131
+ "PostgreSQLAdapter found legacy data. Set migrateLegacySchema to true only for the database that owns all legacy records."
38132
+ );
38133
+ }
38134
+ return;
38135
+ }
38136
+ if (!this.pool.connect) {
38137
+ throw new Error("PostgreSQLAdapter legacy migration requires pool.connect");
38138
+ }
38139
+ const client2 = await this.pool.connect();
38140
+ try {
38141
+ await client2.query("BEGIN");
38142
+ await client2.query("select pg_advisory_xact_lock(hashtext($1))", [
38143
+ `PostgreSQLAdapter:${pgSchema}`
38144
+ ]);
38145
+ if (await this._hasLegacyData(pgSchema, client2)) {
38146
+ await client2.query(`create schema if not exists "${this._pgSchema}"`);
38147
+ const { rows } = await client2.query(
38148
+ "select tablename from pg_catalog.pg_tables where schemaname = $1 and tablename = any($2::text[])",
38149
+ [pgSchema, [...Object.keys(this.schema.tables), "local_storage"]]
38150
+ );
38151
+ for (const row of rows) {
38152
+ const table = `"${pgSchema.replace(/"/g, '""')}"."${String(row.tablename).replace(/"/g, '""')}"`;
38153
+ await client2.query(`alter table ${table} set schema "${this._pgSchema}"`);
38154
+ }
38155
+ }
38156
+ await client2.query("COMMIT");
38157
+ } catch (error) {
38158
+ await client2.query("ROLLBACK");
38159
+ throw error;
38160
+ } finally {
38161
+ client2.release();
38162
+ }
38163
+ }
38164
+ async _initialize(pgSchema, migrateLegacySchema) {
38165
+ await this._upgradeLegacySchema(pgSchema, migrateLegacySchema);
38166
+ await this.pool.query(`create schema if not exists "${this._pgSchema}"`);
37992
38167
  await this.pool.query(
37993
38168
  `create table if not exists ${this.qualify("local_storage")} ("key" text primary key, "value" text not null);`
37994
38169
  );
@@ -38057,7 +38232,7 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38057
38232
  );
38058
38233
  for (const col of ts.columnArray) {
38059
38234
  if (col.isIndexed) {
38060
- const indexName = this._pgSchema === "public" ? `"${ts.name}_${col.name}"` : `"${this._pgSchema}_${ts.name}_${col.name}"`;
38235
+ const indexName = `"${ts.name}_${col.name}"`;
38061
38236
  await this.pool.query(
38062
38237
  `create index if not exists ${indexName} on ${this.qualify(ts.name)} ("${col.name}");`
38063
38238
  );
@@ -38075,7 +38250,7 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38075
38250
  `alter table ${this.qualify(table)} add column if not exists "${col.name}" ${pgType}${nullable}${def};`
38076
38251
  );
38077
38252
  if (col.isIndexed) {
38078
- const indexName = this._pgSchema === "public" ? `"${table}_${col.name}"` : `"${this._pgSchema}_${table}_${col.name}"`;
38253
+ const indexName = `"${table}_${col.name}"`;
38079
38254
  await this.pool.query(
38080
38255
  `create index if not exists ${indexName} on ${this.qualify(table)} ("${col.name}");`
38081
38256
  );
@@ -38084,26 +38259,34 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38084
38259
  break;
38085
38260
  }
38086
38261
  case "sql": {
38087
- if (this._pgSchema !== "public" && this.pool.connect) {
38088
- const client2 = await this.pool.connect();
38089
- try {
38090
- await client2.query("BEGIN");
38091
- await client2.query(`SET LOCAL search_path TO "${this._pgSchema}", public`);
38092
- await client2.query(step.sql);
38093
- await client2.query("COMMIT");
38094
- } catch (err) {
38095
- await client2.query("ROLLBACK");
38096
- throw err;
38097
- } finally {
38098
- client2.release();
38099
- }
38100
- } else {
38101
- await this.pool.query(step.sql);
38102
- }
38262
+ await this._withSchema((client2) => client2.query(step.sql));
38103
38263
  break;
38104
38264
  }
38105
38265
  }
38106
38266
  }
38267
+ async _withSchema(run) {
38268
+ if (!this.pool.connect) {
38269
+ throw new Error("PostgreSQLAdapter raw SQL requires pool.connect for database isolation");
38270
+ }
38271
+ const client2 = await this.pool.connect();
38272
+ try {
38273
+ await client2.query("BEGIN");
38274
+ await client2.query(`SET LOCAL search_path TO "${this._pgSchema}"`);
38275
+ const result = await run(client2);
38276
+ await client2.query("COMMIT");
38277
+ return result;
38278
+ } catch (err) {
38279
+ await client2.query("ROLLBACK");
38280
+ throw err;
38281
+ } finally {
38282
+ client2.release();
38283
+ }
38284
+ }
38285
+ async _query(query, countMode = false, idsOnly = false) {
38286
+ const [sql, values] = encodeQuery(query, this.qualify, countMode, idsOnly);
38287
+ const description = query.description;
38288
+ return description.sql || hasSql(description.where) ? this._withSchema((client2) => client2.query(sql, values)) : this.pool.query(sql, values);
38289
+ }
38107
38290
  async _resetAndRecreate(targetVersion) {
38108
38291
  for (const tableName of Object.keys(this.schema.tables)) {
38109
38292
  await this.pool.query(`drop table if exists ${this.qualify(tableName)} cascade;`);
@@ -38147,8 +38330,7 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38147
38330
  this._fromPromise(
38148
38331
  (async () => {
38149
38332
  await this._ready();
38150
- const [sql, values] = encodeQuery(query, this.qualify);
38151
- const { rows } = await this.pool.query(sql, values);
38333
+ const { rows } = await this._query(query);
38152
38334
  return rows.map(rowToRaw);
38153
38335
  })(),
38154
38336
  callback
@@ -38158,8 +38340,7 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38158
38340
  this._fromPromise(
38159
38341
  (async () => {
38160
38342
  await this._ready();
38161
- const [sql, values] = encodeQuery(query, this.qualify, false, true);
38162
- const { rows } = await this.pool.query(sql, values);
38343
+ const { rows } = await this._query(query, false, true);
38163
38344
  return rows.map((r) => r.id);
38164
38345
  })(),
38165
38346
  callback
@@ -38170,8 +38351,7 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38170
38351
  this._fromPromise(
38171
38352
  (async () => {
38172
38353
  await this._ready();
38173
- const [sql, values] = encodeQuery(query, this.qualify);
38174
- const { rows } = await this.pool.query(sql, values);
38354
+ const { rows } = await this._query(query);
38175
38355
  return rows;
38176
38356
  })(),
38177
38357
  callback
@@ -38181,8 +38361,7 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38181
38361
  this._fromPromise(
38182
38362
  (async () => {
38183
38363
  await this._ready();
38184
- const [sql, values] = encodeQuery(query, this.qualify, true);
38185
- const { rows } = await this.pool.query(sql, values);
38364
+ const { rows } = await this._query(query, true);
38186
38365
  return Number(rows[0]?.count ?? 0);
38187
38366
  })(),
38188
38367
  callback
@@ -38306,7 +38485,7 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38306
38485
  this._fromPromise(
38307
38486
  (async () => {
38308
38487
  await this._ready();
38309
- await this.pool.query(ops.sqlString);
38488
+ await this._withSchema((client2) => client2.query(ops.sqlString));
38310
38489
  })(),
38311
38490
  callback
38312
38491
  );
@@ -38316,9 +38495,11 @@ var _PostgreSQLAdapter = class _PostgreSQLAdapter {
38316
38495
  this._fromPromise(
38317
38496
  (async () => {
38318
38497
  await this._ready();
38319
- for (const [sql, args] of ops.sqls) {
38320
- await this.pool.query(sql, args);
38321
- }
38498
+ await this._withSchema(async (client2) => {
38499
+ for (const [sql, args] of ops.sqls) {
38500
+ await client2.query(sql, args);
38501
+ }
38502
+ });
38322
38503
  })(),
38323
38504
  callback
38324
38505
  );
@@ -38526,6 +38707,7 @@ export {
38526
38707
  decryptDataBytes,
38527
38708
  decryptDataBytesFromBytes,
38528
38709
  decryptDataWithKey,
38710
+ decryptMessageEmbeddingFields,
38529
38711
  defaultServerToolsFilter,
38530
38712
  deleteAllVaultMemoriesForUserOp,
38531
38713
  deleteConversationOp,
@@ -38649,6 +38831,7 @@ export {
38649
38831
  sdkMigrations,
38650
38832
  sdkModelClasses,
38651
38833
  sdkSchema,
38834
+ sealLegacyMessageEmbeddingsOp,
38652
38835
  searchChunksOp,
38653
38836
  searchMediaOp,
38654
38837
  searchMessagesOp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "7.6.1",
3
+ "version": "8.0.1",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",