@kya-os/mcp-i-core 1.3.24 → 1.3.26

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
@@ -110,12 +137,19 @@ function bytesToBase64(bytes) {
110
137
  return Buffer.from(bytes).toString("base64");
111
138
  }
112
139
  /**
113
- * Convert standard base64 to bytes
140
+ * Convert standard base64 or base64url to bytes
141
+ * Handles both standard base64 (+/) and base64url (-_) formats
114
142
  */
115
143
  function base64ToBytes(base64) {
144
+ // Convert base64url to standard base64 if needed
145
+ // Base64url uses - instead of + and _ instead of /
146
+ let standardBase64 = base64.replace(/-/g, "+").replace(/_/g, "/");
147
+ // Add padding if needed (base64url often omits padding)
148
+ const paddingNeeded = (4 - (standardBase64.length % 4)) % 4;
149
+ standardBase64 += "=".repeat(paddingNeeded);
116
150
  // For platforms that don't have Buffer
117
151
  if (typeof atob !== "undefined") {
118
- const binaryString = atob(base64);
152
+ const binaryString = atob(standardBase64);
119
153
  const bytes = new Uint8Array(binaryString.length);
120
154
  for (let i = 0; i < binaryString.length; i++) {
121
155
  bytes[i] = binaryString.charCodeAt(i);
@@ -123,7 +157,7 @@ function base64ToBytes(base64) {
123
157
  return bytes;
124
158
  }
125
159
  // For Node.js environments
126
- return new Uint8Array(Buffer.from(base64, "base64"));
160
+ return new Uint8Array(Buffer.from(standardBase64, "base64"));
127
161
  }
128
162
  /**
129
163
  * Add padding to base64url string if needed
@@ -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.24",
3
+ "version": "1.3.26",
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.17",
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"