@anuma/sdk 4.1.0 → 4.2.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.
- package/dist/expo/{chunk-VBO6KSNQ.mjs → chunk-3CDSIN22.mjs} +304 -49
- package/dist/expo/index.cjs +446 -59
- package/dist/expo/index.d.mts +115 -11
- package/dist/expo/index.d.ts +115 -11
- package/dist/expo/index.mjs +146 -11
- package/dist/expo/{recall-OCQOA7M3.mjs → recall-NARBDQAK.mjs} +1 -1
- package/dist/index.cjs +31 -17
- package/dist/index.mjs +31 -17
- package/dist/react/{chunk-BS7C4CUW.mjs → chunk-CUJDSH55.mjs} +304 -49
- package/dist/react/index.cjs +446 -59
- package/dist/react/index.d.mts +109 -11
- package/dist/react/index.d.ts +109 -11
- package/dist/react/index.mjs +146 -11
- package/dist/react/{recall-WXCZHXHZ.mjs → recall-FPPCKYYH.mjs} +1 -1
- package/dist/server/{chunk-WADHFDMA.mjs → chunk-UQDYBQVF.mjs} +304 -49
- package/dist/server/index.cjs +446 -59
- package/dist/server/index.d.mts +108 -10
- package/dist/server/index.d.ts +108 -10
- package/dist/server/index.mjs +146 -11
- package/dist/server/{recall-QTVT7HCZ.mjs → recall-ZHEPQNEU.mjs} +1 -1
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
EMBEDDINGS_DEGRADED_EMPTY,
|
|
9
9
|
ENTITY_FANOUT,
|
|
10
10
|
ENTITY_KINDS,
|
|
11
|
+
EncryptionKeyMissingError,
|
|
11
12
|
LRUCache,
|
|
12
13
|
MAX_HOPS,
|
|
13
14
|
NODE_BUDGET,
|
|
@@ -92,6 +93,7 @@ import {
|
|
|
92
93
|
prepareVaultCandidates,
|
|
93
94
|
rankPreparedVaultCandidates,
|
|
94
95
|
recall,
|
|
96
|
+
refreshEncryptionKeyIfMatches,
|
|
95
97
|
relinkMemoryTopicsOp,
|
|
96
98
|
replaceMemoryEntitiesGuardedOp,
|
|
97
99
|
requestEncryptionKey,
|
|
@@ -99,6 +101,7 @@ import {
|
|
|
99
101
|
restoreVaultMemoryOp,
|
|
100
102
|
searchChunksOp,
|
|
101
103
|
searchVaultMemories,
|
|
104
|
+
seedEncryptionKeys,
|
|
102
105
|
setMemoryVisibilityOp,
|
|
103
106
|
shouldChunkMessage,
|
|
104
107
|
stampTopicsExtractedAtOp,
|
|
@@ -116,7 +119,7 @@ import {
|
|
|
116
119
|
upsertMessageOp,
|
|
117
120
|
useEncryption,
|
|
118
121
|
vaultMemoryToStored
|
|
119
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-3CDSIN22.mjs";
|
|
120
123
|
import {
|
|
121
124
|
PII_PATTERNS,
|
|
122
125
|
PiiRedactor,
|
|
@@ -8114,21 +8117,63 @@ var DEFAULT_PROFILE_FACETS = [
|
|
|
8114
8117
|
guidance: "Summarize what the person has been up to lately in one line, favoring the most recently reinforced facts. Frame it as current/ongoing (e.g. 'Lately: training for a first half-marathon and learning Portuguese'). Omit if nothing recent stands out."
|
|
8115
8118
|
}
|
|
8116
8119
|
];
|
|
8120
|
+
var NEARBY_MAX_OCCUPATION_CODEPOINTS = 80;
|
|
8121
|
+
var NEARBY_MAX_INTERESTS = 12;
|
|
8122
|
+
var NEARBY_MAX_INTEREST_CODEPOINTS = 40;
|
|
8123
|
+
var MAX_RAW_INTERESTS = NEARBY_MAX_INTERESTS * 2;
|
|
8124
|
+
function codePointLength(value) {
|
|
8125
|
+
return [...value].length;
|
|
8126
|
+
}
|
|
8127
|
+
var FACET_BASE_PROPERTIES = {
|
|
8128
|
+
summary: {
|
|
8129
|
+
type: "string",
|
|
8130
|
+
description: "The synthesized section prose. Empty string if the memories don't cover it."
|
|
8131
|
+
},
|
|
8132
|
+
hasEvidence: {
|
|
8133
|
+
type: "boolean",
|
|
8134
|
+
description: "False when the supplied memories don't support any claim for this facet."
|
|
8135
|
+
}
|
|
8136
|
+
};
|
|
8117
8137
|
var FACET_RESPONSE_SCHEMA = {
|
|
8138
|
+
type: "object",
|
|
8139
|
+
properties: FACET_BASE_PROPERTIES,
|
|
8140
|
+
required: ["summary", "hasEvidence"],
|
|
8141
|
+
additionalProperties: false
|
|
8142
|
+
};
|
|
8143
|
+
var WORK_ROLE_RESPONSE_SCHEMA = {
|
|
8118
8144
|
type: "object",
|
|
8119
8145
|
properties: {
|
|
8120
|
-
|
|
8146
|
+
...FACET_BASE_PROPERTIES,
|
|
8147
|
+
occupation: {
|
|
8121
8148
|
type: "string",
|
|
8122
|
-
description:
|
|
8123
|
-
},
|
|
8124
|
-
hasEvidence: {
|
|
8125
|
-
type: "boolean",
|
|
8126
|
-
description: "False when the supplied memories don't support any claim for this facet."
|
|
8149
|
+
description: `The same role as a standalone phrase for a profile field, at most ${NEARBY_MAX_OCCUPATION_CODEPOINTS} characters (e.g. "Backend engineer, fintech"). Empty string when hasEvidence is false.`
|
|
8127
8150
|
}
|
|
8128
8151
|
},
|
|
8129
|
-
required: ["summary", "hasEvidence"],
|
|
8152
|
+
required: ["summary", "hasEvidence", "occupation"],
|
|
8153
|
+
additionalProperties: false
|
|
8154
|
+
};
|
|
8155
|
+
var INTERESTS_RESPONSE_SCHEMA = {
|
|
8156
|
+
type: "object",
|
|
8157
|
+
properties: {
|
|
8158
|
+
...FACET_BASE_PROPERTIES,
|
|
8159
|
+
interests: {
|
|
8160
|
+
type: "array",
|
|
8161
|
+
items: { type: "string" },
|
|
8162
|
+
description: `The same interests as discrete strings \u2014 at most ${NEARBY_MAX_INTERESTS} items, each at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters (e.g. ["trail running", "film photography"]). Empty array when hasEvidence is false.`
|
|
8163
|
+
}
|
|
8164
|
+
},
|
|
8165
|
+
required: ["summary", "hasEvidence", "interests"],
|
|
8130
8166
|
additionalProperties: false
|
|
8131
8167
|
};
|
|
8168
|
+
function facetResponseSchema(key) {
|
|
8169
|
+
if (key === "work_role") return WORK_ROLE_RESPONSE_SCHEMA;
|
|
8170
|
+
if (key === "interests") return INTERESTS_RESPONSE_SCHEMA;
|
|
8171
|
+
return FACET_RESPONSE_SCHEMA;
|
|
8172
|
+
}
|
|
8173
|
+
var FACET_STRUCTURED_RESPONSE_HINT = {
|
|
8174
|
+
work_role: `, "occupation": <the role as a standalone phrase of at most ${NEARBY_MAX_OCCUPATION_CODEPOINTS} characters, e.g. "Backend engineer, fintech", or "">`,
|
|
8175
|
+
interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
|
|
8176
|
+
};
|
|
8132
8177
|
async function synthesizeProfile(ctx, options = {}) {
|
|
8133
8178
|
if (!ctx.vaultCtx) {
|
|
8134
8179
|
throw new Error("synthesizeProfile requires ctx.vaultCtx (vault-backed facts).");
|
|
@@ -8224,7 +8269,7 @@ function reviewedMemoryIdsSignature(ids) {
|
|
|
8224
8269
|
return [...new Set(ids)].sort().join("\n");
|
|
8225
8270
|
}
|
|
8226
8271
|
function facetsSignature(facets) {
|
|
8227
|
-
return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance])).sort().join("\n");
|
|
8272
|
+
return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance, facetResponseSchema(f.key)])).sort().join("\n");
|
|
8228
8273
|
}
|
|
8229
8274
|
function trendsEqual(a, b) {
|
|
8230
8275
|
if (!a) return false;
|
|
@@ -8372,7 +8417,7 @@ async function synthesizeFacet(facet, ctx, options, prior) {
|
|
|
8372
8417
|
types: ["fact"],
|
|
8373
8418
|
maxTokens: DEFAULT_FACET_MAX_TOKENS,
|
|
8374
8419
|
systemPrompt: buildFacetSystemPrompt(facet),
|
|
8375
|
-
responseSchema:
|
|
8420
|
+
responseSchema: facetResponseSchema(facet.key),
|
|
8376
8421
|
memories
|
|
8377
8422
|
});
|
|
8378
8423
|
const noEvidence = result.basedOn.memoryIds.length === 0;
|
|
@@ -8395,6 +8440,25 @@ async function synthesizeFacet(facet, ctx, options, prior) {
|
|
|
8395
8440
|
const redacted = await options.redactor.redactTextAsync(text12);
|
|
8396
8441
|
section.text = redacted.text;
|
|
8397
8442
|
}
|
|
8443
|
+
if (!legitimateEmpty && !noEvidence) {
|
|
8444
|
+
const values = extractStructuredValues(facet.key, result.structuredOutput);
|
|
8445
|
+
if (options.redactor) {
|
|
8446
|
+
if (values.occupation) {
|
|
8447
|
+
values.occupation = (await options.redactor.redactTextAsync(values.occupation)).text;
|
|
8448
|
+
}
|
|
8449
|
+
if (values.interests) {
|
|
8450
|
+
const gated = [];
|
|
8451
|
+
for (const interest of values.interests) {
|
|
8452
|
+
gated.push((await options.redactor.redactTextAsync(interest)).text);
|
|
8453
|
+
}
|
|
8454
|
+
values.interests = gated;
|
|
8455
|
+
}
|
|
8456
|
+
}
|
|
8457
|
+
const occupation = normalizeOccupation(values.occupation);
|
|
8458
|
+
if (occupation !== void 0) section.occupation = occupation;
|
|
8459
|
+
const interests = normalizeInterests(values.interests);
|
|
8460
|
+
if (interests !== void 0) section.interests = interests;
|
|
8461
|
+
}
|
|
8398
8462
|
return section;
|
|
8399
8463
|
}
|
|
8400
8464
|
function fallbackSection(facet, prior) {
|
|
@@ -8411,6 +8475,7 @@ function fallbackSection(facet, prior) {
|
|
|
8411
8475
|
};
|
|
8412
8476
|
}
|
|
8413
8477
|
function buildFacetSystemPrompt(facet) {
|
|
8478
|
+
const structuredField = FACET_STRUCTURED_RESPONSE_HINT[facet.key] ?? "";
|
|
8414
8479
|
return `You are writing the "${facet.label}" section of a person's shareable profile, using their private memories (supplied as evidence) as the only source of truth.
|
|
8415
8480
|
|
|
8416
8481
|
Task for this section:
|
|
@@ -8421,7 +8486,7 @@ Rules:
|
|
|
8421
8486
|
- If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
|
|
8422
8487
|
- Write in third person about the person, in a natural voice suitable for a public profile (no "I"/"you", no name repetition).
|
|
8423
8488
|
- Be concise and specific; no preamble, hedging, or meta-commentary.
|
|
8424
|
-
- Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false
|
|
8489
|
+
- Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false>${structuredField} }.`;
|
|
8425
8490
|
}
|
|
8426
8491
|
function extractFacetText(structured) {
|
|
8427
8492
|
if (structured && typeof structured === "object") {
|
|
@@ -8432,6 +8497,73 @@ function extractFacetText(structured) {
|
|
|
8432
8497
|
}
|
|
8433
8498
|
return { text: "", legitimateEmpty: false };
|
|
8434
8499
|
}
|
|
8500
|
+
function extractStructuredValues(key, structured) {
|
|
8501
|
+
if (!structured || typeof structured !== "object") return {};
|
|
8502
|
+
const obj = structured;
|
|
8503
|
+
if (key === "work_role") {
|
|
8504
|
+
return typeof obj.occupation === "string" ? { occupation: obj.occupation } : {};
|
|
8505
|
+
}
|
|
8506
|
+
if (key === "interests") {
|
|
8507
|
+
const list = coerceInterestList(obj.interests);
|
|
8508
|
+
if (list) return { interests: list.slice(0, MAX_RAW_INTERESTS) };
|
|
8509
|
+
}
|
|
8510
|
+
return {};
|
|
8511
|
+
}
|
|
8512
|
+
function coerceInterestList(value) {
|
|
8513
|
+
if (Array.isArray(value)) return value.filter((i) => typeof i === "string");
|
|
8514
|
+
if (typeof value !== "string") return void 0;
|
|
8515
|
+
const trimmed = value.trim();
|
|
8516
|
+
if (trimmed.startsWith("[")) {
|
|
8517
|
+
try {
|
|
8518
|
+
const parsed = JSON.parse(trimmed);
|
|
8519
|
+
if (Array.isArray(parsed)) return parsed.filter((i) => typeof i === "string");
|
|
8520
|
+
} catch {
|
|
8521
|
+
if (trimmed.endsWith("]")) return splitInterestFragments(trimmed.slice(1, -1));
|
|
8522
|
+
}
|
|
8523
|
+
}
|
|
8524
|
+
return splitInterestFragments(trimmed);
|
|
8525
|
+
}
|
|
8526
|
+
function splitInterestFragments(source) {
|
|
8527
|
+
return source.split(",").map((fragment) => {
|
|
8528
|
+
let entry = fragment.trim();
|
|
8529
|
+
if (entry.startsWith("[")) entry = entry.slice(1);
|
|
8530
|
+
if (entry.endsWith("]")) entry = entry.slice(0, -1);
|
|
8531
|
+
entry = entry.trim();
|
|
8532
|
+
const quote = entry[0];
|
|
8533
|
+
if ((quote === '"' || quote === "'") && entry.endsWith(quote)) entry = entry.slice(1, -1);
|
|
8534
|
+
return entry;
|
|
8535
|
+
});
|
|
8536
|
+
}
|
|
8537
|
+
function normalizeOccupation(value) {
|
|
8538
|
+
if (value === void 0) return void 0;
|
|
8539
|
+
const trimmed = value.trim();
|
|
8540
|
+
if (!trimmed) return void 0;
|
|
8541
|
+
const length = codePointLength(trimmed);
|
|
8542
|
+
if (length > NEARBY_MAX_OCCUPATION_CODEPOINTS) {
|
|
8543
|
+
getLogger().warn(
|
|
8544
|
+
"[memory/synthesizeProfile] occupation exceeded the publishable length; dropping it",
|
|
8545
|
+
{ length, max: NEARBY_MAX_OCCUPATION_CODEPOINTS }
|
|
8546
|
+
);
|
|
8547
|
+
return void 0;
|
|
8548
|
+
}
|
|
8549
|
+
return trimmed;
|
|
8550
|
+
}
|
|
8551
|
+
function normalizeInterests(values) {
|
|
8552
|
+
if (values === void 0) return void 0;
|
|
8553
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8554
|
+
const out = [];
|
|
8555
|
+
for (const value of values) {
|
|
8556
|
+
const trimmed = value.trim();
|
|
8557
|
+
if (!trimmed) continue;
|
|
8558
|
+
if (codePointLength(trimmed) > NEARBY_MAX_INTEREST_CODEPOINTS) continue;
|
|
8559
|
+
const key = trimmed.toLowerCase();
|
|
8560
|
+
if (seen.has(key)) continue;
|
|
8561
|
+
seen.add(key);
|
|
8562
|
+
out.push(trimmed);
|
|
8563
|
+
if (out.length === NEARBY_MAX_INTERESTS) break;
|
|
8564
|
+
}
|
|
8565
|
+
return out.length > 0 ? out : void 0;
|
|
8566
|
+
}
|
|
8435
8567
|
|
|
8436
8568
|
// src/lib/memory/topicExtract.ts
|
|
8437
8569
|
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
@@ -14103,6 +14235,7 @@ export {
|
|
|
14103
14235
|
DEFAULT_VAULT_CACHE_SIZE,
|
|
14104
14236
|
DatabaseManager,
|
|
14105
14237
|
ENTITY_FANOUT,
|
|
14238
|
+
EncryptionKeyMissingError,
|
|
14106
14239
|
HARD_DELETE_WINDOW_MS,
|
|
14107
14240
|
INFERENCE_ID_HEADER,
|
|
14108
14241
|
LoggerProvider,
|
|
@@ -14229,6 +14362,7 @@ export {
|
|
|
14229
14362
|
rankProfileCandidates,
|
|
14230
14363
|
recall,
|
|
14231
14364
|
reflect,
|
|
14365
|
+
refreshEncryptionKeyIfMatches,
|
|
14232
14366
|
refreshNotionAccessToken,
|
|
14233
14367
|
registerNotionClient,
|
|
14234
14368
|
relinkMemoryTopicsOp,
|
|
@@ -14243,6 +14377,7 @@ export {
|
|
|
14243
14377
|
sdkModelClasses,
|
|
14244
14378
|
sdkSchema,
|
|
14245
14379
|
searchVaultMemories,
|
|
14380
|
+
seedEncryptionKeys,
|
|
14246
14381
|
setLogger,
|
|
14247
14382
|
setMemoryVisibilityOp,
|
|
14248
14383
|
shouldChunkMessage,
|
package/dist/index.cjs
CHANGED
|
@@ -2830,6 +2830,16 @@ function buildSystemPrompt(ctx, options) {
|
|
|
2830
2830
|
}
|
|
2831
2831
|
|
|
2832
2832
|
// src/react/useEncryption.ts
|
|
2833
|
+
var EncryptionKeyMissingError = class extends Error {
|
|
2834
|
+
constructor(address, version) {
|
|
2835
|
+
super(
|
|
2836
|
+
`Encryption key (${version}) not found for ${address}. Please sign a message to generate your encryption key.`
|
|
2837
|
+
);
|
|
2838
|
+
this.name = "EncryptionKeyMissingError";
|
|
2839
|
+
this.address = address;
|
|
2840
|
+
this.version = version;
|
|
2841
|
+
}
|
|
2842
|
+
};
|
|
2833
2843
|
var encryptionKeyStore = /* @__PURE__ */ new Map();
|
|
2834
2844
|
var cryptoKeyCache = /* @__PURE__ */ new Map();
|
|
2835
2845
|
var clearAllEncryptionStateCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -2839,14 +2849,11 @@ function onClearAllEncryptionState(callback) {
|
|
|
2839
2849
|
clearAllEncryptionStateCallbacks.delete(callback);
|
|
2840
2850
|
};
|
|
2841
2851
|
}
|
|
2842
|
-
function getStoredKey(address) {
|
|
2843
|
-
const keys = encryptionKeyStore.get(address);
|
|
2844
|
-
return keys?.current ?? null;
|
|
2845
|
-
}
|
|
2846
2852
|
function getStoredKeyByVersion(address, version) {
|
|
2847
2853
|
const keys = encryptionKeyStore.get(address);
|
|
2848
2854
|
if (!keys) return null;
|
|
2849
|
-
|
|
2855
|
+
const value = version === "v2" ? keys.legacy : keys.current;
|
|
2856
|
+
return value ?? null;
|
|
2850
2857
|
}
|
|
2851
2858
|
function hexToBytes(hex) {
|
|
2852
2859
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
@@ -2866,9 +2873,7 @@ async function getEncryptionKey(address, version = "v3") {
|
|
|
2866
2873
|
}
|
|
2867
2874
|
const keyHex = getStoredKeyByVersion(address, version);
|
|
2868
2875
|
if (!keyHex) {
|
|
2869
|
-
throw new
|
|
2870
|
-
"Encryption key not found. Please sign a message to generate your encryption key."
|
|
2871
|
-
);
|
|
2876
|
+
throw new EncryptionKeyMissingError(address, version);
|
|
2872
2877
|
}
|
|
2873
2878
|
const keyBytes = hexToBytes(keyHex);
|
|
2874
2879
|
const cryptoKey = await crypto.subtle.importKey(
|
|
@@ -2885,8 +2890,8 @@ async function decryptData(encryptedHex, address, version = "v3") {
|
|
|
2885
2890
|
const key = await getEncryptionKey(address, version);
|
|
2886
2891
|
return decryptDataWithKey(encryptedHex, key);
|
|
2887
2892
|
}
|
|
2888
|
-
function hasEncryptionKey(address) {
|
|
2889
|
-
return
|
|
2893
|
+
function hasEncryptionKey(address, version) {
|
|
2894
|
+
return getStoredKeyByVersion(address, version ?? "v3") !== null;
|
|
2890
2895
|
}
|
|
2891
2896
|
async function decryptDataWithKey(encryptedHex, key) {
|
|
2892
2897
|
const combined = hexToBytes(encryptedHex);
|
|
@@ -2919,20 +2924,29 @@ function detectEncryptionVersion(value) {
|
|
|
2919
2924
|
}
|
|
2920
2925
|
return null;
|
|
2921
2926
|
}
|
|
2922
|
-
async function
|
|
2923
|
-
if (!value) return value;
|
|
2927
|
+
async function decryptFieldDetailed(value, address) {
|
|
2928
|
+
if (!value) return { status: "plaintext", value };
|
|
2924
2929
|
const detected = detectEncryptionVersion(value);
|
|
2925
|
-
if (!detected) return value;
|
|
2930
|
+
if (!detected) return { status: "plaintext", value };
|
|
2926
2931
|
if (detected.encryptedData.length < 56 || !/^[0-9a-f]+$/i.test(detected.encryptedData)) {
|
|
2927
|
-
return value;
|
|
2932
|
+
return { status: "invalid_payload", value, version: detected.version };
|
|
2928
2933
|
}
|
|
2929
2934
|
try {
|
|
2930
|
-
|
|
2935
|
+
const plaintext = await decryptData(detected.encryptedData, address, detected.version);
|
|
2936
|
+
return { status: "ok", value: plaintext, version: detected.version };
|
|
2931
2937
|
} catch (error) {
|
|
2932
|
-
|
|
2933
|
-
|
|
2938
|
+
if (error instanceof EncryptionKeyMissingError) {
|
|
2939
|
+
getLogger().warn("Failed to decrypt field (key missing for version):", error.message);
|
|
2940
|
+
return { status: "key_missing", value, version: detected.version };
|
|
2941
|
+
}
|
|
2942
|
+
getLogger().warn("Failed to decrypt field (auth mismatch or crypto error):", error);
|
|
2943
|
+
return { status: "auth_mismatch", value, version: detected.version };
|
|
2934
2944
|
}
|
|
2935
2945
|
}
|
|
2946
|
+
async function decryptField(value, address) {
|
|
2947
|
+
const result = await decryptFieldDetailed(value, address);
|
|
2948
|
+
return result.value;
|
|
2949
|
+
}
|
|
2936
2950
|
|
|
2937
2951
|
// src/lib/chat/useChat/strategies/types.ts
|
|
2938
2952
|
function isChatCompletionResponse(r) {
|
package/dist/index.mjs
CHANGED
|
@@ -2634,6 +2634,16 @@ function buildSystemPrompt(ctx, options) {
|
|
|
2634
2634
|
}
|
|
2635
2635
|
|
|
2636
2636
|
// src/react/useEncryption.ts
|
|
2637
|
+
var EncryptionKeyMissingError = class extends Error {
|
|
2638
|
+
constructor(address, version) {
|
|
2639
|
+
super(
|
|
2640
|
+
`Encryption key (${version}) not found for ${address}. Please sign a message to generate your encryption key.`
|
|
2641
|
+
);
|
|
2642
|
+
this.name = "EncryptionKeyMissingError";
|
|
2643
|
+
this.address = address;
|
|
2644
|
+
this.version = version;
|
|
2645
|
+
}
|
|
2646
|
+
};
|
|
2637
2647
|
var encryptionKeyStore = /* @__PURE__ */ new Map();
|
|
2638
2648
|
var cryptoKeyCache = /* @__PURE__ */ new Map();
|
|
2639
2649
|
var clearAllEncryptionStateCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -2643,14 +2653,11 @@ function onClearAllEncryptionState(callback) {
|
|
|
2643
2653
|
clearAllEncryptionStateCallbacks.delete(callback);
|
|
2644
2654
|
};
|
|
2645
2655
|
}
|
|
2646
|
-
function getStoredKey(address) {
|
|
2647
|
-
const keys = encryptionKeyStore.get(address);
|
|
2648
|
-
return keys?.current ?? null;
|
|
2649
|
-
}
|
|
2650
2656
|
function getStoredKeyByVersion(address, version) {
|
|
2651
2657
|
const keys = encryptionKeyStore.get(address);
|
|
2652
2658
|
if (!keys) return null;
|
|
2653
|
-
|
|
2659
|
+
const value = version === "v2" ? keys.legacy : keys.current;
|
|
2660
|
+
return value ?? null;
|
|
2654
2661
|
}
|
|
2655
2662
|
function hexToBytes(hex) {
|
|
2656
2663
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
@@ -2670,9 +2677,7 @@ async function getEncryptionKey(address, version = "v3") {
|
|
|
2670
2677
|
}
|
|
2671
2678
|
const keyHex = getStoredKeyByVersion(address, version);
|
|
2672
2679
|
if (!keyHex) {
|
|
2673
|
-
throw new
|
|
2674
|
-
"Encryption key not found. Please sign a message to generate your encryption key."
|
|
2675
|
-
);
|
|
2680
|
+
throw new EncryptionKeyMissingError(address, version);
|
|
2676
2681
|
}
|
|
2677
2682
|
const keyBytes = hexToBytes(keyHex);
|
|
2678
2683
|
const cryptoKey = await crypto.subtle.importKey(
|
|
@@ -2689,8 +2694,8 @@ async function decryptData(encryptedHex, address, version = "v3") {
|
|
|
2689
2694
|
const key = await getEncryptionKey(address, version);
|
|
2690
2695
|
return decryptDataWithKey(encryptedHex, key);
|
|
2691
2696
|
}
|
|
2692
|
-
function hasEncryptionKey(address) {
|
|
2693
|
-
return
|
|
2697
|
+
function hasEncryptionKey(address, version) {
|
|
2698
|
+
return getStoredKeyByVersion(address, version ?? "v3") !== null;
|
|
2694
2699
|
}
|
|
2695
2700
|
async function decryptDataWithKey(encryptedHex, key) {
|
|
2696
2701
|
const combined = hexToBytes(encryptedHex);
|
|
@@ -2723,20 +2728,29 @@ function detectEncryptionVersion(value) {
|
|
|
2723
2728
|
}
|
|
2724
2729
|
return null;
|
|
2725
2730
|
}
|
|
2726
|
-
async function
|
|
2727
|
-
if (!value) return value;
|
|
2731
|
+
async function decryptFieldDetailed(value, address) {
|
|
2732
|
+
if (!value) return { status: "plaintext", value };
|
|
2728
2733
|
const detected = detectEncryptionVersion(value);
|
|
2729
|
-
if (!detected) return value;
|
|
2734
|
+
if (!detected) return { status: "plaintext", value };
|
|
2730
2735
|
if (detected.encryptedData.length < 56 || !/^[0-9a-f]+$/i.test(detected.encryptedData)) {
|
|
2731
|
-
return value;
|
|
2736
|
+
return { status: "invalid_payload", value, version: detected.version };
|
|
2732
2737
|
}
|
|
2733
2738
|
try {
|
|
2734
|
-
|
|
2739
|
+
const plaintext = await decryptData(detected.encryptedData, address, detected.version);
|
|
2740
|
+
return { status: "ok", value: plaintext, version: detected.version };
|
|
2735
2741
|
} catch (error) {
|
|
2736
|
-
|
|
2737
|
-
|
|
2742
|
+
if (error instanceof EncryptionKeyMissingError) {
|
|
2743
|
+
getLogger().warn("Failed to decrypt field (key missing for version):", error.message);
|
|
2744
|
+
return { status: "key_missing", value, version: detected.version };
|
|
2745
|
+
}
|
|
2746
|
+
getLogger().warn("Failed to decrypt field (auth mismatch or crypto error):", error);
|
|
2747
|
+
return { status: "auth_mismatch", value, version: detected.version };
|
|
2738
2748
|
}
|
|
2739
2749
|
}
|
|
2750
|
+
async function decryptField(value, address) {
|
|
2751
|
+
const result = await decryptFieldDetailed(value, address);
|
|
2752
|
+
return result.value;
|
|
2753
|
+
}
|
|
2740
2754
|
|
|
2741
2755
|
// src/lib/chat/useChat/strategies/types.ts
|
|
2742
2756
|
function isChatCompletionResponse(r) {
|