@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
package/README.md
CHANGED
|
@@ -4,17 +4,12 @@ GemiGo Extension SDK for building apps that run inside the GemiGo browser extens
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
### CDN (Recommended
|
|
7
|
+
### CDN (Recommended)
|
|
8
8
|
|
|
9
9
|
```html
|
|
10
10
|
<script src="https://unpkg.com/@gemigo/extension-sdk/dist/gemigo-extension-sdk.umd.js"></script>
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Or use jsDelivr:
|
|
14
|
-
```html
|
|
15
|
-
<script src="https://cdn.jsdelivr.net/npm/@gemigo/extension-sdk/dist/gemigo-extension-sdk.umd.js"></script>
|
|
16
|
-
```
|
|
17
|
-
|
|
18
13
|
### npm
|
|
19
14
|
|
|
20
15
|
```bash
|
|
@@ -23,39 +18,22 @@ npm install @gemigo/extension-sdk
|
|
|
23
18
|
|
|
24
19
|
## Quick Start
|
|
25
20
|
|
|
26
|
-
### CDN Usage
|
|
27
|
-
|
|
28
21
|
```html
|
|
29
22
|
<script src="https://unpkg.com/@gemigo/extension-sdk/dist/gemigo-extension-sdk.umd.js"></script>
|
|
30
23
|
<script>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log('Menu clicked:', event.menuId, event.selectionText);
|
|
38
|
-
});
|
|
24
|
+
// SDK auto-connects, use gemigo.extension.* APIs directly
|
|
25
|
+
gemigo.extension.getPageInfo().then(console.log);
|
|
26
|
+
|
|
27
|
+
// Subscribe to context menu events
|
|
28
|
+
gemigo.extension.onContextMenu((event) => {
|
|
29
|
+
console.log('Menu clicked:', event.menuId, event.selectionText);
|
|
39
30
|
});
|
|
40
31
|
</script>
|
|
41
32
|
```
|
|
42
33
|
|
|
43
|
-
### ES Module Usage
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
import { connect } from '@gemigo/extension-sdk';
|
|
47
|
-
|
|
48
|
-
const gemigo = await connect();
|
|
49
|
-
const pageInfo = await gemigo.getPageInfo();
|
|
50
|
-
```
|
|
51
|
-
|
|
52
34
|
## API Reference
|
|
53
35
|
|
|
54
|
-
###
|
|
55
|
-
|
|
56
|
-
Connect to the GemiGo extension host. Must be called before using any SDK methods.
|
|
57
|
-
|
|
58
|
-
### Page APIs
|
|
36
|
+
### Page Content Reading
|
|
59
37
|
|
|
60
38
|
| Method | Description |
|
|
61
39
|
|--------|-------------|
|
|
@@ -64,49 +42,73 @@ Connect to the GemiGo extension host. Must be called before using any SDK method
|
|
|
64
42
|
| `getPageText()` | Get page text content |
|
|
65
43
|
| `getSelection()` | Get selected text |
|
|
66
44
|
| `extractArticle()` | Extract article title, content, excerpt |
|
|
45
|
+
| `extractLinks()` | Extract all links from page |
|
|
46
|
+
| `extractImages()` | Extract all images from page |
|
|
47
|
+
| `queryElement(selector, limit?)` | Query elements by CSS selector |
|
|
48
|
+
|
|
49
|
+
### Page Manipulation
|
|
50
|
+
|
|
51
|
+
| Method | Description |
|
|
52
|
+
|--------|-------------|
|
|
53
|
+
| `highlight(selector, color?)` | Highlight elements (returns highlightId) |
|
|
54
|
+
| `removeHighlight(highlightId)` | Remove highlight |
|
|
55
|
+
| `insertWidget(html, position)` | Insert floating widget |
|
|
56
|
+
| `updateWidget(widgetId, html)` | Update widget content |
|
|
57
|
+
| `removeWidget(widgetId)` | Remove widget |
|
|
58
|
+
| `injectCSS(css)` | Inject CSS (returns styleId) |
|
|
59
|
+
| `removeCSS(styleId)` | Remove injected CSS |
|
|
67
60
|
|
|
68
|
-
###
|
|
61
|
+
### Screenshots
|
|
69
62
|
|
|
70
63
|
| Method | Description |
|
|
71
64
|
|--------|-------------|
|
|
72
|
-
| `
|
|
73
|
-
| `notify(title, message)` | Send system notification |
|
|
74
|
-
| `captureVisible()` | Capture screenshot of visible tab |
|
|
65
|
+
| `captureVisible()` | Capture visible area screenshot |
|
|
75
66
|
|
|
76
|
-
###
|
|
67
|
+
### Events
|
|
77
68
|
|
|
78
69
|
| Method | Description |
|
|
79
70
|
|--------|-------------|
|
|
80
|
-
| `
|
|
81
|
-
| `off('contextMenu', handler?)` | Unsubscribe from events |
|
|
71
|
+
| `onContextMenu(handler)` | Subscribe to context menu events |
|
|
82
72
|
| `getContextMenuEvent()` | Get pending context menu event |
|
|
83
73
|
|
|
84
|
-
|
|
74
|
+
### Common APIs
|
|
75
|
+
|
|
76
|
+
| Method | Description |
|
|
77
|
+
|--------|-------------|
|
|
78
|
+
| `gemigo.notify(title, message)` | Send system notification |
|
|
79
|
+
|
|
80
|
+
## Example: Translation Bubble
|
|
85
81
|
|
|
86
82
|
```html
|
|
87
|
-
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
83
|
+
<script src="https://unpkg.com/@gemigo/extension-sdk/dist/gemigo-extension-sdk.umd.js"></script>
|
|
84
|
+
<script>
|
|
85
|
+
gemigo.extension.onContextMenu(async (event) => {
|
|
86
|
+
if (event.selectionText) {
|
|
87
|
+
const translated = await translateText(event.selectionText);
|
|
88
|
+
|
|
89
|
+
// Show translation bubble on page
|
|
90
|
+
await gemigo.extension.insertWidget(
|
|
91
|
+
`<div style="background:#667eea;color:#fff;padding:16px;border-radius:12px;">
|
|
92
|
+
${translated}
|
|
93
|
+
</div>`,
|
|
94
|
+
'bottom-right'
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
</script>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Example: Reader Mode
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// Inject reader-friendly CSS
|
|
105
|
+
const { styleId } = await gemigo.extension.injectCSS(`
|
|
106
|
+
body { max-width: 720px; margin: 0 auto; font-family: Georgia, serif; }
|
|
107
|
+
nav, aside, .ads { display: none !important; }
|
|
108
|
+
`);
|
|
109
|
+
|
|
110
|
+
// Remove later
|
|
111
|
+
await gemigo.extension.removeCSS(styleId);
|
|
110
112
|
```
|
|
111
113
|
|
|
112
114
|
## License
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { ContextMenuEvent, ContextMenuEventResult, CaptureResult } from '../types';
|
|
2
|
+
/** Widget insertion result */
|
|
3
|
+
export interface WidgetResult {
|
|
4
|
+
success: boolean;
|
|
5
|
+
widgetId?: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
/** CSS injection result */
|
|
9
|
+
export interface CSSResult {
|
|
10
|
+
success: boolean;
|
|
11
|
+
styleId?: string;
|
|
12
|
+
error?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Highlight result with cleanup ID */
|
|
15
|
+
export interface HighlightResult {
|
|
16
|
+
success: boolean;
|
|
17
|
+
count?: number;
|
|
18
|
+
highlightId?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extension API object
|
|
22
|
+
*/
|
|
23
|
+
export declare const extensionAPI: {
|
|
24
|
+
/**
|
|
25
|
+
* Get current page info
|
|
26
|
+
*/
|
|
27
|
+
getPageInfo: () => Promise<{
|
|
28
|
+
url: string;
|
|
29
|
+
title: string;
|
|
30
|
+
favIconUrl?: string;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Get full page HTML
|
|
34
|
+
*/
|
|
35
|
+
getPageHTML: () => Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Get page text content
|
|
38
|
+
*/
|
|
39
|
+
getPageText: () => Promise<string>;
|
|
40
|
+
/**
|
|
41
|
+
* Get selected text
|
|
42
|
+
*/
|
|
43
|
+
getSelection: () => Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Extract article content
|
|
46
|
+
*/
|
|
47
|
+
extractArticle: () => Promise<{
|
|
48
|
+
success: boolean;
|
|
49
|
+
title?: string;
|
|
50
|
+
content?: string;
|
|
51
|
+
excerpt?: string;
|
|
52
|
+
url?: string;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Highlight elements matching selector
|
|
56
|
+
* @returns Result with highlightId for cleanup
|
|
57
|
+
*/
|
|
58
|
+
highlight: (selector: string, color?: string) => Promise<HighlightResult>;
|
|
59
|
+
/**
|
|
60
|
+
* Remove highlight by ID
|
|
61
|
+
*/
|
|
62
|
+
removeHighlight: (highlightId: string) => Promise<{
|
|
63
|
+
success: boolean;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Insert a widget (floating element) in the page
|
|
67
|
+
* @param html - HTML content of the widget
|
|
68
|
+
* @param position - 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | { x, y }
|
|
69
|
+
*/
|
|
70
|
+
insertWidget: (html: string, position?: string | {
|
|
71
|
+
x: number;
|
|
72
|
+
y: number;
|
|
73
|
+
}) => Promise<WidgetResult>;
|
|
74
|
+
/**
|
|
75
|
+
* Update widget content
|
|
76
|
+
*/
|
|
77
|
+
updateWidget: (widgetId: string, html: string) => Promise<{
|
|
78
|
+
success: boolean;
|
|
79
|
+
error?: string;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Remove a widget
|
|
83
|
+
*/
|
|
84
|
+
removeWidget: (widgetId: string) => Promise<{
|
|
85
|
+
success: boolean;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Inject CSS into the page
|
|
89
|
+
* @returns Result with styleId for cleanup
|
|
90
|
+
*/
|
|
91
|
+
injectCSS: (css: string) => Promise<CSSResult>;
|
|
92
|
+
/**
|
|
93
|
+
* Remove injected CSS by ID
|
|
94
|
+
*/
|
|
95
|
+
removeCSS: (styleId: string) => Promise<{
|
|
96
|
+
success: boolean;
|
|
97
|
+
}>;
|
|
98
|
+
/**
|
|
99
|
+
* Extract all links from the page
|
|
100
|
+
*/
|
|
101
|
+
extractLinks: () => Promise<{
|
|
102
|
+
success: boolean;
|
|
103
|
+
links?: {
|
|
104
|
+
href: string;
|
|
105
|
+
text: string;
|
|
106
|
+
title?: string;
|
|
107
|
+
}[];
|
|
108
|
+
error?: string;
|
|
109
|
+
}>;
|
|
110
|
+
/**
|
|
111
|
+
* Extract all images from the page
|
|
112
|
+
*/
|
|
113
|
+
extractImages: () => Promise<{
|
|
114
|
+
success: boolean;
|
|
115
|
+
images?: {
|
|
116
|
+
src: string;
|
|
117
|
+
alt?: string;
|
|
118
|
+
width?: number;
|
|
119
|
+
height?: number;
|
|
120
|
+
}[];
|
|
121
|
+
error?: string;
|
|
122
|
+
}>;
|
|
123
|
+
/**
|
|
124
|
+
* Query elements by CSS selector
|
|
125
|
+
* @param selector - CSS selector
|
|
126
|
+
* @param limit - Max number of results (default 100)
|
|
127
|
+
*/
|
|
128
|
+
queryElement: (selector: string, limit?: number) => Promise<{
|
|
129
|
+
success: boolean;
|
|
130
|
+
elements?: {
|
|
131
|
+
tagName: string;
|
|
132
|
+
text: string;
|
|
133
|
+
attributes: Record<string, string>;
|
|
134
|
+
}[];
|
|
135
|
+
count?: number;
|
|
136
|
+
error?: string;
|
|
137
|
+
}>;
|
|
138
|
+
/**
|
|
139
|
+
* Capture visible area
|
|
140
|
+
*/
|
|
141
|
+
captureVisible: () => Promise<CaptureResult>;
|
|
142
|
+
/**
|
|
143
|
+
* Get pending context menu event
|
|
144
|
+
*/
|
|
145
|
+
getContextMenuEvent: () => Promise<ContextMenuEventResult>;
|
|
146
|
+
/**
|
|
147
|
+
* Register context menu event handler
|
|
148
|
+
*/
|
|
149
|
+
onContextMenu: (handler: (event: ContextMenuEvent) => void) => (() => void);
|
|
150
|
+
/**
|
|
151
|
+
* Register selection change event handler
|
|
152
|
+
* @returns Unsubscribe function
|
|
153
|
+
*/
|
|
154
|
+
onSelectionChange: (handler: (selection: string, url?: string) => void) => (() => void);
|
|
155
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { AsyncMethodReturns } from 'penpal';
|
|
2
|
+
import { ContextMenuEvent } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Host methods interface - what the extension provides to apps
|
|
5
|
+
*/
|
|
6
|
+
export interface HostMethods {
|
|
7
|
+
getPageInfo(): Promise<{
|
|
8
|
+
url: string;
|
|
9
|
+
title: string;
|
|
10
|
+
favIconUrl?: string;
|
|
11
|
+
}>;
|
|
12
|
+
getPageHTML(): Promise<string>;
|
|
13
|
+
getPageText(): Promise<string>;
|
|
14
|
+
getSelection(): Promise<string>;
|
|
15
|
+
highlight(selector: string, color?: string): Promise<{
|
|
16
|
+
success: boolean;
|
|
17
|
+
count?: number;
|
|
18
|
+
highlightId?: string;
|
|
19
|
+
}>;
|
|
20
|
+
removeHighlight(highlightId: string): Promise<{
|
|
21
|
+
success: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
insertWidget(config: {
|
|
24
|
+
html: string;
|
|
25
|
+
position: string | {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
};
|
|
29
|
+
}): Promise<{
|
|
30
|
+
success: boolean;
|
|
31
|
+
widgetId?: string;
|
|
32
|
+
error?: string;
|
|
33
|
+
}>;
|
|
34
|
+
updateWidget(widgetId: string, html: string): Promise<{
|
|
35
|
+
success: boolean;
|
|
36
|
+
error?: string;
|
|
37
|
+
}>;
|
|
38
|
+
removeWidget(widgetId: string): Promise<{
|
|
39
|
+
success: boolean;
|
|
40
|
+
}>;
|
|
41
|
+
injectCSS(css: string): Promise<{
|
|
42
|
+
success: boolean;
|
|
43
|
+
styleId?: string;
|
|
44
|
+
error?: string;
|
|
45
|
+
}>;
|
|
46
|
+
removeCSS(styleId: string): Promise<{
|
|
47
|
+
success: boolean;
|
|
48
|
+
}>;
|
|
49
|
+
notify(options: {
|
|
50
|
+
title: string;
|
|
51
|
+
message: string;
|
|
52
|
+
}): Promise<{
|
|
53
|
+
success: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
captureVisible(): Promise<{
|
|
56
|
+
success: boolean;
|
|
57
|
+
dataUrl?: string;
|
|
58
|
+
error?: string;
|
|
59
|
+
}>;
|
|
60
|
+
extractArticle(): Promise<{
|
|
61
|
+
success: boolean;
|
|
62
|
+
title?: string;
|
|
63
|
+
content?: string;
|
|
64
|
+
excerpt?: string;
|
|
65
|
+
url?: string;
|
|
66
|
+
}>;
|
|
67
|
+
extractLinks(): Promise<{
|
|
68
|
+
success: boolean;
|
|
69
|
+
links?: {
|
|
70
|
+
href: string;
|
|
71
|
+
text: string;
|
|
72
|
+
title?: string;
|
|
73
|
+
}[];
|
|
74
|
+
error?: string;
|
|
75
|
+
}>;
|
|
76
|
+
extractImages(): Promise<{
|
|
77
|
+
success: boolean;
|
|
78
|
+
images?: {
|
|
79
|
+
src: string;
|
|
80
|
+
alt?: string;
|
|
81
|
+
width?: number;
|
|
82
|
+
height?: number;
|
|
83
|
+
}[];
|
|
84
|
+
error?: string;
|
|
85
|
+
}>;
|
|
86
|
+
queryElement(selector: string, limit?: number): Promise<{
|
|
87
|
+
success: boolean;
|
|
88
|
+
elements?: {
|
|
89
|
+
tagName: string;
|
|
90
|
+
text: string;
|
|
91
|
+
attributes: Record<string, string>;
|
|
92
|
+
}[];
|
|
93
|
+
count?: number;
|
|
94
|
+
error?: string;
|
|
95
|
+
}>;
|
|
96
|
+
getContextMenuEvent(): Promise<{
|
|
97
|
+
success: boolean;
|
|
98
|
+
event?: ContextMenuEvent;
|
|
99
|
+
}>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Child methods interface - what apps expose to the extension host
|
|
103
|
+
*/
|
|
104
|
+
export interface ChildMethods {
|
|
105
|
+
onContextMenuEvent(event: ContextMenuEvent): void;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get or create connection to parent (extension host)
|
|
109
|
+
*
|
|
110
|
+
* @param childMethods - Methods to expose to parent
|
|
111
|
+
* @returns Promise resolving to host methods
|
|
112
|
+
*/
|
|
113
|
+
export declare function getHost(childMethods?: ChildMethods): Promise<AsyncMethodReturns<HostMethods>>;
|
|
114
|
+
/**
|
|
115
|
+
* Initialize connection immediately (for faster first call)
|
|
116
|
+
*/
|
|
117
|
+
export declare function initConnection(childMethods?: ChildMethods): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ContextMenuEvent } from '../types';
|
|
2
|
+
/** Selection change event */
|
|
3
|
+
export interface SelectionChangeEvent {
|
|
4
|
+
selection: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Event handler type map */
|
|
8
|
+
export interface EventHandlerMap {
|
|
9
|
+
contextMenu: (event: ContextMenuEvent) => void;
|
|
10
|
+
selectionChange: (selection: string, url?: string) => void;
|
|
11
|
+
}
|
|
12
|
+
/** Event names */
|
|
13
|
+
export type EventName = keyof EventHandlerMap;
|
|
14
|
+
/**
|
|
15
|
+
* Register an event handler
|
|
16
|
+
*
|
|
17
|
+
* @param event - Event name
|
|
18
|
+
* @param handler - Handler function
|
|
19
|
+
* @returns Unsubscribe function
|
|
20
|
+
*/
|
|
21
|
+
export declare function on<K extends EventName>(event: K, handler: EventHandlerMap[K]): () => void;
|
|
22
|
+
/**
|
|
23
|
+
* Emit an event to all registered handlers
|
|
24
|
+
*
|
|
25
|
+
* @param event - Event name
|
|
26
|
+
* @param data - Event data
|
|
27
|
+
*/
|
|
28
|
+
export declare function emit<K extends EventName>(event: K, data: Parameters<EventHandlerMap[K]>[0]): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get child methods that connect events to the bus
|
|
31
|
+
*/
|
|
32
|
+
export declare function getChildMethods(): {
|
|
33
|
+
onContextMenuEvent(event: ContextMenuEvent): void;
|
|
34
|
+
onSelectionChange(selection: string, url?: string): void;
|
|
35
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core module exports
|
|
3
|
+
*/
|
|
4
|
+
export { getHost, initConnection } from './connection';
|
|
5
|
+
export type { HostMethods, ChildMethods } from './connection';
|
|
6
|
+
export { on, emit, getChildMethods } from './event-bus';
|
|
7
|
+
export type { EventHandlerMap, EventName } from './event-bus';
|