6#include <emscripten/val.h>
8#include "absl/strings/str_cat.h"
9#include "absl/strings/str_format.h"
18EM_JS(
void, js_session_storage_set, (
const char* key,
const char* value), {
20 if (typeof(Storage) !=
"undefined" && sessionStorage) {
21 sessionStorage.setItem(UTF8ToString(key), UTF8ToString(value));
24 console.error(
'Failed to set sessionStorage:', e);
28EM_JS(
char*, js_session_storage_get, (
const char* key), {
30 if (typeof(Storage) !=
"undefined" && sessionStorage) {
31 const value = sessionStorage.getItem(UTF8ToString(key));
34 const len = lengthBytesUTF8(value) + 1;
35 const ptr = _malloc(len);
36 stringToUTF8(value, ptr, len);
40 console.error(
'Failed to get from sessionStorage:', e);
45EM_JS(
void, js_session_storage_remove, (
const char* key), {
47 if (typeof(Storage) !=
"undefined" && sessionStorage) {
48 sessionStorage.removeItem(UTF8ToString(key));
51 console.error(
'Failed to remove from sessionStorage:', e);
55EM_JS(
int, js_session_storage_has, (
const char* key), {
57 if (typeof(Storage) !=
"undefined" && sessionStorage) {
58 return sessionStorage.getItem(UTF8ToString(key)) != null ? 1 : 0;
61 console.error(
'Failed to check sessionStorage:', e);
67EM_JS(
void, js_local_storage_set, (
const char* key,
const char* value), {
69 if (typeof(Storage) !=
"undefined" && localStorage) {
70 localStorage.setItem(UTF8ToString(key), UTF8ToString(value));
73 console.error(
'Failed to set localStorage:', e);
77EM_JS(
char*, js_local_storage_get, (
const char* key), {
79 if (typeof(Storage) !=
"undefined" && localStorage) {
80 const value = localStorage.getItem(UTF8ToString(key));
83 const len = lengthBytesUTF8(value) + 1;
84 const ptr = _malloc(len);
85 stringToUTF8(value, ptr, len);
89 console.error(
'Failed to get from localStorage:', e);
94EM_JS(
void, js_local_storage_remove, (
const char* key), {
96 if (typeof(Storage) !=
"undefined" && localStorage) {
97 localStorage.removeItem(UTF8ToString(key));
100 console.error(
'Failed to remove from localStorage:', e);
104EM_JS(
int, js_local_storage_has, (
const char* key), {
106 if (typeof(Storage) !=
"undefined" && localStorage) {
107 return localStorage.getItem(UTF8ToString(key)) != null ? 1 : 0;
110 console.error(
'Failed to check localStorage:', e);
116EM_JS(
char*, js_session_storage_keys, (), {
118 if (typeof(Storage) !=
"undefined" && sessionStorage) {
120 for (let i = 0; i < sessionStorage.length; i++) {
121 keys.push(sessionStorage.key(i));
123 const keysStr = keys.join(
'|');
124 const len = lengthBytesUTF8(keysStr) + 1;
125 const ptr = _malloc(len);
126 stringToUTF8(keysStr, ptr, len);
130 console.error(
'Failed to get sessionStorage keys:', e);
135EM_JS(
char*, js_local_storage_keys, (), {
137 if (typeof(Storage) !=
"undefined" && localStorage) {
139 for (let i = 0; i < localStorage.length; i++) {
140 keys.push(localStorage.key(i));
142 const keysStr = keys.join(
'|');
143 const len = lengthBytesUTF8(keysStr) + 1;
144 const ptr = _malloc(len);
145 stringToUTF8(keysStr, ptr, len);
149 console.error(
'Failed to get localStorage keys:', e);
155EM_JS(
void, js_session_storage_clear_prefix, (
const char* prefix), {
157 if (typeof(Storage) !=
"undefined" && sessionStorage) {
158 const prefixStr = UTF8ToString(prefix);
159 const keysToRemove = [];
160 for (let i = 0; i < sessionStorage.length; i++) {
161 const key = sessionStorage.key(i);
162 if (key &&
key.startsWith(prefixStr)) {
163 keysToRemove.push(key);
166 keysToRemove.forEach(function(key) { sessionStorage.removeItem(key); });
169 console.error(
'Failed to clear sessionStorage prefix:', e);
173EM_JS(
void, js_local_storage_clear_prefix, (
const char* prefix), {
175 if (typeof(Storage) !=
"undefined" && localStorage) {
176 const prefixStr = UTF8ToString(prefix);
177 const keysToRemove = [];
178 for (let i = 0; i < localStorage.length; i++) {
179 const key = localStorage.key(i);
180 if (key &&
key.startsWith(prefixStr)) {
181 keysToRemove.push(key);
184 keysToRemove.forEach(function(key) { localStorage.removeItem(key); });
187 console.error(
'Failed to clear localStorage prefix:', e);
192EM_JS(
int, js_is_storage_available, (), {
194 if (typeof(Storage) !=
"undefined") {
196 const testKey =
'__yaze_storage_test__';
199 if (sessionStorage) {
200 sessionStorage.setItem(testKey,
'test');
201 sessionStorage.removeItem(testKey);
206 localStorage.setItem(testKey,
'test');
207 localStorage.removeItem(testKey);
213 console.error(
'Storage not available:', e);
219std::vector<std::string> SplitString(
const std::string& str,
char delimiter) {
220 std::vector<std::string> result;
222 size_t end = str.find(delimiter);
224 while (end != std::string::npos) {
225 result.push_back(str.substr(start, end - start));
227 end = str.find(delimiter, start);
230 if (start < str.length()) {
231 result.push_back(str.substr(start));
242 const std::string& key,
243 StorageType storage_type) {
244 if (service.empty()) {
245 return absl::InvalidArgumentError(
"Service name cannot be empty");
248 return absl::InvalidArgumentError(
"API key cannot be empty");
251 std::string storage_key = BuildApiKeyStorageKey(service);
254 js_session_storage_set(storage_key.c_str(),
key.c_str());
256 js_local_storage_set(storage_key.c_str(),
key.c_str());
259 return absl::OkStatus();
263 const std::string& service, StorageType storage_type) {
264 if (service.empty()) {
265 return absl::InvalidArgumentError(
"Service name cannot be empty");
268 std::string storage_key = BuildApiKeyStorageKey(service);
269 char* value =
nullptr;
272 value = js_session_storage_get(storage_key.c_str());
274 value = js_local_storage_get(storage_key.c_str());
277 if (value ==
nullptr) {
278 return absl::NotFoundError(
279 absl::StrFormat(
"No API key found for service: %s", service));
282 std::string result(value);
288 StorageType storage_type) {
289 if (service.empty()) {
290 return absl::InvalidArgumentError(
"Service name cannot be empty");
293 std::string storage_key = BuildApiKeyStorageKey(service);
296 js_session_storage_remove(storage_key.c_str());
298 js_local_storage_remove(storage_key.c_str());
301 return absl::OkStatus();
305 StorageType storage_type) {
306 if (service.empty()) {
310 std::string storage_key = BuildApiKeyStorageKey(service);
313 return js_session_storage_has(storage_key.c_str()) != 0;
315 return js_local_storage_has(storage_key.c_str()) != 0;
320 const std::string& value,
321 StorageType storage_type) {
323 return absl::InvalidArgumentError(
"Key cannot be empty");
326 return absl::InvalidArgumentError(
"Value cannot be empty");
329 std::string storage_key = BuildSecretStorageKey(key);
332 js_session_storage_set(storage_key.c_str(), value.c_str());
334 js_local_storage_set(storage_key.c_str(), value.c_str());
337 return absl::OkStatus();
341 const std::string& key, StorageType storage_type) {
343 return absl::InvalidArgumentError(
"Key cannot be empty");
346 std::string storage_key = BuildSecretStorageKey(key);
347 char* value =
nullptr;
350 value = js_session_storage_get(storage_key.c_str());
352 value = js_local_storage_get(storage_key.c_str());
355 if (value ==
nullptr) {
356 return absl::NotFoundError(
357 absl::StrFormat(
"No secret found for key: %s", key));
360 std::string result(value);
366 StorageType storage_type) {
368 return absl::InvalidArgumentError(
"Key cannot be empty");
371 std::string storage_key = BuildSecretStorageKey(key);
374 js_session_storage_remove(storage_key.c_str());
376 js_local_storage_remove(storage_key.c_str());
379 return absl::OkStatus();
383 StorageType storage_type) {
384 std::vector<std::string> services;
385 char* keys_str =
nullptr;
388 keys_str = js_session_storage_keys();
390 keys_str = js_local_storage_keys();
393 if (keys_str !=
nullptr) {
394 std::string keys(keys_str);
398 auto all_keys = SplitString(keys,
'|');
399 std::string api_prefix = kApiKeyPrefix;
401 for (
const auto& key : all_keys) {
402 if (
key.find(api_prefix) == 0) {
404 std::string service = ExtractServiceFromKey(key);
405 if (!service.empty()) {
406 services.push_back(service);
417 js_session_storage_clear_prefix(kApiKeyPrefix);
419 js_local_storage_clear_prefix(kApiKeyPrefix);
422 return absl::OkStatus();
426 return js_is_storage_available() != 0;
429absl::StatusOr<WasmSecureStorage::StorageQuota>
437 quota.available_bytes = 5 * 1024 * 1024;
440 quota.available_bytes = 10 * 1024 * 1024;
444 char* keys_str =
nullptr;
446 keys_str = js_session_storage_keys();
448 keys_str = js_local_storage_keys();
452 if (keys_str !=
nullptr) {
453 std::string keys(keys_str);
456 auto all_keys = SplitString(keys,
'|');
457 for (
const auto& key : all_keys) {
458 char* value =
nullptr;
460 value = js_session_storage_get(
key.c_str());
462 value = js_local_storage_get(
key.c_str());
465 if (value !=
nullptr) {
466 used += strlen(value) +
key.length();
472 quota.used_bytes = used;
478std::string WasmSecureStorage::BuildApiKeyStorageKey(
479 const std::string& service) {
480 return absl::StrCat(kApiKeyPrefix, service);
483std::string WasmSecureStorage::BuildSecretStorageKey(
const std::string& key) {
484 return absl::StrCat(kSecretPrefix, key);
487std::string WasmSecureStorage::ExtractServiceFromKey(
488 const std::string& storage_key) {
489 std::string prefix = kApiKeyPrefix;
490 if (storage_key.find(prefix) == 0) {
491 return storage_key.substr(prefix.length());
EM_JS(void, CallJsAiDriver,(const char *history_json), { if(window.yaze &&window.yaze.ai &&window.yaze.ai.processAgentRequest) { window.yaze.ai.processAgentRequest(UTF8ToString(history_json));} else { console.error("AI Driver not found in window.yaze.ai.processAgentRequest");} })