@gemigo/extension-sdk 0.1.0 → 0.1.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.
@@ -202,9 +202,16 @@ var connectCallSender_default = (m, g, _, v, b) => {
202
202
  S();
203
203
  }
204
204
  };
205
- }, eventHandlers = { contextMenu: [] }, connection = null, hostMethods = null;
206
- async function connect() {
207
- return hostMethods ? createSDKInstance(hostMethods) : (connection = connectToParent_default({ methods: { onContextMenuEvent(e) {
205
+ }, eventHandlers = { contextMenu: [] }, connectionPromise = null;
206
+ function isInIframe() {
207
+ try {
208
+ return window.self !== window.top;
209
+ } catch {
210
+ return !0;
211
+ }
212
+ }
213
+ function getHost() {
214
+ return connectionPromise || (isInIframe() || console.warn("[GemiGo SDK] Not running in iframe. SDK calls will verify connection forever."), connectionPromise = connectToParent_default({ methods: { onContextMenuEvent(e) {
208
215
  eventHandlers.contextMenu.forEach((f) => {
209
216
  try {
210
217
  f(e);
@@ -212,32 +219,33 @@ async function connect() {
212
219
  console.error("[GemiGo SDK] Error in contextMenu handler:", e);
213
220
  }
214
221
  });
215
- } } }), hostMethods = await connection.promise, createSDKInstance(hostMethods));
216
- }
217
- function createSDKInstance(e) {
218
- return {
219
- getPageInfo: () => e.getPageInfo(),
220
- getPageHTML: () => e.getPageHTML(),
221
- getPageText: () => e.getPageText(),
222
- getSelection: () => e.getSelection(),
223
- highlight: (f, p) => e.highlight(f, p),
224
- notify: (f, p) => e.notify({
225
- title: f,
226
- message: p
227
- }),
228
- captureVisible: () => e.captureVisible(),
229
- extractArticle: () => e.extractArticle(),
230
- getContextMenuEvent: () => e.getContextMenuEvent(),
231
- on(e, f) {
232
- e === "contextMenu" && eventHandlers.contextMenu.push(f);
233
- },
234
- off(e, f) {
235
- if (e === "contextMenu") if (f) {
236
- let e = eventHandlers.contextMenu.indexOf(f);
237
- e > -1 && eventHandlers.contextMenu.splice(e, 1);
238
- } else eventHandlers.contextMenu = [];
239
- }
240
- };
222
+ } } }).promise, connectionPromise);
241
223
  }
242
- var src_default = { connect };
243
- export { connect, src_default as default };
224
+ var sdkInstance = {
225
+ getPageInfo: () => getHost().then((e) => e.getPageInfo()),
226
+ getPageHTML: () => getHost().then((e) => e.getPageHTML()),
227
+ getPageText: () => getHost().then((e) => e.getPageText()),
228
+ getSelection: () => getHost().then((e) => e.getSelection()),
229
+ highlight: (e, f) => getHost().then((p) => p.highlight(e, f)),
230
+ notify: (e, f) => getHost().then((p) => p.notify({
231
+ title: e,
232
+ message: f
233
+ })),
234
+ captureVisible: () => getHost().then((e) => e.captureVisible()),
235
+ extractArticle: () => getHost().then((e) => e.extractArticle()),
236
+ getContextMenuEvent: () => getHost().then((e) => e.getContextMenuEvent()),
237
+ on(e, f) {
238
+ getHost(), e === "contextMenu" && eventHandlers.contextMenu.push(f);
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
+ }
246
+ };
247
+ getHost().catch((e) => {
248
+ console.debug("[GemiGo SDK] Auto-connect waiting...", e);
249
+ });
250
+ var src_default = sdkInstance;
251
+ export { src_default as default };
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.GemigoExtensionSDK={}))})(this,function(e){Object.defineProperty(e,`__esModule`,{value:!0});var t;(function(e){e.Call=`call`,e.Reply=`reply`,e.Syn=`syn`,e.SynAck=`synAck`,e.Ack=`ack`})(t||={});var n;(function(e){e.Fulfilled=`fulfilled`,e.Rejected=`rejected`})(n||={});var r;(function(e){e.ConnectionDestroyed=`ConnectionDestroyed`,e.ConnectionTimeout=`ConnectionTimeout`,e.NoIframeSrc=`NoIframeSrc`})(r||={});var i;(function(e){e.DataCloneError=`DataCloneError`})(i||={});var a;(function(e){e.Message=`message`})(a||={});var o=(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)}}},s=e=>(...t)=>{e&&console.log(`[Penpal]`,...t)};let c=({name:e,message:t,stack:n})=>({name:e,message:t,stack:n}),l=e=>{let t=Error();return Object.keys(e).forEach(n=>t[n]=e[n]),t};var u=(e,r,o)=>{let{localName:s,local:l,remote:u,originForSending:d,originForReceiving:f}=e,p=!1,m=e=>{if(e.source!==u||e.data.penpal!==t.Call)return;if(f!==`*`&&e.origin!==f){o(`${s} received message from origin ${e.origin} which did not match expected origin ${f}`);return}let{methodName:a,args:l,id:m}=e.data;o(`${s}: Received ${a}() call`);let h=e=>r=>{if(o(`${s}: Sending ${a}() reply`),p){o(`${s}: Unable to send ${a}() reply due to destroyed connection`);return}let l={penpal:t.Reply,id:m,resolution:e,returnValue:r};e===n.Rejected&&r instanceof Error&&(l.returnValue=c(r),l.returnValueIsError=!0);try{u.postMessage(l,d)}catch(e){if(e.name===i.DataCloneError){let r={penpal:t.Reply,id:m,resolution:n.Rejected,returnValue:c(e),returnValueIsError:!0};u.postMessage(r,d)}throw e}};new Promise(e=>e(r[a].apply(r,l))).then(h(n.Fulfilled),h(n.Rejected))};return l.addEventListener(a.Message,m),()=>{p=!0,l.removeEventListener(a.Message,m)}},d=0,f=()=>++d,p=`.`,m=e=>e?e.split(p):[],h=e=>e.join(p),g=(e,t)=>{let n=m(t||``);return n.push(e),h(n)};let _=(e,t,n)=>{let r=m(t);return r.reduce((e,t,i)=>(e[t]===void 0&&(e[t]={}),i===r.length-1&&(e[t]=n),e[t]),e),e},v=(e,t)=>{let n={};return Object.keys(e).forEach(r=>{let i=e[r],a=g(r,t);typeof i==`object`&&Object.assign(n,v(i,a)),typeof i==`function`&&(n[a]=i)}),n},y=e=>{let t={};for(let n in e)_(t,n,e[n]);return t};var b=(e,i,o,s,c)=>{let{localName:u,local:d,remote:p,originForSending:m,originForReceiving:h}=i,g=!1;c(`${u}: Connecting call sender`);let _=e=>(...i)=>{c(`${u}: Sending ${e}() call`);let o;try{p.closed&&(o=!0)}catch{o=!0}if(o&&s(),g){let t=Error(`Unable to send ${e}() call due to destroyed connection`);throw t.code=r.ConnectionDestroyed,t}return new Promise((r,o)=>{let s=f(),g=i=>{if(i.source!==p||i.data.penpal!==t.Reply||i.data.id!==s)return;if(h!==`*`&&i.origin!==h){c(`${u} received message from origin ${i.origin} which did not match expected origin ${h}`);return}let f=i.data;c(`${u}: Received ${e}() reply`),d.removeEventListener(a.Message,g);let m=f.returnValue;f.returnValueIsError&&(m=l(m)),(f.resolution===n.Fulfilled?r:o)(m)};d.addEventListener(a.Message,g);let _={penpal:t.Call,id:s,methodName:e,args:i};p.postMessage(_,m)})},v=o.reduce((e,t)=>(e[t]=_(t),e),{});return Object.assign(e,y(v)),()=>{g=!0}},x=(e,t)=>{let n;return e!==void 0&&(n=window.setTimeout(()=>{let n=Error(`Connection timed out after ${e}ms`);n.code=r.ConnectionTimeout,t(n)},e)),()=>{clearTimeout(n)}},S=(e,n,r,i)=>{let{destroy:a,onDestroy:o}=r;return r=>{if(!(e instanceof RegExp?e.test(r.origin):e===`*`||e===r.origin)){i(`Child: Handshake - Received SYN-ACK from origin ${r.origin} which did not match expected origin ${e}`);return}i(`Child: Handshake - Received SYN-ACK, responding with ACK`);let s=r.origin===`null`?`*`:r.origin,c={penpal:t.Ack,methodNames:Object.keys(n)};window.parent.postMessage(c,s);let l={localName:`Child`,local:window,remote:window.parent,originForSending:s,originForReceiving:r.origin};o(u(l,n,i));let d={};return o(b(d,l,r.data.methodNames,a,i)),d}},C=()=>{try{clearTimeout()}catch{return!1}return!0},w=(e={})=>{let{parentOrigin:n=`*`,methods:r={},timeout:i,debug:c=!1}=e,l=s(c),u=o(`Child`,l),{destroy:d,onDestroy:f}=u,p=S(n,v(r),u,l),m=()=>{l(`Child: Handshake - Sending SYN`);let e={penpal:t.Syn},r=n instanceof RegExp?`*`:n;window.parent.postMessage(e,r)};return{promise:new Promise((e,n)=>{let r=x(i,d),o=n=>{if(C()&&!(n.source!==parent||!n.data)&&n.data.penpal===t.SynAck){let t=p(n);t&&(window.removeEventListener(a.Message,o),r(),e(t))}};window.addEventListener(a.Message,o),m(),f(e=>{window.removeEventListener(a.Message,o),e&&n(e)})}),destroy(){d()}}},T={contextMenu:[]},E=null,D=null;async function O(){return D?k(D):(E=w({methods:{onContextMenuEvent(e){T.contextMenu.forEach(t=>{try{t(e)}catch(e){console.error(`[GemiGo SDK] Error in contextMenu handler:`,e)}})}}}),D=await E.promise,k(D))}function k(e){return{getPageInfo:()=>e.getPageInfo(),getPageHTML:()=>e.getPageHTML(),getPageText:()=>e.getPageText(),getSelection:()=>e.getSelection(),highlight:(t,n)=>e.highlight(t,n),notify:(t,n)=>e.notify({title:t,message:n}),captureVisible:()=>e.captureVisible(),extractArticle:()=>e.extractArticle(),getContextMenuEvent:()=>e.getContextMenuEvent(),on(e,t){e===`contextMenu`&&T.contextMenu.push(t)},off(e,t){if(e===`contextMenu`)if(t){let e=T.contextMenu.indexOf(t);e>-1&&T.contextMenu.splice(e,1)}else T.contextMenu=[]}}}var A={connect:O};e.connect=O,e.default=A});
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.GemigoExtensionSDK=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={contextMenu:[]},T=null;function E(){try{return window.self!==window.top}catch{return!0}}function D(){return T||(E()||console.warn(`[GemiGo SDK] Not running in iframe. SDK calls will verify connection forever.`),T=C({methods:{onContextMenuEvent(e){w.contextMenu.forEach(t=>{try{t(e)}catch(e){console.error(`[GemiGo SDK] Error in contextMenu handler:`,e)}})}}}).promise,T)}return D().catch(e=>{console.debug(`[GemiGo SDK] Auto-connect waiting...`,e)}),{getPageInfo:()=>D().then(e=>e.getPageInfo()),getPageHTML:()=>D().then(e=>e.getPageHTML()),getPageText:()=>D().then(e=>e.getPageText()),getSelection:()=>D().then(e=>e.getSelection()),highlight:(e,t)=>D().then(n=>n.highlight(e,t)),notify:(e,t)=>D().then(n=>n.notify({title:e,message:t})),captureVisible:()=>D().then(e=>e.captureVisible()),extractArticle:()=>D().then(e=>e.extractArticle()),getContextMenuEvent:()=>D().then(e=>e.getContextMenuEvent()),on(e,t){D(),e===`contextMenu`&&w.contextMenu.push(t)},off(e,t){if(e===`contextMenu`)if(t){let e=w.contextMenu.indexOf(t);e>-1&&w.contextMenu.splice(e,1)}else w.contextMenu=[]}}});
package/dist/index.d.ts CHANGED
@@ -4,16 +4,19 @@
4
4
  * SDK for building apps that run inside the GemiGo browser extension.
5
5
  *
6
6
  * Usage (CDN):
7
- * <script src="https://cdn.example.com/gemigo-extension-sdk.umd.js"></script>
7
+ * <script src="https://unpkg.com/@gemigo/extension-sdk/dist/gemigo-extension-sdk.umd.js"></script>
8
8
  * <script>
9
- * GemigoExtensionSDK.connect().then((gemigo) => {
10
- * gemigo.getPageInfo().then(console.log);
9
+ * // No connect() needed - just use the global gemigo object
10
+ * gemigo.getPageInfo().then(console.log);
11
+ *
12
+ * gemigo.on('contextMenu', (event) => {
13
+ * console.log('Context menu clicked:', event);
11
14
  * });
12
15
  * </script>
13
16
  *
14
17
  * Usage (ES Module):
15
- * import { connect } from '@gemigo/extension-sdk';
16
- * const gemigo = await connect();
18
+ * import gemigo from '@gemigo/extension-sdk';
19
+ *
17
20
  * const pageInfo = await gemigo.getPageInfo();
18
21
  */
19
22
  type ContextMenuEventHandler = (event: {
@@ -21,7 +24,7 @@ type ContextMenuEventHandler = (event: {
21
24
  selectionText?: string;
22
25
  pageUrl?: string;
23
26
  }) => void;
24
- export interface GemigoExtension {
27
+ export interface GemigoSDK {
25
28
  /** Get current page information */
26
29
  getPageInfo(): Promise<{
27
30
  url: string;
@@ -72,13 +75,7 @@ export interface GemigoExtension {
72
75
  off(event: 'contextMenu', handler?: ContextMenuEventHandler): void;
73
76
  }
74
77
  /**
75
- * Connect to the GemiGo extension host.
76
- * Must be called before using any SDK methods.
77
- *
78
- * @returns Promise resolving to the GemiGo SDK instance
78
+ * Proxy handler to auto-connect on method calls
79
79
  */
80
- export declare function connect(): Promise<GemigoExtension>;
81
- declare const _default: {
82
- connect: typeof connect;
83
- };
84
- export default _default;
80
+ declare const sdkInstance: GemigoSDK;
81
+ export default sdkInstance;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gemigo/extension-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "GemiGo Extension SDK for browser extension apps",
5
5
  "main": "dist/gemigo-extension-sdk.umd.js",
6
6
  "module": "dist/gemigo-extension-sdk.es.js",