diff --git a/webview_rpc_runtime_library/CHANGELOG.md b/webview_rpc_runtime_library/CHANGELOG.md index 93fa131..ee4c17a 100644 --- a/webview_rpc_runtime_library/CHANGELOG.md +++ b/webview_rpc_runtime_library/CHANGELOG.md @@ -5,7 +5,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.0.1] - 2025-06-23 +## [1.0.4] - 2025-06-24 + +### Fixed +- Fixed null handling issue in RPC envelope encoding + - WebViewRpcClient and WebViewRpcServer were explicitly setting `error` field to `null` + - This caused `Cannot read properties of null (reading 'length')` error + - Now follows Proto3 spec: optional fields are omitted instead of set to null + - Proto3 string fields default to empty string automatically when not set + +## [1.0.3] - 2025-06-23 + +### Fixed +- Fixed npm package build issue where wrong function names were in the published package + - The source code used `base64ToUint8Array` and `uint8ArrayToBase64` + - But the published npm package incorrectly had `base64ToBytes` and `base64FromBytes` + - This caused import errors when using the package + +## [1.0.2] - 2025-06-23 ### Changed - **BREAKING**: Complete redesign for async-only architecture diff --git a/webview_rpc_runtime_library/package-lock.json b/webview_rpc_runtime_library/package-lock.json index c6ccfdc..f02b780 100644 --- a/webview_rpc_runtime_library/package-lock.json +++ b/webview_rpc_runtime_library/package-lock.json @@ -1,12 +1,12 @@ { "name": "app-webview-rpc", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "app-webview-rpc", - "version": "1.0.0", + "version": "1.0.1", "license": "MIT", "devDependencies": { "rimraf": "^5.0.0", diff --git a/webview_rpc_runtime_library/package.json b/webview_rpc_runtime_library/package.json index 0984496..7ec701f 100644 --- a/webview_rpc_runtime_library/package.json +++ b/webview_rpc_runtime_library/package.json @@ -1,6 +1,6 @@ { "name": "app-webview-rpc", - "version": "1.0.1", + "version": "1.0.4", "type": "module", "description": "WebView RPC provides an abstraction layer that allows communication between the App (e.g. Unity C#) and WebView (HTML, JS) using protobuf, similar to gRPC.", "main": "./dist/cjs/index.js", diff --git a/webview_rpc_runtime_library/src/core/webview_rpc_client.js b/webview_rpc_runtime_library/src/core/webview_rpc_client.js index b4102c6..19d97bf 100644 --- a/webview_rpc_runtime_library/src/core/webview_rpc_client.js +++ b/webview_rpc_runtime_library/src/core/webview_rpc_client.js @@ -35,8 +35,7 @@ export class WebViewRpcClient { requestId, isRequest: true, method, - payload: requestPayload, - error: null + payload: requestPayload }; // Create promise for this request diff --git a/webview_rpc_runtime_library/src/core/webview_rpc_server.js b/webview_rpc_runtime_library/src/core/webview_rpc_server.js index cb3c2cd..bf42a92 100644 --- a/webview_rpc_runtime_library/src/core/webview_rpc_server.js +++ b/webview_rpc_runtime_library/src/core/webview_rpc_server.js @@ -62,9 +62,8 @@ export class WebViewRpcServer { const responseEnvelope = { requestId: requestEnvelope.requestId, isRequest: false, - method: requestEnvelope.method, - payload: null, - error: null + method: requestEnvelope.method + // payload and error fields will be set only when needed }; try { diff --git a/webview_rpc_runtime_library/src/core/webview_rpc_utils.js b/webview_rpc_runtime_library/src/core/webview_rpc_utils.js index b6bab5e..083148a 100644 --- a/webview_rpc_runtime_library/src/core/webview_rpc_utils.js +++ b/webview_rpc_runtime_library/src/core/webview_rpc_utils.js @@ -7,40 +7,61 @@ export function encodeEnvelopeToBase64(envObj) { const rawBytes = encodeRpcEnvelope(envObj); // rawBytes is Uint8Array - return base64FromBytes(rawBytes); + return uint8ArrayToBase64(rawBytes); } export function decodeEnvelopeFromBase64(base64Str) { - const bytes = base64ToBytes(base64Str); + const bytes = base64ToUint8Array(base64Str); // decodeRpcEnvelope(bytes) -> plain object { requestId, isRequest, ...} const messageObj = decodeRpcEnvelope(bytes); return messageObj; } -/** Uint8Array -> Base64 (browser JS) */ -let isNode = typeof window === 'undefined'; +/** + * Base64 <-> Uint8Array conversion utilities + * (Browser and Node.js compatible) + */ -export function base64FromBytes(u8arr) { - if (isNode) { - return Buffer.from(u8arr).toString('base64'); - } else { - let binary = ""; - for (let i = 0; i < u8arr.length; i++) { - binary += String.fromCharCode(u8arr[i]); +/** + * Converts a Uint8Array to a Base64 string. + * @param {Uint8Array} bytes - The byte array to convert. + * @returns {string} The Base64 encoded string. + */ +export function uint8ArrayToBase64(bytes) { + if (typeof window !== 'undefined' && typeof window.btoa === 'function') { + // Browser environment + let binary = ''; + for (let i = 0; i < bytes.length; i++) { + binary += String.fromCharCode(bytes[i]); } - return btoa(binary); + return window.btoa(binary); + } else if (typeof Buffer === 'function') { + // Node.js environment + return Buffer.from(bytes).toString('base64'); + } else { + throw new Error('Unsupported environment for Base64 encoding'); } } -export function base64ToBytes(b64) { - if (isNode) { - return Buffer.from(b64, 'base64'); - } else { - const bin = atob(b64); - const u8 = new Uint8Array(bin.length); - for (let i = 0; i < bin.length; i++) { - u8[i] = bin.charCodeAt(i); +/** + * Converts a Base64 string to a Uint8Array. + * @param {string} base64 - The Base64 string to convert. + * @returns {Uint8Array} The decoded byte array. + */ +export function base64ToUint8Array(base64) { + if (typeof window !== 'undefined' && typeof window.atob === 'function') { + // Browser environment + const binary_string = window.atob(base64); + const len = binary_string.length; + const bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); } - return u8; + return bytes; + } else if (typeof Buffer === 'function') { + // Node.js environment + return new Uint8Array(Buffer.from(base64, 'base64')); + } else { + throw new Error('Unsupported environment for Base64 decoding'); } }