@gemigo/app-sdk 0.2.5
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.
- package/LICENSE +22 -0
- package/README.md +117 -0
- package/dist/apis/index.d.ts +10 -0
- package/dist/connection-C-IGR2wz.js +2 -0
- package/dist/connection-DwOg1Kh5.js +248 -0
- package/dist/core/api-factory.d.ts +84 -0
- package/dist/core/connection.d.ts +99 -0
- package/dist/core/event-bus.d.ts +77 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/fallback/index.d.ts +8 -0
- package/dist/fallback/network.d.ts +2 -0
- package/dist/fallback/notify.d.ts +2 -0
- package/dist/fallback/storage.d.ts +2 -0
- package/dist/gemigo-app-sdk.es.js +272 -0
- package/dist/gemigo-app-sdk.umd.js +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/types/ai.d.ts +48 -0
- package/dist/types/clipboard.d.ts +39 -0
- package/dist/types/common.d.ts +72 -0
- package/dist/types/desktop.d.ts +138 -0
- package/dist/types/dialog.d.ts +65 -0
- package/dist/types/extension.d.ts +167 -0
- package/dist/types/file.d.ts +79 -0
- package/dist/types/index.d.ts +91 -0
- package/dist/types/manifest.d.ts +87 -0
- package/dist/types/network.d.ts +37 -0
- package/dist/types/notify.d.ts +28 -0
- package/dist/types/storage.d.ts +27 -0
- package/package.json +27 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { i as tryGetHost, n as createRPCProxy, t as callHost } from "./connection-DwOg1Kh5.js";
|
|
2
|
+
function createEventBus() {
|
|
3
|
+
let e = /* @__PURE__ */ new Map();
|
|
4
|
+
return {
|
|
5
|
+
on(x, S) {
|
|
6
|
+
return e.has(x) || e.set(x, /* @__PURE__ */ new Set()), e.get(x).add(S), () => e.get(x)?.delete(S);
|
|
7
|
+
},
|
|
8
|
+
emit(x, ...S) {
|
|
9
|
+
e.get(x)?.forEach((e) => e(...S));
|
|
10
|
+
},
|
|
11
|
+
off(x) {
|
|
12
|
+
x ? e.delete(x) : e.clear();
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const sdkEventBus = createEventBus();
|
|
17
|
+
function createUnifiedAPI(S) {
|
|
18
|
+
let C = tryGetHost, T = {}, E = {};
|
|
19
|
+
if (S.rpc) {
|
|
20
|
+
let e = createRPCProxy(S.rpc.methods, {
|
|
21
|
+
mapping: S.rpc.mapping,
|
|
22
|
+
fallbacks: S.rpc.fallbacks
|
|
23
|
+
});
|
|
24
|
+
Object.assign(T, e);
|
|
25
|
+
}
|
|
26
|
+
if (S.events) if (Array.isArray(S.events)) for (let e of S.events) {
|
|
27
|
+
let x = e;
|
|
28
|
+
T[e] = (e) => (C?.(), sdkEventBus.on(x, e)), E[e] = (...e) => {
|
|
29
|
+
sdkEventBus.emit(x, ...e);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
else for (let [e, x] of Object.entries(S.events)) {
|
|
33
|
+
if (!x) continue;
|
|
34
|
+
let S = x, D = typeof S == "string" ? S : S.event, O = typeof S == "object" && "childMethod" in S && S.childMethod ? S.childMethod : e;
|
|
35
|
+
T[e] = (e) => (C?.(), sdkEventBus.on(D, e)), E[O] = (...e) => {
|
|
36
|
+
sdkEventBus.emit(D, ...e);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
api: T,
|
|
41
|
+
childMethods: E
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function createRPCAction(e, x) {
|
|
45
|
+
return async (...C) => {
|
|
46
|
+
try {
|
|
47
|
+
let w = await callHost(e, x.transform ? x.transform(...C) : C);
|
|
48
|
+
return x.onSuccess ? x.onSuccess(w) : w;
|
|
49
|
+
} catch {
|
|
50
|
+
return x.fallback(...C);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function createSDK(e) {
|
|
55
|
+
let x = e.statics ? { ...e.statics } : {}, S = {};
|
|
56
|
+
if (e.modules) for (let [C, w] of Object.entries(e.modules)) {
|
|
57
|
+
let { api: e, childMethods: E } = createUnifiedAPI(w);
|
|
58
|
+
x[C] = e, Object.assign(S, E);
|
|
59
|
+
}
|
|
60
|
+
if (e.actions) for (let [S, C] of Object.entries(e.actions)) {
|
|
61
|
+
let e = C;
|
|
62
|
+
x[S] = createRPCAction(e.method, e);
|
|
63
|
+
}
|
|
64
|
+
if (e.getters) for (let [S, C] of Object.entries(e.getters)) Object.defineProperty(x, S, {
|
|
65
|
+
get: C,
|
|
66
|
+
enumerable: !0,
|
|
67
|
+
configurable: !0
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
sdk: x,
|
|
71
|
+
childMethods: S
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function bootstrapSDK(x, S = {}) {
|
|
75
|
+
let { initConnection: C } = await import("./connection-C-IGR2wz.js");
|
|
76
|
+
C(x, S);
|
|
77
|
+
let w = await tryGetHost();
|
|
78
|
+
if (w && typeof w.getProtocolInfo == "function") try {
|
|
79
|
+
return await w.getProtocolInfo();
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
var localStoragePrefix = () => `gemigo:${typeof window > "u" ? "unknown" : window.location.origin.replace(/[:/]/g, "_")}:`;
|
|
86
|
+
const fallbackStorage = {
|
|
87
|
+
get: async (e) => {
|
|
88
|
+
if (typeof window > "u" || !window.localStorage) return null;
|
|
89
|
+
let x = window.localStorage.getItem(`${localStoragePrefix()}${e}`);
|
|
90
|
+
if (!x) return null;
|
|
91
|
+
try {
|
|
92
|
+
return JSON.parse(x);
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
set: async (e, x) => {
|
|
98
|
+
typeof window > "u" || !window.localStorage || window.localStorage.setItem(`${localStoragePrefix()}${e}`, JSON.stringify(x));
|
|
99
|
+
},
|
|
100
|
+
delete: async (e) => {
|
|
101
|
+
typeof window > "u" || !window.localStorage || window.localStorage.removeItem(`${localStoragePrefix()}${e}`);
|
|
102
|
+
},
|
|
103
|
+
clear: async () => {
|
|
104
|
+
if (typeof window > "u" || !window.localStorage) return;
|
|
105
|
+
let e = localStoragePrefix();
|
|
106
|
+
for (let x = window.localStorage.length - 1; x >= 0; --x) {
|
|
107
|
+
let S = window.localStorage.key(x);
|
|
108
|
+
S && S.startsWith(e) && window.localStorage.removeItem(S);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}, fallbackNotify = async (e) => {
|
|
112
|
+
if (typeof window > "u" || typeof Notification > "u") return {
|
|
113
|
+
success: !1,
|
|
114
|
+
reason: "not_supported"
|
|
115
|
+
};
|
|
116
|
+
if (Notification.permission !== "granted") return {
|
|
117
|
+
success: !1,
|
|
118
|
+
reason: "permission_not_granted"
|
|
119
|
+
};
|
|
120
|
+
try {
|
|
121
|
+
return new Notification(e.title, {
|
|
122
|
+
body: e.message,
|
|
123
|
+
icon: e.icon
|
|
124
|
+
}), { success: !0 };
|
|
125
|
+
} catch {
|
|
126
|
+
return {
|
|
127
|
+
success: !1,
|
|
128
|
+
reason: "failed_to_notify"
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}, fallbackNetwork = { request: async (e, x) => {
|
|
132
|
+
let { method: S = "GET", headers: C, body: w, responseType: T } = x ?? {}, E = await fetch(e, {
|
|
133
|
+
method: S,
|
|
134
|
+
headers: C,
|
|
135
|
+
body: w ? typeof w == "string" ? w : JSON.stringify(w) : void 0
|
|
136
|
+
}), D = {};
|
|
137
|
+
E.headers.forEach((e, x) => D[x] = e);
|
|
138
|
+
let O = T === "text" ? await E.text() : T === "arraybuffer" ? await E.arrayBuffer() : await E.json();
|
|
139
|
+
return {
|
|
140
|
+
status: E.status,
|
|
141
|
+
data: O,
|
|
142
|
+
headers: D
|
|
143
|
+
};
|
|
144
|
+
} };
|
|
145
|
+
var SDKError = class e extends Error {
|
|
146
|
+
constructor(x, S) {
|
|
147
|
+
super(S), this.code = x, this.name = "SDKError", Object.setPrototypeOf(this, e.prototype);
|
|
148
|
+
}
|
|
149
|
+
}, hostInfo = null, defaultCapabilities = {
|
|
150
|
+
storage: !0,
|
|
151
|
+
network: !1,
|
|
152
|
+
scheduler: !1,
|
|
153
|
+
fileWatch: !1,
|
|
154
|
+
fileWrite: !1,
|
|
155
|
+
notification: !0,
|
|
156
|
+
clipboard: !1,
|
|
157
|
+
ai: !1,
|
|
158
|
+
shell: !1,
|
|
159
|
+
extension: {
|
|
160
|
+
read: !1,
|
|
161
|
+
events: !1,
|
|
162
|
+
modify: !1,
|
|
163
|
+
capture: !1
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const updateHostInfo = (e) => {
|
|
167
|
+
hostInfo = e;
|
|
168
|
+
};
|
|
169
|
+
var throwNotSupported = (e) => {
|
|
170
|
+
throw new SDKError("NOT_SUPPORTED", `${e} is not supported in this environment.`);
|
|
171
|
+
}, stubAsync = (e) => async () => throwNotSupported(e), stubHandler = (e) => () => throwNotSupported(e), aiAPI = {
|
|
172
|
+
chat: stubAsync("ai.chat"),
|
|
173
|
+
summarize: stubAsync("ai.summarize"),
|
|
174
|
+
translate: stubAsync("ai.translate")
|
|
175
|
+
}, clipboardAPI = {
|
|
176
|
+
readText: stubAsync("clipboard.readText"),
|
|
177
|
+
writeText: stubAsync("clipboard.writeText"),
|
|
178
|
+
readImage: stubAsync("clipboard.readImage"),
|
|
179
|
+
writeImage: stubAsync("clipboard.writeImage"),
|
|
180
|
+
onChange: stubHandler("clipboard.onChange")
|
|
181
|
+
}, dialogAPI = {
|
|
182
|
+
openFile: stubAsync("dialog.openFile"),
|
|
183
|
+
openDirectory: stubAsync("dialog.openDirectory"),
|
|
184
|
+
saveFile: stubAsync("dialog.saveFile"),
|
|
185
|
+
message: stubAsync("dialog.message")
|
|
186
|
+
}, fileAPI = {
|
|
187
|
+
readText: stubAsync("file.readText"),
|
|
188
|
+
readBinary: stubAsync("file.readBinary"),
|
|
189
|
+
write: stubAsync("file.write"),
|
|
190
|
+
append: stubAsync("file.append"),
|
|
191
|
+
exists: stubAsync("file.exists"),
|
|
192
|
+
stat: stubAsync("file.stat"),
|
|
193
|
+
copy: stubAsync("file.copy"),
|
|
194
|
+
move: stubAsync("file.move"),
|
|
195
|
+
remove: stubAsync("file.remove"),
|
|
196
|
+
list: stubAsync("file.list"),
|
|
197
|
+
mkdir: stubAsync("file.mkdir"),
|
|
198
|
+
persistPermission: stubAsync("file.persistPermission")
|
|
199
|
+
}, onNotificationAction = stubHandler("onNotificationAction"), onFileDrop = stubHandler("onFileDrop");
|
|
200
|
+
const { sdk, childMethods } = createSDK({
|
|
201
|
+
getters: {
|
|
202
|
+
platform: () => hostInfo?.platform ?? "web",
|
|
203
|
+
capabilities: () => hostInfo?.capabilities ?? defaultCapabilities
|
|
204
|
+
},
|
|
205
|
+
modules: {
|
|
206
|
+
storage: { rpc: {
|
|
207
|
+
methods: [
|
|
208
|
+
"get",
|
|
209
|
+
"set",
|
|
210
|
+
"delete",
|
|
211
|
+
"clear"
|
|
212
|
+
],
|
|
213
|
+
mapping: {
|
|
214
|
+
get: "storageGet",
|
|
215
|
+
set: "storageSet",
|
|
216
|
+
delete: "storageDelete",
|
|
217
|
+
clear: "storageClear"
|
|
218
|
+
},
|
|
219
|
+
fallbacks: {
|
|
220
|
+
get: fallbackStorage.get,
|
|
221
|
+
set: fallbackStorage.set,
|
|
222
|
+
delete: fallbackStorage.delete,
|
|
223
|
+
clear: fallbackStorage.clear
|
|
224
|
+
}
|
|
225
|
+
} },
|
|
226
|
+
network: { rpc: {
|
|
227
|
+
methods: ["request"],
|
|
228
|
+
mapping: { request: "networkRequest" },
|
|
229
|
+
fallbacks: { request: fallbackNetwork.request }
|
|
230
|
+
} },
|
|
231
|
+
extension: {
|
|
232
|
+
rpc: { methods: [
|
|
233
|
+
"getPageInfo",
|
|
234
|
+
"getPageHTML",
|
|
235
|
+
"getPageText",
|
|
236
|
+
"getSelection",
|
|
237
|
+
"extractArticle",
|
|
238
|
+
"extractLinks",
|
|
239
|
+
"extractImages",
|
|
240
|
+
"queryElement",
|
|
241
|
+
"highlight",
|
|
242
|
+
"removeHighlight",
|
|
243
|
+
"insertWidget",
|
|
244
|
+
"updateWidget",
|
|
245
|
+
"removeWidget",
|
|
246
|
+
"injectCSS",
|
|
247
|
+
"removeCSS",
|
|
248
|
+
"captureVisible",
|
|
249
|
+
"getContextMenuEvent"
|
|
250
|
+
] },
|
|
251
|
+
events: ["onContextMenu", "onSelectionChange"]
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
actions: { notify: {
|
|
255
|
+
method: "notify",
|
|
256
|
+
fallback: fallbackNotify
|
|
257
|
+
} },
|
|
258
|
+
statics: {
|
|
259
|
+
SDKError,
|
|
260
|
+
ai: aiAPI,
|
|
261
|
+
clipboard: clipboardAPI,
|
|
262
|
+
dialog: dialogAPI,
|
|
263
|
+
file: fileAPI,
|
|
264
|
+
onNotificationAction,
|
|
265
|
+
onFileDrop
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
bootstrapSDK(childMethods, { timeoutMs: 1500 }).then((e) => {
|
|
269
|
+
e && updateHostInfo(e);
|
|
270
|
+
}), sdk.SDKError = SDKError;
|
|
271
|
+
var src_default = sdk;
|
|
272
|
+
export { src_default as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?module.exports=t():typeof define==`function`&&define.amd?define([],t):(e=typeof globalThis<`u`?globalThis:e||self,e.gemigo=t())})(this,function(){var e=Object.defineProperty,t=(e,t)=>()=>(e&&(t=e(e=0)),t),n=t=>{let n={};for(var r in t)e(n,r,{get:t[r],enumerable:!0});return n},r,i,a,o,s,c=t((()=>{(function(e){e.Call=`call`,e.Reply=`reply`,e.Syn=`syn`,e.SynAck=`synAck`,e.Ack=`ack`})(r||={}),(function(e){e.Fulfilled=`fulfilled`,e.Rejected=`rejected`})(i||={}),(function(e){e.ConnectionDestroyed=`ConnectionDestroyed`,e.ConnectionTimeout=`ConnectionTimeout`,e.NoIframeSrc=`NoIframeSrc`})(a||={}),(function(e){e.DataCloneError=`DataCloneError`})(o||={}),(function(e){e.Message=`message`})(s||={})})),l,u=t((()=>{l=(e,t)=>{let n=[],r=!1;return{destroy(i){r||(r=!0,t(`${e}: Destroying connection`),n.forEach(e=>{e(i)}))},onDestroy(e){r?e():n.push(e)}}}})),d,f=t((()=>{d=e=>(...t)=>{e&&console.log(`[Penpal]`,...t)}})),p,m,h=t((()=>{p=({name:e,message:t,stack:n})=>({name:e,message:t,stack:n}),m=e=>{let t=Error();return Object.keys(e).forEach(n=>t[n]=e[n]),t}})),g,_=t((()=>{h(),c(),g=(e,t,n)=>{let{localName:a,local:c,remote:l,originForSending:u,originForReceiving:d}=e,f=!1,m=e=>{if(e.source!==l||e.data.penpal!==r.Call)return;if(d!==`*`&&e.origin!==d){n(`${a} received message from origin ${e.origin} which did not match expected origin ${d}`);return}let{methodName:s,args:c,id:m}=e.data;n(`${a}: Received ${s}() call`);let h=e=>t=>{if(n(`${a}: Sending ${s}() reply`),f){n(`${a}: Unable to send ${s}() reply due to destroyed connection`);return}let c={penpal:r.Reply,id:m,resolution:e,returnValue:t};e===i.Rejected&&t instanceof Error&&(c.returnValue=p(t),c.returnValueIsError=!0);try{l.postMessage(c,u)}catch(e){if(e.name===o.DataCloneError){let t={penpal:r.Reply,id:m,resolution:i.Rejected,returnValue:p(e),returnValueIsError:!0};l.postMessage(t,u)}throw e}};new Promise(e=>e(t[s].apply(t,c))).then(h(i.Fulfilled),h(i.Rejected))};return c.addEventListener(s.Message,m),()=>{f=!0,c.removeEventListener(s.Message,m)}}})),v,y,ee=t((()=>{v=0,y=()=>++v})),b,x,S,C,w,T,E,D=t((()=>{b=`.`,x=e=>e?e.split(b):[],S=e=>e.join(b),C=(e,t)=>{let n=x(t||``);return n.push(e),S(n)},w=(e,t,n)=>{let r=x(t);return r.reduce((e,t,i)=>(e[t]===void 0&&(e[t]={}),i===r.length-1&&(e[t]=n),e[t]),e),e},T=(e,t)=>{let n={};return Object.keys(e).forEach(r=>{let i=e[r],a=C(r,t);typeof i==`object`&&Object.assign(n,T(i,a)),typeof i==`function`&&(n[a]=i)}),n},E=e=>{let t={};for(let n in e)w(t,n,e[n]);return t}})),O,k=t((()=>{ee(),h(),D(),c(),O=(e,t,n,o,c)=>{let{localName:l,local:u,remote:d,originForSending:f,originForReceiving:p}=t,h=!1;c(`${l}: Connecting call sender`);let g=e=>(...t)=>{c(`${l}: Sending ${e}() call`);let n;try{d.closed&&(n=!0)}catch{n=!0}if(n&&o(),h){let t=Error(`Unable to send ${e}() call due to destroyed connection`);throw t.code=a.ConnectionDestroyed,t}return new Promise((n,a)=>{let o=y(),h=t=>{if(t.source!==d||t.data.penpal!==r.Reply||t.data.id!==o)return;if(p!==`*`&&t.origin!==p){c(`${l} received message from origin ${t.origin} which did not match expected origin ${p}`);return}let f=t.data;c(`${l}: Received ${e}() reply`),u.removeEventListener(s.Message,h);let g=f.returnValue;f.returnValueIsError&&(g=m(g)),(f.resolution===i.Fulfilled?n:a)(g)};u.addEventListener(s.Message,h);let g={penpal:r.Call,id:o,methodName:e,args:t};d.postMessage(g,f)})},_=n.reduce((e,t)=>(e[t]=g(t),e),{});return Object.assign(e,E(_)),()=>{h=!0}}})),te=t((()=>{_(),k()})),ne=t((()=>{c()})),A,j=t((()=>{c(),A=(e,t)=>{let n;return e!==void 0&&(n=window.setTimeout(()=>{let n=Error(`Connection timed out after ${e}ms`);n.code=a.ConnectionTimeout,t(n)},e)),()=>{clearTimeout(n)}}})),re=t((()=>{c()})),ie=t((()=>{c(),te(),ne(),j(),re()})),M,ae=t((()=>{c(),_(),k(),M=(e,t,n,i)=>{let{destroy:a,onDestroy:o}=n;return n=>{if(!(e instanceof RegExp?e.test(n.origin):e===`*`||e===n.origin)){i(`Child: Handshake - Received SYN-ACK from origin ${n.origin} which did not match expected origin ${e}`);return}i(`Child: Handshake - Received SYN-ACK, responding with ACK`);let s=n.origin===`null`?`*`:n.origin,c={penpal:r.Ack,methodNames:Object.keys(t)};window.parent.postMessage(c,s);let l={localName:`Child`,local:window,remote:window.parent,originForSending:s,originForReceiving:n.origin};o(g(l,t,i));let u={};return o(O(u,l,n.data.methodNames,a,i)),u}}})),N,P,oe=t((()=>{u(),f(),c(),ae(),D(),j(),N=()=>{try{clearTimeout()}catch{return!1}return!0},P=(e={})=>{let{parentOrigin:t=`*`,methods:n={},timeout:i,debug:a=!1}=e,o=d(a),c=l(`Child`,o),{destroy:u,onDestroy:f}=c,p=M(t,T(n),c,o),m=()=>{o(`Child: Handshake - Sending SYN`);let e={penpal:r.Syn},n=t instanceof RegExp?`*`:t;window.parent.postMessage(e,n)};return{promise:new Promise((e,t)=>{let n=A(i,u),a=t=>{if(N()&&!(t.source!==parent||!t.data)&&t.data.penpal===r.SynAck){let r=p(t);r&&(window.removeEventListener(s.Message,a),n(),e(r))}};window.addEventListener(s.Message,a),m(),f(e=>{window.removeEventListener(s.Message,a),e&&t(e)})}),destroy(){u()}}}})),se=t((()=>{ie(),oe(),c()})),ce=n({callHost:()=>I,createRPCProxy:()=>L,getHost:()=>ue,hasConnectionFailed:()=>fe,initConnection:()=>pe,isConnected:()=>de,tryGetHost:()=>F,withFallback:()=>me});function le(){try{return window.self!==window.top}catch{return!0}}async function F(e,t){if(z)return z;if(B)return null;if(!le())return B=!0,null;if(!R){let n={},r=e??V;r&&Object.assign(n,r),R=P({methods:n,timeout:t?.timeoutMs??H}).promise.then(e=>(z=e,e)).catch(e=>(console.error(`[GemiGo Connection] Promise failed:`,e),B=!0,R=null,null))}return R}async function ue(){let e=await F();if(!e)throw Error(`Not connected to host. SDK may be running outside of a supported environment.`);return e}function de(){return z!==null}function fe(){return B}function pe(e,t){V=e,F(e,t)}async function I(e,t=[],n){let r=await F();if(r&&typeof r[e]==`function`){let i=await r[e](...t);if(i?.success!==!1)return i?.data===void 0?i?.value===void 0?i:i.value:i.data;if(n)return n(...t);throw Error(i?.error||`Host method ${String(e)} failed`)}if(n)return n(...t);throw Error(`Method ${String(e)} not supported in this environment`)}function L(e,t={}){let n={};for(let r of e){let e=t.mapping?.[r]||r,i=t.fallbacks?.[r];n[r]=(...t)=>I(e,t,i)}return n}function me(e,t){return async(...n)=>{try{return await e(...n)}catch{return t(...n)}}}var R,z,B,V,H,U=t((()=>{se(),R=null,z=null,B=!1,H=1500}));U();function W(){let e=new Map;return{on(t,n){return e.has(t)||e.set(t,new Set),e.get(t).add(n),()=>e.get(t)?.delete(n)},emit(t,...n){e.get(t)?.forEach(e=>e(...n))},off(t){t?e.delete(t):e.clear()}}}let G=W();function he(e){let t=F,n={},r={};if(e.rpc){let t=L(e.rpc.methods,{mapping:e.rpc.mapping,fallbacks:e.rpc.fallbacks});Object.assign(n,t)}if(e.events)if(Array.isArray(e.events))for(let i of e.events){let e=i;n[i]=n=>(t?.(),G.on(e,n)),r[i]=(...t)=>{G.emit(e,...t)}}else for(let[i,a]of Object.entries(e.events)){if(!a)continue;let e=a,o=typeof e==`string`?e:e.event,s=typeof e==`object`&&`childMethod`in e&&e.childMethod?e.childMethod:i;n[i]=e=>(t?.(),G.on(o,e)),r[s]=(...e)=>{G.emit(o,...e)}}return{api:n,childMethods:r}}function ge(e,t){return async(...n)=>{try{let r=await I(e,t.transform?t.transform(...n):n);return t.onSuccess?t.onSuccess(r):r}catch{return t.fallback(...n)}}}function _e(e){let t=e.statics?{...e.statics}:{},n={};if(e.modules)for(let[r,i]of Object.entries(e.modules)){let{api:e,childMethods:a}=he(i);t[r]=e,Object.assign(n,a)}if(e.actions)for(let[n,r]of Object.entries(e.actions)){let e=r;t[n]=ge(e.method,e)}if(e.getters)for(let[n,r]of Object.entries(e.getters))Object.defineProperty(t,n,{get:r,enumerable:!0,configurable:!0});return{sdk:t,childMethods:n}}async function ve(e,t={}){let{initConnection:n}=await Promise.resolve().then(()=>(U(),ce));n(e,t);let r=await F();if(r&&typeof r.getProtocolInfo==`function`)try{return await r.getProtocolInfo()}catch{return null}return null}U();var K=()=>`gemigo:${typeof window>`u`?`unknown`:window.location.origin.replace(/[:/]/g,`_`)}:`;let q={get:async e=>{if(typeof window>`u`||!window.localStorage)return null;let t=window.localStorage.getItem(`${K()}${e}`);if(!t)return null;try{return JSON.parse(t)}catch{return null}},set:async(e,t)=>{typeof window>`u`||!window.localStorage||window.localStorage.setItem(`${K()}${e}`,JSON.stringify(t))},delete:async e=>{typeof window>`u`||!window.localStorage||window.localStorage.removeItem(`${K()}${e}`)},clear:async()=>{if(typeof window>`u`||!window.localStorage)return;let e=K();for(let t=window.localStorage.length-1;t>=0;--t){let n=window.localStorage.key(t);n&&n.startsWith(e)&&window.localStorage.removeItem(n)}}},ye=async e=>{if(typeof window>`u`||typeof Notification>`u`)return{success:!1,reason:`not_supported`};if(Notification.permission!==`granted`)return{success:!1,reason:`permission_not_granted`};try{return new Notification(e.title,{body:e.message,icon:e.icon}),{success:!0}}catch{return{success:!1,reason:`failed_to_notify`}}},be={request:async(e,t)=>{let{method:n=`GET`,headers:r,body:i,responseType:a}=t??{},o=await fetch(e,{method:n,headers:r,body:i?typeof i==`string`?i:JSON.stringify(i):void 0}),s={};o.headers.forEach((e,t)=>s[t]=e);let c=a===`text`?await o.text():a===`arraybuffer`?await o.arrayBuffer():await o.json();return{status:o.status,data:c,headers:s}}};var J=class e extends Error{constructor(t,n){super(n),this.code=t,this.name=`SDKError`,Object.setPrototypeOf(this,e.prototype)}},Y=null,xe={storage:!0,network:!1,scheduler:!1,fileWatch:!1,fileWrite:!1,notification:!0,clipboard:!1,ai:!1,shell:!1,extension:{read:!1,events:!1,modify:!1,capture:!1}};let Se=e=>{Y=e};var X=e=>{throw new J(`NOT_SUPPORTED`,`${e} is not supported in this environment.`)},Z=e=>async()=>X(e),Q=e=>()=>X(e),Ce={chat:Z(`ai.chat`),summarize:Z(`ai.summarize`),translate:Z(`ai.translate`)},we={readText:Z(`clipboard.readText`),writeText:Z(`clipboard.writeText`),readImage:Z(`clipboard.readImage`),writeImage:Z(`clipboard.writeImage`),onChange:Q(`clipboard.onChange`)},Te={openFile:Z(`dialog.openFile`),openDirectory:Z(`dialog.openDirectory`),saveFile:Z(`dialog.saveFile`),message:Z(`dialog.message`)},Ee={readText:Z(`file.readText`),readBinary:Z(`file.readBinary`),write:Z(`file.write`),append:Z(`file.append`),exists:Z(`file.exists`),stat:Z(`file.stat`),copy:Z(`file.copy`),move:Z(`file.move`),remove:Z(`file.remove`),list:Z(`file.list`),mkdir:Z(`file.mkdir`),persistPermission:Z(`file.persistPermission`)},De=Q(`onNotificationAction`),Oe=Q(`onFileDrop`);let{sdk:$,childMethods:ke}=_e({getters:{platform:()=>Y?.platform??`web`,capabilities:()=>Y?.capabilities??xe},modules:{storage:{rpc:{methods:[`get`,`set`,`delete`,`clear`],mapping:{get:`storageGet`,set:`storageSet`,delete:`storageDelete`,clear:`storageClear`},fallbacks:{get:q.get,set:q.set,delete:q.delete,clear:q.clear}}},network:{rpc:{methods:[`request`],mapping:{request:`networkRequest`},fallbacks:{request:be.request}}},extension:{rpc:{methods:[`getPageInfo`,`getPageHTML`,`getPageText`,`getSelection`,`extractArticle`,`extractLinks`,`extractImages`,`queryElement`,`highlight`,`removeHighlight`,`insertWidget`,`updateWidget`,`removeWidget`,`injectCSS`,`removeCSS`,`captureVisible`,`getContextMenuEvent`]},events:[`onContextMenu`,`onSelectionChange`]}},actions:{notify:{method:`notify`,fallback:ye}},statics:{SDKError:J,ai:Ce,clipboard:we,dialog:Te,file:Ee,onNotificationAction:De,onFileDrop:Oe}});return ve(ke,{timeoutMs:1500}).then(e=>{e&&Se(e)}),$.SDKError=J,$});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI API types
|
|
3
|
+
*/
|
|
4
|
+
/** Chat message */
|
|
5
|
+
export interface ChatMessage {
|
|
6
|
+
role: 'user' | 'assistant' | 'system';
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
/** Chat response */
|
|
10
|
+
export interface ChatResponse {
|
|
11
|
+
role: 'assistant';
|
|
12
|
+
content: string;
|
|
13
|
+
}
|
|
14
|
+
/** Translation options */
|
|
15
|
+
export interface TranslateOptions {
|
|
16
|
+
/** Source language (auto-detect if not specified) */
|
|
17
|
+
from?: string;
|
|
18
|
+
/** Target language (required) */
|
|
19
|
+
to: string;
|
|
20
|
+
}
|
|
21
|
+
/** Translation result */
|
|
22
|
+
export interface TranslateResult {
|
|
23
|
+
text: string;
|
|
24
|
+
from: string;
|
|
25
|
+
to: string;
|
|
26
|
+
}
|
|
27
|
+
/** AI API for cloud model integration */
|
|
28
|
+
export interface AIAPI {
|
|
29
|
+
/**
|
|
30
|
+
* Multi-turn conversation
|
|
31
|
+
* @param messages - Conversation history
|
|
32
|
+
* @returns Assistant response
|
|
33
|
+
*/
|
|
34
|
+
chat(messages: ChatMessage[]): Promise<ChatResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* Summarize text content
|
|
37
|
+
* @param text - Text to summarize
|
|
38
|
+
* @returns Summary text
|
|
39
|
+
*/
|
|
40
|
+
summarize(text: string): Promise<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Translate text
|
|
43
|
+
* @param text - Text to translate
|
|
44
|
+
* @param options - Translation options
|
|
45
|
+
* @returns Translation result
|
|
46
|
+
*/
|
|
47
|
+
translate(text: string, options: TranslateOptions): Promise<TranslateResult>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard API types
|
|
3
|
+
*/
|
|
4
|
+
/** Clipboard content */
|
|
5
|
+
export interface ClipboardContent {
|
|
6
|
+
text?: string;
|
|
7
|
+
image?: Blob;
|
|
8
|
+
}
|
|
9
|
+
/** Clipboard change callback */
|
|
10
|
+
export type ClipboardChangeCallback = (content: ClipboardContent) => void;
|
|
11
|
+
/** Clipboard API */
|
|
12
|
+
export interface ClipboardAPI {
|
|
13
|
+
/**
|
|
14
|
+
* Read text from clipboard
|
|
15
|
+
* @returns Clipboard text content
|
|
16
|
+
*/
|
|
17
|
+
readText(): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Write text to clipboard
|
|
20
|
+
* @param text - Text to write
|
|
21
|
+
*/
|
|
22
|
+
writeText(text: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Read image from clipboard
|
|
25
|
+
* @returns Image blob or null
|
|
26
|
+
*/
|
|
27
|
+
readImage(): Promise<Blob | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Write image to clipboard
|
|
30
|
+
* @param blob - Image blob to write
|
|
31
|
+
*/
|
|
32
|
+
writeImage(blob: Blob): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Listen for clipboard content changes (desktop only)
|
|
35
|
+
* @param callback - Change callback
|
|
36
|
+
* @returns Unsubscribe function
|
|
37
|
+
*/
|
|
38
|
+
onChange(callback: ClipboardChangeCallback): () => void;
|
|
39
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common types used across the GemiGo SDK
|
|
3
|
+
*/
|
|
4
|
+
/** Current platform type */
|
|
5
|
+
export type Platform = 'web' | 'desktop' | 'extension';
|
|
6
|
+
/** SDK Error Codes */
|
|
7
|
+
export type SDKErrorCode = 'NOT_SUPPORTED' | 'PERMISSION_DENIED' | 'NETWORK_NOT_ALLOWED' | 'TIMEOUT' | 'INTERNAL_ERROR' | 'NOT_CONNECTED';
|
|
8
|
+
/** Unified SDK Error class */
|
|
9
|
+
export declare class SDKError extends Error {
|
|
10
|
+
code: SDKErrorCode;
|
|
11
|
+
constructor(code: SDKErrorCode, message: string);
|
|
12
|
+
}
|
|
13
|
+
/** Environment capabilities */
|
|
14
|
+
export interface Capabilities {
|
|
15
|
+
/** Persistent key-value storage */
|
|
16
|
+
storage: boolean;
|
|
17
|
+
/** Cross-origin/network proxy capability (host mediated) */
|
|
18
|
+
network: boolean;
|
|
19
|
+
scheduler: boolean;
|
|
20
|
+
fileWatch: boolean;
|
|
21
|
+
fileWrite: boolean;
|
|
22
|
+
notification: boolean;
|
|
23
|
+
clipboard: boolean;
|
|
24
|
+
ai: boolean;
|
|
25
|
+
shell: boolean;
|
|
26
|
+
/** Extension-specific capability breakdown */
|
|
27
|
+
extension?: {
|
|
28
|
+
read: boolean;
|
|
29
|
+
events: boolean;
|
|
30
|
+
modify: boolean;
|
|
31
|
+
capture: boolean;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** File entry information */
|
|
35
|
+
export interface FileEntry {
|
|
36
|
+
/** File name */
|
|
37
|
+
name: string;
|
|
38
|
+
/** Full path */
|
|
39
|
+
path: string;
|
|
40
|
+
/** Whether this is a file */
|
|
41
|
+
isFile: boolean;
|
|
42
|
+
/** Whether this is a directory */
|
|
43
|
+
isDirectory: boolean;
|
|
44
|
+
/** File size in bytes */
|
|
45
|
+
size: number;
|
|
46
|
+
/** Last modification timestamp */
|
|
47
|
+
mtime: number;
|
|
48
|
+
}
|
|
49
|
+
/** File stat information */
|
|
50
|
+
export interface FileStat {
|
|
51
|
+
size: number;
|
|
52
|
+
mtime: number;
|
|
53
|
+
ctime: number;
|
|
54
|
+
isFile: boolean;
|
|
55
|
+
isDirectory: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Base RPC result structure.
|
|
59
|
+
* All RPC methods that can fail should return this structure.
|
|
60
|
+
*/
|
|
61
|
+
export interface RPCResult<T = void> {
|
|
62
|
+
success: boolean;
|
|
63
|
+
data?: T;
|
|
64
|
+
error?: string;
|
|
65
|
+
code?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* RPC result with required data (for successful operations).
|
|
69
|
+
*/
|
|
70
|
+
export type RPCResultWithData<T> = RPCResult<T> & {
|
|
71
|
+
data: T;
|
|
72
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { NotifyOptions } from './notify';
|
|
2
|
+
/** Scheduler task configuration */
|
|
3
|
+
export interface SchedulerConfig {
|
|
4
|
+
/** Unique task ID */
|
|
5
|
+
id: string;
|
|
6
|
+
/** Interval (e.g. '30m', '1h', '2h', '1d') */
|
|
7
|
+
interval: string;
|
|
8
|
+
/** Start time (e.g. '08:00') */
|
|
9
|
+
startTime?: string;
|
|
10
|
+
/** End time (e.g. '22:00') */
|
|
11
|
+
endTime?: string;
|
|
12
|
+
/** Notification to show when task runs */
|
|
13
|
+
notification?: NotifyOptions;
|
|
14
|
+
}
|
|
15
|
+
/** Scheduler operation result */
|
|
16
|
+
export interface SchedulerResult {
|
|
17
|
+
success: boolean;
|
|
18
|
+
reason?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Scheduler API for background tasks */
|
|
21
|
+
export interface SchedulerAPI {
|
|
22
|
+
/**
|
|
23
|
+
* Register a background scheduled task
|
|
24
|
+
* @param config - Task configuration
|
|
25
|
+
*/
|
|
26
|
+
register(config: SchedulerConfig): Promise<SchedulerResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Update an existing task
|
|
29
|
+
* @param id - Task ID
|
|
30
|
+
* @param config - Updated configuration
|
|
31
|
+
*/
|
|
32
|
+
update(id: string, config: Partial<Omit<SchedulerConfig, 'id'>>): Promise<SchedulerResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Cancel a scheduled task
|
|
35
|
+
* @param id - Task ID
|
|
36
|
+
*/
|
|
37
|
+
cancel(id: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* List all scheduled tasks for this app
|
|
40
|
+
*/
|
|
41
|
+
list(): Promise<SchedulerConfig[]>;
|
|
42
|
+
}
|
|
43
|
+
/** File watch event type */
|
|
44
|
+
export type FileWatchEventType = 'create' | 'modify' | 'delete';
|
|
45
|
+
/** File watch configuration */
|
|
46
|
+
export interface FileWatchConfig {
|
|
47
|
+
/** Unique watch ID */
|
|
48
|
+
id: string;
|
|
49
|
+
/** Path to watch (e.g. '~/Downloads') */
|
|
50
|
+
path: string;
|
|
51
|
+
/** Glob pattern (e.g. '*.png') */
|
|
52
|
+
pattern?: string;
|
|
53
|
+
/** Events to watch for */
|
|
54
|
+
events: FileWatchEventType[];
|
|
55
|
+
/** Action to perform */
|
|
56
|
+
action: {
|
|
57
|
+
type: 'callback';
|
|
58
|
+
callback: string;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** File watch event */
|
|
62
|
+
export interface FileWatchEvent {
|
|
63
|
+
/** Watch ID */
|
|
64
|
+
id: string;
|
|
65
|
+
/** Changed file path */
|
|
66
|
+
path: string;
|
|
67
|
+
/** Event type */
|
|
68
|
+
event: FileWatchEventType;
|
|
69
|
+
}
|
|
70
|
+
/** FileWatch API for monitoring file system changes */
|
|
71
|
+
export interface FileWatchAPI {
|
|
72
|
+
/**
|
|
73
|
+
* Register a file watch
|
|
74
|
+
* @param config - Watch configuration
|
|
75
|
+
*/
|
|
76
|
+
register(config: FileWatchConfig): Promise<{
|
|
77
|
+
success: boolean;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Cancel a file watch
|
|
81
|
+
* @param id - Watch ID
|
|
82
|
+
*/
|
|
83
|
+
cancel(id: string): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
/** File watch callback handler */
|
|
86
|
+
export type FileWatchHandler = (callbackId: string, handler: (event: FileWatchEvent) => void) => void;
|
|
87
|
+
/** Shell API for system integration */
|
|
88
|
+
export interface ShellAPI {
|
|
89
|
+
/**
|
|
90
|
+
* Open URL in system default browser
|
|
91
|
+
* @param url - URL to open
|
|
92
|
+
*/
|
|
93
|
+
openExternal(url: string): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Show file in Finder/Explorer
|
|
96
|
+
* @param path - File path
|
|
97
|
+
*/
|
|
98
|
+
showItemInFolder(path: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Open file with system default application
|
|
101
|
+
* @param path - File path
|
|
102
|
+
*/
|
|
103
|
+
openPath(path: string): Promise<void>;
|
|
104
|
+
}
|
|
105
|
+
/** GlobalShortcut API for system-level keyboard shortcuts */
|
|
106
|
+
export interface GlobalShortcutAPI {
|
|
107
|
+
/**
|
|
108
|
+
* Register a global shortcut
|
|
109
|
+
* @param accelerator - Key combination (e.g. 'Cmd+Shift+X', 'Ctrl+Alt+P')
|
|
110
|
+
* @param callback - Handler function
|
|
111
|
+
* @returns True if registration succeeded
|
|
112
|
+
*/
|
|
113
|
+
register(accelerator: string, callback: () => void): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Unregister a global shortcut
|
|
116
|
+
* @param accelerator - Key combination
|
|
117
|
+
*/
|
|
118
|
+
unregister(accelerator: string): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Unregister all shortcuts for this app
|
|
121
|
+
*/
|
|
122
|
+
unregisterAll(): Promise<void>;
|
|
123
|
+
}
|
|
124
|
+
/** Autostart API for managing app launch on system startup */
|
|
125
|
+
export interface AutostartAPI {
|
|
126
|
+
/**
|
|
127
|
+
* Enable auto-start on system boot
|
|
128
|
+
*/
|
|
129
|
+
enable(): Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Disable auto-start
|
|
132
|
+
*/
|
|
133
|
+
disable(): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Check if auto-start is enabled
|
|
136
|
+
*/
|
|
137
|
+
isEnabled(): Promise<boolean>;
|
|
138
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { FileEntry } from './common';
|
|
2
|
+
/** File filter for save dialog */
|
|
3
|
+
export interface FileFilter {
|
|
4
|
+
name: string;
|
|
5
|
+
extensions: string[];
|
|
6
|
+
}
|
|
7
|
+
/** Open file dialog options */
|
|
8
|
+
export interface OpenFileOptions {
|
|
9
|
+
/** MIME type filter, e.g. 'image/*' */
|
|
10
|
+
accept?: string;
|
|
11
|
+
/** Allow multiple file selection */
|
|
12
|
+
multiple?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Save file dialog options */
|
|
15
|
+
export interface SaveFileOptions {
|
|
16
|
+
/** Default file name */
|
|
17
|
+
defaultName?: string;
|
|
18
|
+
/** File type filters */
|
|
19
|
+
filters?: FileFilter[];
|
|
20
|
+
}
|
|
21
|
+
/** Message dialog options */
|
|
22
|
+
export interface MessageOptions {
|
|
23
|
+
/** Dialog title */
|
|
24
|
+
title: string;
|
|
25
|
+
/** Dialog message */
|
|
26
|
+
message: string;
|
|
27
|
+
/** Message type */
|
|
28
|
+
type?: 'info' | 'warning' | 'error';
|
|
29
|
+
/** Button labels */
|
|
30
|
+
buttons?: string[];
|
|
31
|
+
}
|
|
32
|
+
/** Dialog API */
|
|
33
|
+
export interface DialogAPI {
|
|
34
|
+
/**
|
|
35
|
+
* Open file selection dialog
|
|
36
|
+
* @param options - Dialog options
|
|
37
|
+
* @returns Selected file(s) or null if cancelled
|
|
38
|
+
*/
|
|
39
|
+
openFile(options?: OpenFileOptions): Promise<FileEntry | FileEntry[] | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Open directory selection dialog
|
|
42
|
+
* @returns Selected directory path or null if cancelled
|
|
43
|
+
*/
|
|
44
|
+
openDirectory(): Promise<{
|
|
45
|
+
path: string;
|
|
46
|
+
} | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Open save file dialog
|
|
49
|
+
* @param options - Dialog options
|
|
50
|
+
* @returns Selected save path or null if cancelled
|
|
51
|
+
*/
|
|
52
|
+
saveFile(options?: SaveFileOptions): Promise<{
|
|
53
|
+
path: string;
|
|
54
|
+
} | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Show a message dialog
|
|
57
|
+
* @param options - Message options
|
|
58
|
+
* @returns Index of clicked button
|
|
59
|
+
*/
|
|
60
|
+
message(options: MessageOptions): Promise<number>;
|
|
61
|
+
}
|
|
62
|
+
/** File drop callback */
|
|
63
|
+
export type FileDropCallback = (files: FileEntry[]) => void;
|
|
64
|
+
/** File drop handler (top-level API) */
|
|
65
|
+
export type FileDropHandler = (callback: FileDropCallback) => () => void;
|