@kya-os/mcp-i-core 1.3.23 → 1.3.25

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.
@@ -18,29 +18,41 @@ exports.base64ToBytes = base64ToBytes;
18
18
  function base64urlDecodeToString(input) {
19
19
  const padded = addPadding(input);
20
20
  const base64 = padded.replace(/-/g, "+").replace(/_/g, "/");
21
+ // Prefer Buffer when available (Node.js) as it handles UTF-8 correctly
22
+ if (typeof Buffer !== "undefined") {
23
+ // Buffer.from doesn't throw for invalid base64, so we validate first
24
+ const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
25
+ if (!base64Regex.test(base64)) {
26
+ throw new Error("Invalid base64url string: contains invalid characters");
27
+ }
28
+ try {
29
+ const decoded = Buffer.from(base64, "base64").toString("utf-8");
30
+ return decoded;
31
+ }
32
+ catch (error) {
33
+ throw new Error(`Invalid base64url string: ${error instanceof Error ? error.message : String(error)}`);
34
+ }
35
+ }
21
36
  // For platforms that don't have Buffer (e.g., Cloudflare Workers)
22
37
  if (typeof atob !== "undefined") {
23
38
  try {
24
- return atob(base64);
39
+ const binaryString = atob(base64);
40
+ // Decode UTF-8 bytes to string
41
+ if (typeof TextDecoder !== "undefined") {
42
+ const bytes = new Uint8Array(binaryString.length);
43
+ for (let i = 0; i < binaryString.length; i++) {
44
+ bytes[i] = binaryString.charCodeAt(i);
45
+ }
46
+ return new TextDecoder().decode(bytes);
47
+ }
48
+ // Fallback: return binary string as-is (may not handle UTF-8 correctly)
49
+ return binaryString;
25
50
  }
26
51
  catch (error) {
27
52
  throw new Error(`Invalid base64url string: ${error instanceof Error ? error.message : String(error)}`);
28
53
  }
29
54
  }
30
- // For Node.js environments - Buffer.from doesn't throw for invalid base64
31
- // We need to validate by checking if the input contains only valid base64 characters
32
- // Base64 characters: A-Z, a-z, 0-9, +, /, = (padding)
33
- const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
34
- if (!base64Regex.test(base64)) {
35
- throw new Error("Invalid base64url string: contains invalid characters");
36
- }
37
- try {
38
- const decoded = Buffer.from(base64, "base64").toString("utf-8");
39
- return decoded;
40
- }
41
- catch (error) {
42
- throw new Error(`Invalid base64url string: ${error instanceof Error ? error.message : String(error)}`);
43
- }
55
+ throw new Error("Neither Buffer nor atob is available");
44
56
  }
45
57
  /**
46
58
  * Decode base64url string to Uint8Array
@@ -70,14 +82,29 @@ function base64urlDecodeToBytes(input) {
70
82
  * Encode string to base64url
71
83
  */
72
84
  function base64urlEncodeFromString(input) {
73
- // For platforms that don't have Buffer
74
- if (typeof btoa !== "undefined") {
75
- const base64 = btoa(input);
85
+ // Prefer Buffer when available (Node.js) as it handles Unicode correctly
86
+ if (typeof Buffer !== "undefined") {
87
+ const base64 = Buffer.from(input, "utf-8").toString("base64");
76
88
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
77
89
  }
78
- // For Node.js environments
79
- const base64 = Buffer.from(input, "utf-8").toString("base64");
80
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
90
+ // For platforms that don't have Buffer (e.g., Cloudflare Workers)
91
+ if (typeof btoa !== "undefined") {
92
+ // btoa doesn't handle Unicode, so we need to encode to UTF-8 bytes first
93
+ try {
94
+ const utf8Bytes = new TextEncoder().encode(input);
95
+ const binaryString = Array.from(utf8Bytes)
96
+ .map((byte) => String.fromCharCode(byte))
97
+ .join("");
98
+ const base64 = btoa(binaryString);
99
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
100
+ }
101
+ catch {
102
+ // Fallback: if TextEncoder not available, try direct btoa (may fail for Unicode)
103
+ const base64 = btoa(input);
104
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
105
+ }
106
+ }
107
+ throw new Error("Neither Buffer nor btoa is available");
81
108
  }
82
109
  /**
83
110
  * Encode Uint8Array to base64url
@@ -94,9 +94,9 @@ async function migrateDelegationKeys(storage, options = {}) {
94
94
  };
95
95
  try {
96
96
  // Find all legacy delegation keys
97
- const legacyKeys = await storage.list('agent:');
97
+ const legacyKeys = await storage.list("agent:");
98
98
  const delegationKeys = legacyKeys.filter((key) => key.match(/^agent:[^:]+:delegation$/));
99
- console.log(`Found ${delegationKeys.length} legacy delegation keys to migrate`);
99
+ console.error(`Found ${delegationKeys.length} legacy delegation keys to migrate`);
100
100
  for (const oldKey of delegationKeys) {
101
101
  try {
102
102
  // Extract agentDid from key: `agent:${agentDid}:delegation`
@@ -104,7 +104,7 @@ async function migrateDelegationKeys(storage, options = {}) {
104
104
  if (!match) {
105
105
  result.errors.push({
106
106
  key: oldKey,
107
- error: 'Invalid legacy key format',
107
+ error: "Invalid legacy key format",
108
108
  });
109
109
  result.failed++;
110
110
  continue;
@@ -120,7 +120,7 @@ async function migrateDelegationKeys(storage, options = {}) {
120
120
  let userDid = null;
121
121
  let sessionId = undefined;
122
122
  // First, attempt to extract from session data to get both userDid and sessionId
123
- const sessionKeys = await storage.list('session:');
123
+ const sessionKeys = await storage.list("session:");
124
124
  for (const sessionKey of sessionKeys) {
125
125
  const sessionData = await storage.get(sessionKey);
126
126
  if (sessionData) {
@@ -153,7 +153,7 @@ async function migrateDelegationKeys(storage, options = {}) {
153
153
  // Cannot migrate without userDid - skip for now
154
154
  result.errors.push({
155
155
  key: oldKey,
156
- error: 'Cannot resolve userDid - skipping migration',
156
+ error: "Cannot resolve userDid - skipping migration",
157
157
  });
158
158
  result.failed++;
159
159
  continue;
@@ -187,7 +187,7 @@ async function migrateDelegationKeys(storage, options = {}) {
187
187
  }
188
188
  catch (error) {
189
189
  result.errors.push({
190
- key: 'migration',
190
+ key: "migration",
191
191
  error: error instanceof Error ? error.message : String(error),
192
192
  });
193
193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kya-os/mcp-i-core",
3
- "version": "1.3.23",
3
+ "version": "1.3.25",
4
4
  "description": "Core runtime and types for MCP-I framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "prepublishOnly": "npm run build && node ../create-mcpi-app/scripts/validate-no-workspace.js"
29
29
  },
30
30
  "dependencies": {
31
- "@kya-os/contracts": "^1.6.16",
31
+ "@kya-os/contracts": "^1.6.18",
32
32
  "jose": "^5.6.3",
33
33
  "json-canonicalize": "^2.0.0",
34
34
  "zod": "^3.25.76"