ext.mjs raw
1 // ext.mjs — Platform-adaptive extension/signer bridge.
2 // Detects whether it is running in a browser extension background page
3 // or in a regular page context and uses the appropriate APIs.
4 //
5 // Extension: browser.storage.local, browser.runtime.onMessage
6 // In-page: localStorage (prefixed), direct handler dispatch
7
8 var _isExt = typeof browser !== 'undefined'
9 && !!browser.runtime && !!browser.runtime.onMessage;
10
11 var _prefix = 'smesh-signer:';
12 var _handler = null;
13 var _readyResolve = null;
14 var _ready = new Promise(function(r) { _readyResolve = r; });
15
16 function _signalReady() {
17 if (_readyResolve) { _readyResolve(); _readyResolve = null; }
18 }
19
20 // --- Storage ---
21
22 export function StorageGet(key, fn) {
23 if (_isExt) {
24 browser.storage.local.get(key).then(function(result) {
25 fn(result[key] || '');
26 }).catch(function() { fn(''); });
27 } else {
28 fn(localStorage.getItem(_prefix + key) || '');
29 }
30 }
31
32 export function StorageSet(key, value) {
33 if (_isExt) {
34 browser.storage.local.set({ [key]: value });
35 } else {
36 localStorage.setItem(_prefix + key, value);
37 }
38 }
39
40 export function StorageRemove(key) {
41 if (_isExt) {
42 browser.storage.local.remove(key);
43 } else {
44 localStorage.removeItem(_prefix + key);
45 }
46 }
47
48 // --- Message handling ---
49
50 // OnMessage registers a handler for incoming requests.
51 // fn receives (method, paramsJSON, senderTabID, respond).
52 export function OnMessage(fn) {
53 if (_isExt) {
54 browser.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
55 var method = msg.method || '';
56 var params = msg.params ? JSON.stringify(msg.params) : '{}';
57 var tabID = (sender.tab && sender.tab.id) || 0;
58 function respond(result) {
59 try {
60 var parsed = JSON.parse(result);
61 if (parsed.error) {
62 sendResponse({ error: parsed.error });
63 } else {
64 sendResponse(parsed.result !== undefined ? parsed.result : parsed);
65 }
66 } catch (e) {
67 sendResponse(result);
68 }
69 }
70 try {
71 fn(method, params, tabID, respond);
72 } catch (e) {
73 console.error('smesh handler error:', e);
74 sendResponse({ error: e.message || 'handler error' });
75 }
76 return true;
77 });
78 } else {
79 _handler = fn;
80 _signalReady();
81 }
82 }
83
84 // dispatch calls the registered handler directly (in-page path).
85 // In extension context this is unused — messages arrive via browser.runtime.
86 export function dispatch(method, params) {
87 return _ready.then(function() {
88 return new Promise(function(resolve) {
89 if (!_handler) { resolve(null); return; }
90 var paramsJSON = JSON.stringify(params || {});
91 _handler(method, paramsJSON, 0, function(result) {
92 try {
93 var parsed = JSON.parse('' + result);
94 if (parsed.error) {
95 resolve({ error: parsed.error });
96 } else {
97 resolve(parsed.result !== undefined ? parsed.result : parsed);
98 }
99 } catch (e) {
100 resolve('' + result);
101 }
102 });
103 });
104 });
105 }
106
107 // --- Tab messaging (extension only, no-op in-page) ---
108
109 export function SendMessageToTab(tabID, msg) {
110 if (!_isExt) return;
111 try {
112 browser.tabs.sendMessage(tabID, JSON.parse(msg));
113 } catch (e) {
114 browser.tabs.sendMessage(tabID, { data: msg });
115 }
116 }
117
118 export function ConsoleLog(msg) {
119 console.log('[smesh]', '' + msg);
120 if (!_isExt) return;
121 try {
122 browser.tabs.query({ active: true, currentWindow: true }).then(function(tabs) {
123 if (tabs.length > 0) {
124 browser.tabs.sendMessage(tabs[0].id, { type: 'LOG', text: msg }).catch(function() {});
125 }
126 }).catch(function() {});
127 } catch(e) {}
128 }
129
130 export function GetActiveTab(fn) {
131 if (_isExt) {
132 browser.tabs.query({ active: true, currentWindow: true }).then(function(tabs) {
133 if (tabs.length > 0) {
134 fn(tabs[0].id, tabs[0].url || '');
135 } else {
136 fn(0, '');
137 }
138 }).catch(function() { fn(0, ''); });
139 } else {
140 fn(0, '');
141 }
142 }
143
144 export function SessionGet(key, fn) {
145 try {
146 fn(sessionStorage.getItem(_prefix + key) || '');
147 } catch(e) {
148 fn('');
149 }
150 }
151
152 export function SessionSet(key, value) {
153 try {
154 sessionStorage.setItem(_prefix + key, '' + value);
155 } catch(e) {}
156 }
157
158 export function IsInPage() {
159 return !_isExt;
160 }
161