@gemigo/extension-sdk 0.1.2 → 0.2.1
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/README.md +63 -61
- package/dist/apis/extension.d.ts +155 -0
- package/dist/apis/index.d.ts +4 -0
- package/dist/core/connection.d.ts +117 -0
- package/dist/core/event-bus.d.ts +35 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/gemigo-extension-sdk.es.js +191 -147
- package/dist/gemigo-extension-sdk.umd.js +1 -1
- package/dist/index.d.ts +4 -62
- package/dist/sdk.d.ts +15 -0
- package/dist/types/ai.d.ts +48 -0
- package/dist/types/clipboard.d.ts +39 -0
- package/dist/types/common.d.ts +39 -0
- package/dist/types/desktop.d.ts +138 -0
- package/dist/types/dialog.d.ts +65 -0
- package/dist/types/extension.d.ts +187 -0
- package/dist/types/file.d.ts +79 -0
- package/dist/types/index.d.ts +88 -0
- package/dist/types/manifest.d.ts +87 -0
- package/dist/types/network.d.ts +37 -0
- package/dist/types/notify.d.ts +35 -0
- package/dist/types/storage.d.ts +27 -0
- package/package.json +3 -1
|
@@ -18,160 +18,160 @@ var NativeEventType;
|
|
|
18
18
|
(function(e) {
|
|
19
19
|
e.Message = "message";
|
|
20
20
|
})(NativeEventType ||= {});
|
|
21
|
-
var createDestructor_default = (e,
|
|
22
|
-
let
|
|
21
|
+
var createDestructor_default = (e, v) => {
|
|
22
|
+
let y = [], b = !1;
|
|
23
23
|
return {
|
|
24
|
-
destroy(
|
|
25
|
-
|
|
26
|
-
e(
|
|
24
|
+
destroy(x) {
|
|
25
|
+
b || (b = !0, v(`${e}: Destroying connection`), y.forEach((e) => {
|
|
26
|
+
e(x);
|
|
27
27
|
}));
|
|
28
28
|
},
|
|
29
29
|
onDestroy(e) {
|
|
30
|
-
|
|
30
|
+
b ? e() : y.push(e);
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
|
-
}, createLogger_default = (e) => (...
|
|
34
|
-
e && console.log("[Penpal]", ...
|
|
33
|
+
}, createLogger_default = (e) => (...v) => {
|
|
34
|
+
e && console.log("[Penpal]", ...v);
|
|
35
35
|
};
|
|
36
|
-
const serializeError = ({ name: e, message:
|
|
36
|
+
const serializeError = ({ name: e, message: v, stack: y }) => ({
|
|
37
37
|
name: e,
|
|
38
|
-
message:
|
|
39
|
-
stack:
|
|
38
|
+
message: v,
|
|
39
|
+
stack: y
|
|
40
40
|
}), deserializeError = (e) => {
|
|
41
|
-
let
|
|
42
|
-
return Object.keys(e).forEach((
|
|
41
|
+
let v = /* @__PURE__ */ Error();
|
|
42
|
+
return Object.keys(e).forEach((y) => v[y] = e[y]), v;
|
|
43
43
|
};
|
|
44
|
-
var connectCallReceiver_default = (
|
|
45
|
-
let { localName:
|
|
46
|
-
if (
|
|
47
|
-
if (
|
|
48
|
-
|
|
44
|
+
var connectCallReceiver_default = (y, S, C) => {
|
|
45
|
+
let { localName: T, local: E, remote: D, originForSending: O, originForReceiving: k } = y, A = !1, j = (y) => {
|
|
46
|
+
if (y.source !== D || y.data.penpal !== MessageType.Call) return;
|
|
47
|
+
if (k !== "*" && y.origin !== k) {
|
|
48
|
+
C(`${T} received message from origin ${y.origin} which did not match expected origin ${k}`);
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
|
-
let { methodName:
|
|
52
|
-
|
|
53
|
-
let
|
|
54
|
-
if (
|
|
55
|
-
|
|
51
|
+
let { methodName: x, args: E, id: j } = y.data;
|
|
52
|
+
C(`${T}: Received ${x}() call`);
|
|
53
|
+
let M = (y) => (S) => {
|
|
54
|
+
if (C(`${T}: Sending ${x}() reply`), A) {
|
|
55
|
+
C(`${T}: Unable to send ${x}() reply due to destroyed connection`);
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
let
|
|
58
|
+
let E = {
|
|
59
59
|
penpal: MessageType.Reply,
|
|
60
|
-
id:
|
|
61
|
-
resolution:
|
|
62
|
-
returnValue:
|
|
60
|
+
id: j,
|
|
61
|
+
resolution: y,
|
|
62
|
+
returnValue: S
|
|
63
63
|
};
|
|
64
|
-
|
|
64
|
+
y === Resolution.Rejected && S instanceof Error && (E.returnValue = serializeError(S), E.returnValueIsError = !0);
|
|
65
65
|
try {
|
|
66
|
-
|
|
67
|
-
} catch (
|
|
68
|
-
if (
|
|
69
|
-
let
|
|
66
|
+
D.postMessage(E, O);
|
|
67
|
+
} catch (y) {
|
|
68
|
+
if (y.name === NativeErrorName.DataCloneError) {
|
|
69
|
+
let b = {
|
|
70
70
|
penpal: MessageType.Reply,
|
|
71
|
-
id:
|
|
71
|
+
id: j,
|
|
72
72
|
resolution: Resolution.Rejected,
|
|
73
|
-
returnValue: serializeError(
|
|
73
|
+
returnValue: serializeError(y),
|
|
74
74
|
returnValueIsError: !0
|
|
75
75
|
};
|
|
76
|
-
|
|
76
|
+
D.postMessage(b, O);
|
|
77
77
|
}
|
|
78
|
-
throw
|
|
78
|
+
throw y;
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
|
-
new Promise((e) => e(
|
|
81
|
+
new Promise((e) => e(S[x].apply(S, E))).then(M(Resolution.Fulfilled), M(Resolution.Rejected));
|
|
82
82
|
};
|
|
83
|
-
return
|
|
84
|
-
|
|
83
|
+
return E.addEventListener(NativeEventType.Message, j), () => {
|
|
84
|
+
A = !0, E.removeEventListener(NativeEventType.Message, j);
|
|
85
85
|
};
|
|
86
|
-
}, id = 0, generateId_default = () => ++id, KEY_PATH_DELIMITER = ".", keyPathToSegments = (e) => e ? e.split(KEY_PATH_DELIMITER) : [], segmentsToKeyPath = (e) => e.join(KEY_PATH_DELIMITER), createKeyPath = (e,
|
|
87
|
-
let
|
|
88
|
-
return
|
|
86
|
+
}, id = 0, generateId_default = () => ++id, KEY_PATH_DELIMITER = ".", keyPathToSegments = (e) => e ? e.split(KEY_PATH_DELIMITER) : [], segmentsToKeyPath = (e) => e.join(KEY_PATH_DELIMITER), createKeyPath = (e, v) => {
|
|
87
|
+
let y = keyPathToSegments(v || "");
|
|
88
|
+
return y.push(e), segmentsToKeyPath(y);
|
|
89
89
|
};
|
|
90
|
-
const setAtKeyPath = (e,
|
|
91
|
-
let
|
|
92
|
-
return
|
|
93
|
-
}, serializeMethods = (e,
|
|
94
|
-
let
|
|
95
|
-
return Object.keys(e).forEach((
|
|
96
|
-
let
|
|
97
|
-
typeof
|
|
98
|
-
}),
|
|
90
|
+
const setAtKeyPath = (e, v, y) => {
|
|
91
|
+
let b = keyPathToSegments(v);
|
|
92
|
+
return b.reduce((e, v, x) => (e[v] === void 0 && (e[v] = {}), x === b.length - 1 && (e[v] = y), e[v]), e), e;
|
|
93
|
+
}, serializeMethods = (e, v) => {
|
|
94
|
+
let y = {};
|
|
95
|
+
return Object.keys(e).forEach((b) => {
|
|
96
|
+
let x = e[b], S = createKeyPath(b, v);
|
|
97
|
+
typeof x == "object" && Object.assign(y, serializeMethods(x, S)), typeof x == "function" && (y[S] = x);
|
|
98
|
+
}), y;
|
|
99
99
|
}, deserializeMethods = (e) => {
|
|
100
|
-
let
|
|
101
|
-
for (let
|
|
102
|
-
return
|
|
100
|
+
let v = {};
|
|
101
|
+
for (let y in e) setAtKeyPath(v, y, e[y]);
|
|
102
|
+
return v;
|
|
103
103
|
};
|
|
104
|
-
var connectCallSender_default = (
|
|
105
|
-
let { localName:
|
|
106
|
-
|
|
107
|
-
let
|
|
108
|
-
|
|
109
|
-
let
|
|
104
|
+
var connectCallSender_default = (b, S, C, w, E) => {
|
|
105
|
+
let { localName: D, local: k, remote: A, originForSending: j, originForReceiving: M } = S, N = !1;
|
|
106
|
+
E(`${D}: Connecting call sender`);
|
|
107
|
+
let P = (b) => (...S) => {
|
|
108
|
+
E(`${D}: Sending ${b}() call`);
|
|
109
|
+
let C;
|
|
110
110
|
try {
|
|
111
|
-
|
|
111
|
+
A.closed && (C = !0);
|
|
112
112
|
} catch {
|
|
113
|
-
|
|
113
|
+
C = !0;
|
|
114
114
|
}
|
|
115
|
-
if (
|
|
116
|
-
let e = /* @__PURE__ */ Error(`Unable to send ${
|
|
115
|
+
if (C && w(), N) {
|
|
116
|
+
let e = /* @__PURE__ */ Error(`Unable to send ${b}() call due to destroyed connection`);
|
|
117
117
|
throw e.code = ErrorCode.ConnectionDestroyed, e;
|
|
118
118
|
}
|
|
119
|
-
return new Promise((
|
|
120
|
-
let
|
|
121
|
-
if (
|
|
122
|
-
if (
|
|
123
|
-
|
|
119
|
+
return new Promise((y, C) => {
|
|
120
|
+
let w = generateId_default(), N = (S) => {
|
|
121
|
+
if (S.source !== A || S.data.penpal !== MessageType.Reply || S.data.id !== w) return;
|
|
122
|
+
if (M !== "*" && S.origin !== M) {
|
|
123
|
+
E(`${D} received message from origin ${S.origin} which did not match expected origin ${M}`);
|
|
124
124
|
return;
|
|
125
125
|
}
|
|
126
|
-
let
|
|
127
|
-
|
|
128
|
-
let
|
|
129
|
-
|
|
126
|
+
let O = S.data;
|
|
127
|
+
E(`${D}: Received ${b}() reply`), k.removeEventListener(NativeEventType.Message, N);
|
|
128
|
+
let j = O.returnValue;
|
|
129
|
+
O.returnValueIsError && (j = deserializeError(j)), (O.resolution === Resolution.Fulfilled ? y : C)(j);
|
|
130
130
|
};
|
|
131
|
-
|
|
132
|
-
let
|
|
131
|
+
k.addEventListener(NativeEventType.Message, N);
|
|
132
|
+
let P = {
|
|
133
133
|
penpal: MessageType.Call,
|
|
134
|
-
id:
|
|
135
|
-
methodName:
|
|
136
|
-
args:
|
|
134
|
+
id: w,
|
|
135
|
+
methodName: b,
|
|
136
|
+
args: S
|
|
137
137
|
};
|
|
138
|
-
|
|
138
|
+
A.postMessage(P, j);
|
|
139
139
|
});
|
|
140
|
-
},
|
|
141
|
-
return Object.assign(
|
|
142
|
-
|
|
140
|
+
}, F = C.reduce((e, v) => (e[v] = P(v), e), {});
|
|
141
|
+
return Object.assign(b, deserializeMethods(F)), () => {
|
|
142
|
+
N = !0;
|
|
143
143
|
};
|
|
144
|
-
}, startConnectionTimeout_default = (e,
|
|
145
|
-
let
|
|
146
|
-
return e !== void 0 && (
|
|
147
|
-
let
|
|
148
|
-
|
|
144
|
+
}, startConnectionTimeout_default = (e, v) => {
|
|
145
|
+
let b;
|
|
146
|
+
return e !== void 0 && (b = window.setTimeout(() => {
|
|
147
|
+
let b = /* @__PURE__ */ Error(`Connection timed out after ${e}ms`);
|
|
148
|
+
b.code = ErrorCode.ConnectionTimeout, v(b);
|
|
149
149
|
}, e)), () => {
|
|
150
|
-
clearTimeout(
|
|
150
|
+
clearTimeout(b);
|
|
151
151
|
};
|
|
152
|
-
}, handleSynAckMessageFactory_default = (
|
|
153
|
-
let { destroy:
|
|
154
|
-
return (
|
|
155
|
-
if (!(
|
|
156
|
-
|
|
152
|
+
}, handleSynAckMessageFactory_default = (v, y, b, x) => {
|
|
153
|
+
let { destroy: S, onDestroy: C } = b;
|
|
154
|
+
return (b) => {
|
|
155
|
+
if (!(v instanceof RegExp ? v.test(b.origin) : v === "*" || v === b.origin)) {
|
|
156
|
+
x(`Child: Handshake - Received SYN-ACK from origin ${b.origin} which did not match expected origin ${v}`);
|
|
157
157
|
return;
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
let
|
|
159
|
+
x("Child: Handshake - Received SYN-ACK, responding with ACK");
|
|
160
|
+
let w = b.origin === "null" ? "*" : b.origin, T = {
|
|
161
161
|
penpal: MessageType.Ack,
|
|
162
|
-
methodNames: Object.keys(
|
|
162
|
+
methodNames: Object.keys(y)
|
|
163
163
|
};
|
|
164
|
-
window.parent.postMessage(
|
|
165
|
-
let
|
|
164
|
+
window.parent.postMessage(T, w);
|
|
165
|
+
let D = {
|
|
166
166
|
localName: "Child",
|
|
167
167
|
local: window,
|
|
168
168
|
remote: window.parent,
|
|
169
|
-
originForSending:
|
|
170
|
-
originForReceiving:
|
|
169
|
+
originForSending: w,
|
|
170
|
+
originForReceiving: b.origin
|
|
171
171
|
};
|
|
172
|
-
|
|
173
|
-
let
|
|
174
|
-
return
|
|
172
|
+
C(connectCallReceiver_default(D, y, x));
|
|
173
|
+
let O = {};
|
|
174
|
+
return C(connectCallSender_default(O, D, b.data.methodNames, S, x)), O;
|
|
175
175
|
};
|
|
176
176
|
}, areGlobalsAccessible = () => {
|
|
177
177
|
try {
|
|
@@ -180,29 +180,29 @@ var connectCallSender_default = (m, g, _, v, b) => {
|
|
|
180
180
|
return !1;
|
|
181
181
|
}
|
|
182
182
|
return !0;
|
|
183
|
-
}, connectToParent_default = (
|
|
184
|
-
let { parentOrigin:
|
|
185
|
-
|
|
186
|
-
let
|
|
187
|
-
window.parent.postMessage(
|
|
183
|
+
}, connectToParent_default = (v = {}) => {
|
|
184
|
+
let { parentOrigin: y = "*", methods: b = {}, timeout: w, debug: T = !1 } = v, E = createLogger_default(T), D = createDestructor_default("Child", E), { destroy: O, onDestroy: k } = D, A = handleSynAckMessageFactory_default(y, serializeMethods(b), D, E), j = () => {
|
|
185
|
+
E("Child: Handshake - Sending SYN");
|
|
186
|
+
let v = { penpal: MessageType.Syn }, b = y instanceof RegExp ? "*" : y;
|
|
187
|
+
window.parent.postMessage(v, b);
|
|
188
188
|
};
|
|
189
189
|
return {
|
|
190
|
-
promise: new Promise((
|
|
191
|
-
let
|
|
192
|
-
if (areGlobalsAccessible() && !(
|
|
193
|
-
let e =
|
|
194
|
-
e && (window.removeEventListener(NativeEventType.Message,
|
|
190
|
+
promise: new Promise((v, y) => {
|
|
191
|
+
let b = startConnectionTimeout_default(w, O), S = (y) => {
|
|
192
|
+
if (areGlobalsAccessible() && !(y.source !== parent || !y.data) && y.data.penpal === MessageType.SynAck) {
|
|
193
|
+
let e = A(y);
|
|
194
|
+
e && (window.removeEventListener(NativeEventType.Message, S), b(), v(e));
|
|
195
195
|
}
|
|
196
196
|
};
|
|
197
|
-
window.addEventListener(NativeEventType.Message,
|
|
198
|
-
window.removeEventListener(NativeEventType.Message,
|
|
197
|
+
window.addEventListener(NativeEventType.Message, S), j(), k((e) => {
|
|
198
|
+
window.removeEventListener(NativeEventType.Message, S), e && y(e);
|
|
199
199
|
});
|
|
200
200
|
}),
|
|
201
201
|
destroy() {
|
|
202
|
-
|
|
202
|
+
O();
|
|
203
203
|
}
|
|
204
204
|
};
|
|
205
|
-
},
|
|
205
|
+
}, connectionPromise = null;
|
|
206
206
|
function isInIframe() {
|
|
207
207
|
try {
|
|
208
208
|
return window.self !== window.top;
|
|
@@ -210,42 +210,86 @@ function isInIframe() {
|
|
|
210
210
|
return !0;
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
-
function getHost() {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
213
|
+
function getHost(e) {
|
|
214
|
+
if (connectionPromise) return connectionPromise;
|
|
215
|
+
isInIframe() || console.warn("[GemiGo SDK] Not running in iframe. SDK calls will not work.");
|
|
216
|
+
let v = {};
|
|
217
|
+
return e && Object.assign(v, e), connectionPromise = connectToParent_default({ methods: v }).promise, connectionPromise;
|
|
218
|
+
}
|
|
219
|
+
function initConnection(e) {
|
|
220
|
+
getHost(e).catch((e) => {
|
|
221
|
+
console.debug("[GemiGo SDK] Auto-connect waiting...", e);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
var handlers = {
|
|
225
|
+
contextMenu: [],
|
|
226
|
+
selectionChange: []
|
|
227
|
+
};
|
|
228
|
+
function on(e, v) {
|
|
229
|
+
return handlers[e].push(v), () => {
|
|
230
|
+
let y = handlers[e].indexOf(v);
|
|
231
|
+
y > -1 && handlers[e].splice(y, 1);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function emit(e, v) {
|
|
235
|
+
handlers[e].forEach((y) => {
|
|
236
|
+
try {
|
|
237
|
+
y(v);
|
|
238
|
+
} catch (v) {
|
|
239
|
+
console.error(`[GemiGo SDK] Error in ${e} handler:`, v);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
223
242
|
}
|
|
224
|
-
|
|
243
|
+
function getChildMethods() {
|
|
244
|
+
return {
|
|
245
|
+
onContextMenuEvent(e) {
|
|
246
|
+
emit("contextMenu", e);
|
|
247
|
+
},
|
|
248
|
+
onSelectionChange(e, v) {
|
|
249
|
+
handlers.selectionChange.forEach((y) => {
|
|
250
|
+
try {
|
|
251
|
+
y(e, v);
|
|
252
|
+
} catch (e) {
|
|
253
|
+
console.error("[GemiGo SDK] Error in selectionChange handler:", e);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const extensionAPI = {
|
|
225
260
|
getPageInfo: () => getHost().then((e) => e.getPageInfo()),
|
|
226
261
|
getPageHTML: () => getHost().then((e) => e.getPageHTML()),
|
|
227
262
|
getPageText: () => getHost().then((e) => e.getPageText()),
|
|
228
263
|
getSelection: () => getHost().then((e) => e.getSelection()),
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
264
|
+
extractArticle: () => getHost().then((e) => e.extractArticle()),
|
|
265
|
+
highlight: (e, v) => getHost().then((y) => y.highlight(e, v)),
|
|
266
|
+
removeHighlight: (e) => getHost().then((v) => v.removeHighlight(e)),
|
|
267
|
+
insertWidget: (e, v = "bottom-right") => getHost().then((y) => y.insertWidget({
|
|
268
|
+
html: e,
|
|
269
|
+
position: v
|
|
233
270
|
})),
|
|
271
|
+
updateWidget: (e, v) => getHost().then((y) => y.updateWidget(e, v)),
|
|
272
|
+
removeWidget: (e) => getHost().then((v) => v.removeWidget(e)),
|
|
273
|
+
injectCSS: (e) => getHost().then((v) => v.injectCSS(e)),
|
|
274
|
+
removeCSS: (e) => getHost().then((v) => v.removeCSS(e)),
|
|
275
|
+
extractLinks: () => getHost().then((e) => e.extractLinks()),
|
|
276
|
+
extractImages: () => getHost().then((e) => e.extractImages()),
|
|
277
|
+
queryElement: (e, v) => getHost().then((y) => y.queryElement(e, v)),
|
|
234
278
|
captureVisible: () => getHost().then((e) => e.captureVisible()),
|
|
235
|
-
extractArticle: () => getHost().then((e) => e.extractArticle()),
|
|
236
279
|
getContextMenuEvent: () => getHost().then((e) => e.getContextMenuEvent()),
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
},
|
|
240
|
-
off(e, f) {
|
|
241
|
-
if (e === "contextMenu") if (f) {
|
|
242
|
-
let e = eventHandlers.contextMenu.indexOf(f);
|
|
243
|
-
e > -1 && eventHandlers.contextMenu.splice(e, 1);
|
|
244
|
-
} else eventHandlers.contextMenu = [];
|
|
245
|
-
}
|
|
280
|
+
onContextMenu: (e) => (getHost(), on("contextMenu", e)),
|
|
281
|
+
onSelectionChange: (e) => (getHost(), on("selectionChange", e))
|
|
246
282
|
};
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
283
|
+
function createSDK() {
|
|
284
|
+
return {
|
|
285
|
+
notify: (e, v) => getHost().then((y) => y.notify({
|
|
286
|
+
title: e,
|
|
287
|
+
message: v
|
|
288
|
+
})),
|
|
289
|
+
extension: extensionAPI
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
var sdk = createSDK();
|
|
293
|
+
initConnection(getChildMethods());
|
|
294
|
+
var sdk_default = sdk;
|
|
295
|
+
export { sdk_default as default };
|
|
@@ -1 +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;(function(e){e.Call=`call`,e.Reply=`reply`,e.Syn=`syn`,e.SynAck=`synAck`,e.Ack=`ack`})(e||={});var t;(function(e){e.Fulfilled=`fulfilled`,e.Rejected=`rejected`})(t||={});var n;(function(e){e.ConnectionDestroyed=`ConnectionDestroyed`,e.ConnectionTimeout=`ConnectionTimeout`,e.NoIframeSrc=`NoIframeSrc`})(n||={});var r;(function(e){e.DataCloneError=`DataCloneError`})(r||={});var i;(function(e){e.Message=`message`})(i||={});var a=(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)}}},o=e=>(...t)=>{e&&console.log(`[Penpal]`,...t)};let s=({name:e,message:t,stack:n})=>({name:e,message:t,stack:n}),c=e=>{let t=Error();return Object.keys(e).forEach(n=>t[n]=e[n]),t};var l=(n,a,o)=>{let{localName:c,local:l,remote:u,originForSending:d,originForReceiving:f}=n,p=!1,m=n=>{if(n.source!==u||n.data.penpal!==e.Call)return;if(f!==`*`&&n.origin!==f){o(`${c} received message from origin ${n.origin} which did not match expected origin ${f}`);return}let{methodName:i,args:l,id:m}=n.data;o(`${c}: Received ${i}() call`);let h=n=>a=>{if(o(`${c}: Sending ${i}() reply`),p){o(`${c}: Unable to send ${i}() reply due to destroyed connection`);return}let l={penpal:e.Reply,id:m,resolution:n,returnValue:a};n===t.Rejected&&a instanceof Error&&(l.returnValue=s(a),l.returnValueIsError=!0);try{u.postMessage(l,d)}catch(n){if(n.name===r.DataCloneError){let r={penpal:e.Reply,id:m,resolution:t.Rejected,returnValue:s(n),returnValueIsError:!0};u.postMessage(r,d)}throw n}};new Promise(e=>e(a[i].apply(a,l))).then(h(t.Fulfilled),h(t.Rejected))};return l.addEventListener(i.Message,m),()=>{p=!0,l.removeEventListener(i.Message,m)}},u=0,d=()=>++u,f=`.`,p=e=>e?e.split(f):[],m=e=>e.join(f),h=(e,t)=>{let n=p(t||``);return n.push(e),m(n)};let g=(e,t,n)=>{let r=p(t);return r.reduce((e,t,i)=>(e[t]===void 0&&(e[t]={}),i===r.length-1&&(e[t]=n),e[t]),e),e},_=(e,t)=>{let n={};return Object.keys(e).forEach(r=>{let i=e[r],a=h(r,t);typeof i==`object`&&Object.assign(n,_(i,a)),typeof i==`function`&&(n[a]=i)}),n},v=e=>{let t={};for(let n in e)g(t,n,e[n]);return t};var y=(r,a,o,s,l)=>{let{localName:u,local:f,remote:p,originForSending:m,originForReceiving:h}=a,g=!1;l(`${u}: Connecting call sender`);let _=r=>(...a)=>{l(`${u}: Sending ${r}() call`);let o;try{p.closed&&(o=!0)}catch{o=!0}if(o&&s(),g){let e=Error(`Unable to send ${r}() call due to destroyed connection`);throw e.code=n.ConnectionDestroyed,e}return new Promise((n,o)=>{let s=d(),g=a=>{if(a.source!==p||a.data.penpal!==e.Reply||a.data.id!==s)return;if(h!==`*`&&a.origin!==h){l(`${u} received message from origin ${a.origin} which did not match expected origin ${h}`);return}let d=a.data;l(`${u}: Received ${r}() reply`),f.removeEventListener(i.Message,g);let m=d.returnValue;d.returnValueIsError&&(m=c(m)),(d.resolution===t.Fulfilled?n:o)(m)};f.addEventListener(i.Message,g);let _={penpal:e.Call,id:s,methodName:r,args:a};p.postMessage(_,m)})},y=o.reduce((e,t)=>(e[t]=_(t),e),{});return Object.assign(r,v(y)),()=>{g=!0}},b=(e,t)=>{let r;return e!==void 0&&(r=window.setTimeout(()=>{let r=Error(`Connection timed out after ${e}ms`);r.code=n.ConnectionTimeout,t(r)},e)),()=>{clearTimeout(r)}},x=(t,n,r,i)=>{let{destroy:a,onDestroy:o}=r;return r=>{if(!(t instanceof RegExp?t.test(r.origin):t===`*`||t===r.origin)){i(`Child: Handshake - Received SYN-ACK from origin ${r.origin} which did not match expected origin ${t}`);return}i(`Child: Handshake - Received SYN-ACK, responding with ACK`);let s=r.origin===`null`?`*`:r.origin,c={penpal:e.Ack,methodNames:Object.keys(n)};window.parent.postMessage(c,s);let u={localName:`Child`,local:window,remote:window.parent,originForSending:s,originForReceiving:r.origin};o(l(u,n,i));let d={};return o(y(d,u,r.data.methodNames,a,i)),d}},S=()=>{try{clearTimeout()}catch{return!1}return!0},C=(t={})=>{let{parentOrigin:n=`*`,methods:r={},timeout:s,debug:c=!1}=t,l=o(c),u=a(`Child`,l),{destroy:d,onDestroy:f}=u,p=x(n,_(r),u,l),m=()=>{l(`Child: Handshake - Sending SYN`);let t={penpal:e.Syn},r=n instanceof RegExp?`*`:n;window.parent.postMessage(t,r)};return{promise:new Promise((t,n)=>{let r=b(s,d),a=n=>{if(S()&&!(n.source!==parent||!n.data)&&n.data.penpal===e.SynAck){let e=p(n);e&&(window.removeEventListener(i.Message,a),r(),t(e))}};window.addEventListener(i.Message,a),m(),f(e=>{window.removeEventListener(i.Message,a),e&&n(e)})}),destroy(){d()}}},w=
|
|
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;(function(e){e.Call=`call`,e.Reply=`reply`,e.Syn=`syn`,e.SynAck=`synAck`,e.Ack=`ack`})(e||={});var t;(function(e){e.Fulfilled=`fulfilled`,e.Rejected=`rejected`})(t||={});var n;(function(e){e.ConnectionDestroyed=`ConnectionDestroyed`,e.ConnectionTimeout=`ConnectionTimeout`,e.NoIframeSrc=`NoIframeSrc`})(n||={});var r;(function(e){e.DataCloneError=`DataCloneError`})(r||={});var i;(function(e){e.Message=`message`})(i||={});var a=(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)}}},o=e=>(...t)=>{e&&console.log(`[Penpal]`,...t)};let s=({name:e,message:t,stack:n})=>({name:e,message:t,stack:n}),c=e=>{let t=Error();return Object.keys(e).forEach(n=>t[n]=e[n]),t};var l=(n,a,o)=>{let{localName:c,local:l,remote:u,originForSending:d,originForReceiving:f}=n,p=!1,m=n=>{if(n.source!==u||n.data.penpal!==e.Call)return;if(f!==`*`&&n.origin!==f){o(`${c} received message from origin ${n.origin} which did not match expected origin ${f}`);return}let{methodName:i,args:l,id:m}=n.data;o(`${c}: Received ${i}() call`);let h=n=>a=>{if(o(`${c}: Sending ${i}() reply`),p){o(`${c}: Unable to send ${i}() reply due to destroyed connection`);return}let l={penpal:e.Reply,id:m,resolution:n,returnValue:a};n===t.Rejected&&a instanceof Error&&(l.returnValue=s(a),l.returnValueIsError=!0);try{u.postMessage(l,d)}catch(n){if(n.name===r.DataCloneError){let r={penpal:e.Reply,id:m,resolution:t.Rejected,returnValue:s(n),returnValueIsError:!0};u.postMessage(r,d)}throw n}};new Promise(e=>e(a[i].apply(a,l))).then(h(t.Fulfilled),h(t.Rejected))};return l.addEventListener(i.Message,m),()=>{p=!0,l.removeEventListener(i.Message,m)}},u=0,d=()=>++u,f=`.`,p=e=>e?e.split(f):[],m=e=>e.join(f),h=(e,t)=>{let n=p(t||``);return n.push(e),m(n)};let g=(e,t,n)=>{let r=p(t);return r.reduce((e,t,i)=>(e[t]===void 0&&(e[t]={}),i===r.length-1&&(e[t]=n),e[t]),e),e},_=(e,t)=>{let n={};return Object.keys(e).forEach(r=>{let i=e[r],a=h(r,t);typeof i==`object`&&Object.assign(n,_(i,a)),typeof i==`function`&&(n[a]=i)}),n},v=e=>{let t={};for(let n in e)g(t,n,e[n]);return t};var y=(r,a,o,s,l)=>{let{localName:u,local:f,remote:p,originForSending:m,originForReceiving:h}=a,g=!1;l(`${u}: Connecting call sender`);let _=r=>(...a)=>{l(`${u}: Sending ${r}() call`);let o;try{p.closed&&(o=!0)}catch{o=!0}if(o&&s(),g){let e=Error(`Unable to send ${r}() call due to destroyed connection`);throw e.code=n.ConnectionDestroyed,e}return new Promise((n,o)=>{let s=d(),g=a=>{if(a.source!==p||a.data.penpal!==e.Reply||a.data.id!==s)return;if(h!==`*`&&a.origin!==h){l(`${u} received message from origin ${a.origin} which did not match expected origin ${h}`);return}let d=a.data;l(`${u}: Received ${r}() reply`),f.removeEventListener(i.Message,g);let m=d.returnValue;d.returnValueIsError&&(m=c(m)),(d.resolution===t.Fulfilled?n:o)(m)};f.addEventListener(i.Message,g);let _={penpal:e.Call,id:s,methodName:r,args:a};p.postMessage(_,m)})},y=o.reduce((e,t)=>(e[t]=_(t),e),{});return Object.assign(r,v(y)),()=>{g=!0}},b=(e,t)=>{let r;return e!==void 0&&(r=window.setTimeout(()=>{let r=Error(`Connection timed out after ${e}ms`);r.code=n.ConnectionTimeout,t(r)},e)),()=>{clearTimeout(r)}},x=(t,n,r,i)=>{let{destroy:a,onDestroy:o}=r;return r=>{if(!(t instanceof RegExp?t.test(r.origin):t===`*`||t===r.origin)){i(`Child: Handshake - Received SYN-ACK from origin ${r.origin} which did not match expected origin ${t}`);return}i(`Child: Handshake - Received SYN-ACK, responding with ACK`);let s=r.origin===`null`?`*`:r.origin,c={penpal:e.Ack,methodNames:Object.keys(n)};window.parent.postMessage(c,s);let u={localName:`Child`,local:window,remote:window.parent,originForSending:s,originForReceiving:r.origin};o(l(u,n,i));let d={};return o(y(d,u,r.data.methodNames,a,i)),d}},S=()=>{try{clearTimeout()}catch{return!1}return!0},C=(t={})=>{let{parentOrigin:n=`*`,methods:r={},timeout:s,debug:c=!1}=t,l=o(c),u=a(`Child`,l),{destroy:d,onDestroy:f}=u,p=x(n,_(r),u,l),m=()=>{l(`Child: Handshake - Sending SYN`);let t={penpal:e.Syn},r=n instanceof RegExp?`*`:n;window.parent.postMessage(t,r)};return{promise:new Promise((t,n)=>{let r=b(s,d),a=n=>{if(S()&&!(n.source!==parent||!n.data)&&n.data.penpal===e.SynAck){let e=p(n);e&&(window.removeEventListener(i.Message,a),r(),t(e))}};window.addEventListener(i.Message,a),m(),f(e=>{window.removeEventListener(i.Message,a),e&&n(e)})}),destroy(){d()}}},w=null;function T(){try{return window.self!==window.top}catch{return!0}}function E(e){if(w)return w;T()||console.warn(`[GemiGo SDK] Not running in iframe. SDK calls will not work.`);let t={};return e&&Object.assign(t,e),w=C({methods:t}).promise,w}function D(e){E(e).catch(e=>{console.debug(`[GemiGo SDK] Auto-connect waiting...`,e)})}var O={contextMenu:[],selectionChange:[]};function k(e,t){return O[e].push(t),()=>{let n=O[e].indexOf(t);n>-1&&O[e].splice(n,1)}}function A(e,t){O[e].forEach(n=>{try{n(t)}catch(t){console.error(`[GemiGo SDK] Error in ${e} handler:`,t)}})}function j(){return{onContextMenuEvent(e){A(`contextMenu`,e)},onSelectionChange(e,t){O.selectionChange.forEach(n=>{try{n(e,t)}catch(e){console.error(`[GemiGo SDK] Error in selectionChange handler:`,e)}})}}}let M={getPageInfo:()=>E().then(e=>e.getPageInfo()),getPageHTML:()=>E().then(e=>e.getPageHTML()),getPageText:()=>E().then(e=>e.getPageText()),getSelection:()=>E().then(e=>e.getSelection()),extractArticle:()=>E().then(e=>e.extractArticle()),highlight:(e,t)=>E().then(n=>n.highlight(e,t)),removeHighlight:e=>E().then(t=>t.removeHighlight(e)),insertWidget:(e,t=`bottom-right`)=>E().then(n=>n.insertWidget({html:e,position:t})),updateWidget:(e,t)=>E().then(n=>n.updateWidget(e,t)),removeWidget:e=>E().then(t=>t.removeWidget(e)),injectCSS:e=>E().then(t=>t.injectCSS(e)),removeCSS:e=>E().then(t=>t.removeCSS(e)),extractLinks:()=>E().then(e=>e.extractLinks()),extractImages:()=>E().then(e=>e.extractImages()),queryElement:(e,t)=>E().then(n=>n.queryElement(e,t)),captureVisible:()=>E().then(e=>e.captureVisible()),getContextMenuEvent:()=>E().then(e=>e.getContextMenuEvent()),onContextMenu:e=>(E(),k(`contextMenu`,e)),onSelectionChange:e=>(E(),k(`selectionChange`,e))};function N(){return{notify:(e,t)=>E().then(n=>n.notify({title:e,message:t})),extension:M}}var P=N();return D(j()),P});
|
package/dist/index.d.ts
CHANGED
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
* Usage (CDN):
|
|
7
7
|
* <script src="https://unpkg.com/@gemigo/extension-sdk/dist/gemigo-extension-sdk.umd.js"></script>
|
|
8
8
|
* <script>
|
|
9
|
-
* // No connect() needed - just use the global gemigo object directly
|
|
10
9
|
* gemigo.getPageInfo().then(console.log);
|
|
11
10
|
*
|
|
12
|
-
* gemigo.
|
|
11
|
+
* gemigo.extension.onContextMenu((event) => {
|
|
13
12
|
* console.log('Context menu clicked:', event);
|
|
14
13
|
* });
|
|
15
14
|
* </script>
|
|
@@ -19,63 +18,6 @@
|
|
|
19
18
|
*
|
|
20
19
|
* const pageInfo = await gemigo.getPageInfo();
|
|
21
20
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
pageUrl?: string;
|
|
26
|
-
}) => void;
|
|
27
|
-
export interface GemigoSDK {
|
|
28
|
-
/** Get current page information */
|
|
29
|
-
getPageInfo(): Promise<{
|
|
30
|
-
url: string;
|
|
31
|
-
title: string;
|
|
32
|
-
favIconUrl?: string;
|
|
33
|
-
}>;
|
|
34
|
-
/** Get full page HTML */
|
|
35
|
-
getPageHTML(): Promise<string>;
|
|
36
|
-
/** Get page text content */
|
|
37
|
-
getPageText(): Promise<string>;
|
|
38
|
-
/** Get selected text on page */
|
|
39
|
-
getSelection(): Promise<string>;
|
|
40
|
-
/** Highlight elements matching selector */
|
|
41
|
-
highlight(selector: string, color?: string): Promise<{
|
|
42
|
-
success: boolean;
|
|
43
|
-
count?: number;
|
|
44
|
-
}>;
|
|
45
|
-
/** Send system notification */
|
|
46
|
-
notify(title: string, message: string): Promise<{
|
|
47
|
-
success: boolean;
|
|
48
|
-
}>;
|
|
49
|
-
/** Capture visible tab screenshot */
|
|
50
|
-
captureVisible(): Promise<{
|
|
51
|
-
success: boolean;
|
|
52
|
-
dataUrl?: string;
|
|
53
|
-
error?: string;
|
|
54
|
-
}>;
|
|
55
|
-
/** Extract article content from page */
|
|
56
|
-
extractArticle(): Promise<{
|
|
57
|
-
success: boolean;
|
|
58
|
-
title?: string;
|
|
59
|
-
content?: string;
|
|
60
|
-
excerpt?: string;
|
|
61
|
-
url?: string;
|
|
62
|
-
}>;
|
|
63
|
-
/** Get pending context menu event (if any) */
|
|
64
|
-
getContextMenuEvent(): Promise<{
|
|
65
|
-
success: boolean;
|
|
66
|
-
event?: {
|
|
67
|
-
menuId: string;
|
|
68
|
-
selectionText?: string;
|
|
69
|
-
pageUrl?: string;
|
|
70
|
-
};
|
|
71
|
-
}>;
|
|
72
|
-
/** Register context menu event handler */
|
|
73
|
-
on(event: 'contextMenu', handler: ContextMenuEventHandler): void;
|
|
74
|
-
/** Unregister event handler */
|
|
75
|
-
off(event: 'contextMenu', handler?: ContextMenuEventHandler): void;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Proxy handler to auto-connect on method calls
|
|
79
|
-
*/
|
|
80
|
-
declare const sdkInstance: GemigoSDK;
|
|
81
|
-
export default sdkInstance;
|
|
21
|
+
export * from './types';
|
|
22
|
+
export { default } from './sdk';
|
|
23
|
+
export type { SDKInstance } from './sdk';
|
package/dist/sdk.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { extensionAPI } from './apis';
|
|
2
|
+
/**
|
|
3
|
+
* SDK interface for current implementation
|
|
4
|
+
* (Subset of full GemigoSDK - only extension platform is implemented)
|
|
5
|
+
*/
|
|
6
|
+
export interface SDKInstance {
|
|
7
|
+
/** Send system notification */
|
|
8
|
+
notify(title: string, message: string): Promise<{
|
|
9
|
+
success: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
/** Extension-specific APIs */
|
|
12
|
+
extension: typeof extensionAPI;
|
|
13
|
+
}
|
|
14
|
+
declare const sdk: SDKInstance;
|
|
15
|
+
export default sdk;
|
|
@@ -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
|
+
}
|