@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 ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 GemiGo Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # @gemigo/app-sdk
2
+
3
+ GemiGo App SDK that auto-adapts for Web / Desktop / Browser Extension.
4
+
5
+ ## Installation
6
+
7
+ ### CDN (Recommended)
8
+
9
+ ```html
10
+ <script src="https://unpkg.com/@gemigo/app-sdk/dist/gemigo-app-sdk.umd.js"></script>
11
+ ```
12
+
13
+ ### npm
14
+
15
+ ```bash
16
+ npm install @gemigo/app-sdk
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```html
22
+ <script src="https://unpkg.com/@gemigo/app-sdk/dist/gemigo-app-sdk.umd.js"></script>
23
+ <script>
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);
30
+ });
31
+ </script>
32
+ ```
33
+
34
+ ## API Reference
35
+
36
+ ### Page Content Reading
37
+
38
+ | Method | Description |
39
+ |--------|-------------|
40
+ | `getPageInfo()` | Get current page URL, title, favicon |
41
+ | `getPageHTML()` | Get full page HTML content |
42
+ | `getPageText()` | Get page text content |
43
+ | `getSelection()` | Get selected text and position `{ text, rect? }` |
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 |
60
+
61
+ ### Screenshots
62
+
63
+ | Method | Description |
64
+ |--------|-------------|
65
+ | `captureVisible()` | Capture visible area screenshot |
66
+
67
+ ### Events
68
+
69
+ | Method | Description |
70
+ |--------|-------------|
71
+ | `onContextMenu(handler)` | Subscribe to context menu events |
72
+ | `onSelectionChange(handler)` | Subscribe to selection changes `(text, rect, url)` |
73
+ | `getContextMenuEvent()` | Get pending context menu event |
74
+
75
+ ### Common APIs
76
+
77
+ | Method | Description |
78
+ |--------|-------------|
79
+ | `gemigo.notify(title, message)` | Send system notification |
80
+
81
+ ## Example: Translation Bubble
82
+
83
+ ```html
84
+ <script src="https://unpkg.com/@gemigo/app-sdk/dist/gemigo-app-sdk.umd.js"></script>
85
+ <script>
86
+ gemigo.extension.onContextMenu(async (event) => {
87
+ if (event.selectionText) {
88
+ const translated = await translateText(event.selectionText);
89
+
90
+ // Show translation bubble on page
91
+ await gemigo.extension.insertWidget(
92
+ `<div style="background:#667eea;color:#fff;padding:16px;border-radius:12px;">
93
+ ${translated}
94
+ </div>`,
95
+ 'bottom-right'
96
+ );
97
+ }
98
+ });
99
+ </script>
100
+ ```
101
+
102
+ ## Example: Reader Mode
103
+
104
+ ```javascript
105
+ // Inject reader-friendly CSS
106
+ const { styleId } = await gemigo.extension.injectCSS(`
107
+ body { max-width: 720px; margin: 0 auto; font-family: Georgia, serif; }
108
+ nav, aside, .ads { display: none !important; }
109
+ `);
110
+
111
+ // Remove later
112
+ await gemigo.extension.removeCSS(styleId);
113
+ ```
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,10 @@
1
+ import { ChildMethods } from '../core';
2
+ import { GemigoSDK, Platform, Capabilities } from '../types';
3
+ /**
4
+ * Update the SDK's host environment information.
5
+ */
6
+ export declare const updateHostInfo: (info: {
7
+ platform: Platform;
8
+ capabilities: Capabilities;
9
+ } | null) => void;
10
+ export declare const sdk: GemigoSDK, childMethods: ChildMethods;
@@ -0,0 +1,2 @@
1
+ import { i as tryGetHost, n as createRPCProxy, r as initConnection, t as callHost } from "./connection-DwOg1Kh5.js";
2
+ export { initConnection };
@@ -0,0 +1,248 @@
1
+ var MessageType;
2
+ (function(e) {
3
+ e.Call = "call", e.Reply = "reply", e.Syn = "syn", e.SynAck = "synAck", e.Ack = "ack";
4
+ })(MessageType ||= {});
5
+ var Resolution;
6
+ (function(e) {
7
+ e.Fulfilled = "fulfilled", e.Rejected = "rejected";
8
+ })(Resolution ||= {});
9
+ var ErrorCode;
10
+ (function(e) {
11
+ e.ConnectionDestroyed = "ConnectionDestroyed", e.ConnectionTimeout = "ConnectionTimeout", e.NoIframeSrc = "NoIframeSrc";
12
+ })(ErrorCode ||= {});
13
+ var NativeErrorName;
14
+ (function(e) {
15
+ e.DataCloneError = "DataCloneError";
16
+ })(NativeErrorName ||= {});
17
+ var NativeEventType;
18
+ (function(e) {
19
+ e.Message = "message";
20
+ })(NativeEventType ||= {});
21
+ var createDestructor_default = (e, g) => {
22
+ let _ = [], v = !1;
23
+ return {
24
+ destroy(y) {
25
+ v || (v = !0, g(`${e}: Destroying connection`), _.forEach((e) => {
26
+ e(y);
27
+ }));
28
+ },
29
+ onDestroy(e) {
30
+ v ? e() : _.push(e);
31
+ }
32
+ };
33
+ }, createLogger_default = (e) => (...g) => {
34
+ e && console.log("[Penpal]", ...g);
35
+ };
36
+ const serializeError = ({ name: e, message: g, stack: _ }) => ({
37
+ name: e,
38
+ message: g,
39
+ stack: _
40
+ }), deserializeError = (e) => {
41
+ let g = /* @__PURE__ */ Error();
42
+ return Object.keys(e).forEach((_) => g[_] = e[_]), g;
43
+ };
44
+ var connectCallReceiver_default = (_, b, x) => {
45
+ let { localName: C, local: w, remote: T, originForSending: E, originForReceiving: D } = _, O = !1, k = (_) => {
46
+ if (_.source !== T || _.data.penpal !== MessageType.Call) return;
47
+ if (D !== "*" && _.origin !== D) {
48
+ x(`${C} received message from origin ${_.origin} which did not match expected origin ${D}`);
49
+ return;
50
+ }
51
+ let { methodName: y, args: w, id: k } = _.data;
52
+ x(`${C}: Received ${y}() call`);
53
+ let A = (_) => (b) => {
54
+ if (x(`${C}: Sending ${y}() reply`), O) {
55
+ x(`${C}: Unable to send ${y}() reply due to destroyed connection`);
56
+ return;
57
+ }
58
+ let w = {
59
+ penpal: MessageType.Reply,
60
+ id: k,
61
+ resolution: _,
62
+ returnValue: b
63
+ };
64
+ _ === Resolution.Rejected && b instanceof Error && (w.returnValue = serializeError(b), w.returnValueIsError = !0);
65
+ try {
66
+ T.postMessage(w, E);
67
+ } catch (_) {
68
+ if (_.name === NativeErrorName.DataCloneError) {
69
+ let v = {
70
+ penpal: MessageType.Reply,
71
+ id: k,
72
+ resolution: Resolution.Rejected,
73
+ returnValue: serializeError(_),
74
+ returnValueIsError: !0
75
+ };
76
+ T.postMessage(v, E);
77
+ }
78
+ throw _;
79
+ }
80
+ };
81
+ new Promise((e) => e(b[y].apply(b, w))).then(A(Resolution.Fulfilled), A(Resolution.Rejected));
82
+ };
83
+ return w.addEventListener(NativeEventType.Message, k), () => {
84
+ O = !0, w.removeEventListener(NativeEventType.Message, k);
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, g) => {
87
+ let _ = keyPathToSegments(g || "");
88
+ return _.push(e), segmentsToKeyPath(_);
89
+ };
90
+ const setAtKeyPath = (e, g, _) => {
91
+ let v = keyPathToSegments(g);
92
+ return v.reduce((e, g, y) => (e[g] === void 0 && (e[g] = {}), y === v.length - 1 && (e[g] = _), e[g]), e), e;
93
+ }, serializeMethods = (e, g) => {
94
+ let _ = {};
95
+ return Object.keys(e).forEach((v) => {
96
+ let y = e[v], b = createKeyPath(v, g);
97
+ typeof y == "object" && Object.assign(_, serializeMethods(y, b)), typeof y == "function" && (_[b] = y);
98
+ }), _;
99
+ }, deserializeMethods = (e) => {
100
+ let g = {};
101
+ for (let _ in e) setAtKeyPath(g, _, e[_]);
102
+ return g;
103
+ };
104
+ var connectCallSender_default = (v, b, x, S, w) => {
105
+ let { localName: T, local: D, remote: O, originForSending: k, originForReceiving: A } = b, j = !1;
106
+ w(`${T}: Connecting call sender`);
107
+ let M = (v) => (...b) => {
108
+ w(`${T}: Sending ${v}() call`);
109
+ let x;
110
+ try {
111
+ O.closed && (x = !0);
112
+ } catch {
113
+ x = !0;
114
+ }
115
+ if (x && S(), j) {
116
+ let e = /* @__PURE__ */ Error(`Unable to send ${v}() call due to destroyed connection`);
117
+ throw e.code = ErrorCode.ConnectionDestroyed, e;
118
+ }
119
+ return new Promise((_, x) => {
120
+ let S = generateId_default(), j = (b) => {
121
+ if (b.source !== O || b.data.penpal !== MessageType.Reply || b.data.id !== S) return;
122
+ if (A !== "*" && b.origin !== A) {
123
+ w(`${T} received message from origin ${b.origin} which did not match expected origin ${A}`);
124
+ return;
125
+ }
126
+ let E = b.data;
127
+ w(`${T}: Received ${v}() reply`), D.removeEventListener(NativeEventType.Message, j);
128
+ let k = E.returnValue;
129
+ E.returnValueIsError && (k = deserializeError(k)), (E.resolution === Resolution.Fulfilled ? _ : x)(k);
130
+ };
131
+ D.addEventListener(NativeEventType.Message, j);
132
+ let M = {
133
+ penpal: MessageType.Call,
134
+ id: S,
135
+ methodName: v,
136
+ args: b
137
+ };
138
+ O.postMessage(M, k);
139
+ });
140
+ }, N = x.reduce((e, g) => (e[g] = M(g), e), {});
141
+ return Object.assign(v, deserializeMethods(N)), () => {
142
+ j = !0;
143
+ };
144
+ }, startConnectionTimeout_default = (e, g) => {
145
+ let v;
146
+ return e !== void 0 && (v = window.setTimeout(() => {
147
+ let v = /* @__PURE__ */ Error(`Connection timed out after ${e}ms`);
148
+ v.code = ErrorCode.ConnectionTimeout, g(v);
149
+ }, e)), () => {
150
+ clearTimeout(v);
151
+ };
152
+ }, handleSynAckMessageFactory_default = (g, _, v, y) => {
153
+ let { destroy: b, onDestroy: x } = v;
154
+ return (v) => {
155
+ if (!(g instanceof RegExp ? g.test(v.origin) : g === "*" || g === v.origin)) {
156
+ y(`Child: Handshake - Received SYN-ACK from origin ${v.origin} which did not match expected origin ${g}`);
157
+ return;
158
+ }
159
+ y("Child: Handshake - Received SYN-ACK, responding with ACK");
160
+ let S = v.origin === "null" ? "*" : v.origin, C = {
161
+ penpal: MessageType.Ack,
162
+ methodNames: Object.keys(_)
163
+ };
164
+ window.parent.postMessage(C, S);
165
+ let T = {
166
+ localName: "Child",
167
+ local: window,
168
+ remote: window.parent,
169
+ originForSending: S,
170
+ originForReceiving: v.origin
171
+ };
172
+ x(connectCallReceiver_default(T, _, y));
173
+ let E = {};
174
+ return x(connectCallSender_default(E, T, v.data.methodNames, b, y)), E;
175
+ };
176
+ }, areGlobalsAccessible = () => {
177
+ try {
178
+ clearTimeout();
179
+ } catch {
180
+ return !1;
181
+ }
182
+ return !0;
183
+ }, connectToParent_default = (g = {}) => {
184
+ let { parentOrigin: _ = "*", methods: v = {}, timeout: S, debug: C = !1 } = g, w = createLogger_default(C), T = createDestructor_default("Child", w), { destroy: E, onDestroy: D } = T, O = handleSynAckMessageFactory_default(_, serializeMethods(v), T, w), k = () => {
185
+ w("Child: Handshake - Sending SYN");
186
+ let g = { penpal: MessageType.Syn }, v = _ instanceof RegExp ? "*" : _;
187
+ window.parent.postMessage(g, v);
188
+ };
189
+ return {
190
+ promise: new Promise((g, _) => {
191
+ let v = startConnectionTimeout_default(S, E), b = (_) => {
192
+ if (areGlobalsAccessible() && !(_.source !== parent || !_.data) && _.data.penpal === MessageType.SynAck) {
193
+ let e = O(_);
194
+ e && (window.removeEventListener(NativeEventType.Message, b), v(), g(e));
195
+ }
196
+ };
197
+ window.addEventListener(NativeEventType.Message, b), k(), D((e) => {
198
+ window.removeEventListener(NativeEventType.Message, b), e && _(e);
199
+ });
200
+ }),
201
+ destroy() {
202
+ E();
203
+ }
204
+ };
205
+ }, connectionPromise = null, resolvedHost = null, connectionFailed = !1, defaultChildMethods, DEFAULT_TIMEOUT_MS = 1500;
206
+ function isInIframe() {
207
+ try {
208
+ return window.self !== window.top;
209
+ } catch {
210
+ return !0;
211
+ }
212
+ }
213
+ async function tryGetHost(e, g) {
214
+ if (resolvedHost) return resolvedHost;
215
+ if (connectionFailed) return null;
216
+ if (!isInIframe()) return connectionFailed = !0, null;
217
+ if (!connectionPromise) {
218
+ let _ = {}, v = e ?? defaultChildMethods;
219
+ v && Object.assign(_, v), connectionPromise = connectToParent_default({
220
+ methods: _,
221
+ timeout: g?.timeoutMs ?? DEFAULT_TIMEOUT_MS
222
+ }).promise.then((e) => (resolvedHost = e, e)).catch((e) => (console.error("[GemiGo Connection] Promise failed:", e), connectionFailed = !0, connectionPromise = null, null));
223
+ }
224
+ return connectionPromise;
225
+ }
226
+ function initConnection(e, g) {
227
+ defaultChildMethods = e, tryGetHost(e, g);
228
+ }
229
+ async function callHost(e, g = [], _) {
230
+ let v = await tryGetHost();
231
+ if (v && typeof v[e] == "function") {
232
+ let y = await v[e](...g);
233
+ if (y?.success !== !1) return y?.data === void 0 ? y?.value === void 0 ? y : y.value : y.data;
234
+ if (_) return _(...g);
235
+ throw Error(y?.error || `Host method ${String(e)} failed`);
236
+ }
237
+ if (_) return _(...g);
238
+ throw Error(`Method ${String(e)} not supported in this environment`);
239
+ }
240
+ function createRPCProxy(e, g = {}) {
241
+ let _ = {};
242
+ for (let v of e) {
243
+ let e = g.mapping?.[v] || v, y = g.fallbacks?.[v];
244
+ _[v] = (...g) => callHost(e, g, y);
245
+ }
246
+ return _;
247
+ }
248
+ export { tryGetHost as i, createRPCProxy as n, initConnection as r, callHost as t };
@@ -0,0 +1,84 @@
1
+ import { HostMethods } from './connection';
2
+ import { SDKEvents } from './event-bus';
3
+ export interface APIConfig<TAPI extends object> {
4
+ /** RPC methods mapping to host functions */
5
+ rpc?: {
6
+ methods: readonly (keyof TAPI)[];
7
+ mapping?: Partial<Record<keyof TAPI, keyof HostMethods>>;
8
+ fallbacks?: Partial<Record<keyof TAPI, (...args: any[]) => any>>;
9
+ };
10
+ /** Event methods mapping to SDK event bus */
11
+ events?: readonly (keyof TAPI)[] | {
12
+ [K in keyof TAPI]?: keyof SDKEvents | {
13
+ event: keyof SDKEvents;
14
+ childMethod?: string;
15
+ };
16
+ };
17
+ }
18
+ /**
19
+ * Create a unified API instance from a declarative configuration.
20
+ *
21
+ * @param config - API configuration
22
+ * @returns Object with generated API instance and child methods for host injection
23
+ */
24
+ export declare function createUnifiedAPI<TAPI extends object, TChild extends object = Record<string, any>>(config: APIConfig<TAPI>): {
25
+ api: TAPI;
26
+ childMethods: TChild;
27
+ };
28
+ /**
29
+ * Create a standalone RPC action with argument transformation and fallback handling.
30
+ *
31
+ * @param methodName - Host method name to call
32
+ * @param config - Action configuration
33
+ * @returns An async function that handles the full RPC cycle
34
+ */
35
+ export declare function createRPCAction<TArgs extends any[], TResult, THostResult = any>(methodName: keyof HostMethods, config: {
36
+ /** Transform input arguments for host method */
37
+ transform?: (...args: TArgs) => any[];
38
+ /** Fallback if host fails */
39
+ fallback: (...args: TArgs) => TResult | Promise<TResult>;
40
+ /** Process host result */
41
+ onSuccess?: (result: THostResult) => TResult;
42
+ }): (...args: TArgs) => Promise<TResult>;
43
+ /**
44
+ * Master SDK Action Configuration
45
+ */
46
+ export interface ActionConfig<TFunc extends (...args: any[]) => any> {
47
+ method: keyof HostMethods;
48
+ /** Transform input arguments for host method */
49
+ transform?: (...args: Parameters<TFunc>) => any[];
50
+ /** Fallback if host fails */
51
+ fallback: TFunc;
52
+ /** Process host result */
53
+ onSuccess?: (result: any) => ReturnType<TFunc> extends Promise<infer R> ? R : ReturnType<TFunc>;
54
+ }
55
+ /**
56
+ * Master SDK Factory - Create the entire SDK and child methods from a single config.
57
+ */
58
+ export declare function createSDK<TSDK extends object, TChild extends object = Record<string, any>>(config: {
59
+ /** Sub-modules (e.g., storage, extension) */
60
+ modules?: {
61
+ [K in keyof TSDK]?: NonNullable<TSDK[K]> extends (...args: any[]) => any ? never : NonNullable<TSDK[K]> extends object ? APIConfig<NonNullable<TSDK[K]>> : never;
62
+ };
63
+ /** Standalone functions (e.g., notify) */
64
+ actions?: {
65
+ [K in keyof TSDK]?: TSDK[K] extends (...args: any[]) => any ? ActionConfig<TSDK[K]> : never;
66
+ };
67
+ /** Dynamic getter properties (e.g., platform, capabilities) */
68
+ getters?: {
69
+ [K in keyof TSDK]?: () => TSDK[K];
70
+ };
71
+ /** Static values or stubs (e.g., platform, ai) */
72
+ statics?: {
73
+ [K in keyof TSDK]?: TSDK[K];
74
+ };
75
+ }): {
76
+ sdk: TSDK;
77
+ childMethods: TChild;
78
+ };
79
+ /**
80
+ * Bootstrap the SDK connection and discover host protocol info.
81
+ */
82
+ export declare function bootstrapSDK(childMethods: any, options?: {
83
+ timeoutMs?: number;
84
+ }): Promise<any>;
@@ -0,0 +1,99 @@
1
+ import { AsyncMethodReturns } from 'penpal';
2
+ import { Capabilities, ExtensionRPCMethods, RPCResult, Platform } from '../types';
3
+ import { SDKEvents } from './event-bus';
4
+ export interface ProtocolRPCMethods {
5
+ getProtocolInfo(): Promise<{
6
+ protocolVersion: number;
7
+ platform: Platform;
8
+ appId: string;
9
+ capabilities: Capabilities;
10
+ }>;
11
+ ping(): Promise<{
12
+ pong: boolean;
13
+ }>;
14
+ }
15
+ export interface StorageRPCMethods {
16
+ storageGet(key: string): Promise<{
17
+ success: boolean;
18
+ data?: unknown;
19
+ }>;
20
+ storageSet(key: string, value: unknown): Promise<RPCResult>;
21
+ storageDelete(key: string): Promise<RPCResult>;
22
+ storageClear(): Promise<RPCResult>;
23
+ }
24
+ export interface NetworkRPCMethods {
25
+ networkRequest(url: string, options?: {
26
+ method?: string;
27
+ headers?: Record<string, string>;
28
+ body?: string | object;
29
+ responseType?: 'json' | 'text' | 'arraybuffer';
30
+ timeoutMs?: number;
31
+ }): Promise<{
32
+ success: boolean;
33
+ status?: number;
34
+ headers?: Record<string, string>;
35
+ data?: any;
36
+ error?: string;
37
+ code?: string;
38
+ }>;
39
+ }
40
+ export interface NotifyRPCMethods {
41
+ notify(payload: {
42
+ title: string;
43
+ message: string;
44
+ }): Promise<RPCResult<string>>;
45
+ }
46
+ /**
47
+ * Host methods interface - what the host provides to apps.
48
+ * Same interface for all platforms.
49
+ */
50
+ export interface HostMethods extends ExtensionRPCMethods, ProtocolRPCMethods, StorageRPCMethods, NetworkRPCMethods, NotifyRPCMethods {
51
+ }
52
+ /**
53
+ * Child methods interface - what apps expose to the host.
54
+ * Automatically derived from SDK event definitions.
55
+ */
56
+ export type ChildMethods = {
57
+ [K in keyof SDKEvents]?: (...args: SDKEvents[K]) => void;
58
+ };
59
+ /**
60
+ * Get or create connection to parent (host).
61
+ * Returns null if connection failed or not in iframe.
62
+ */
63
+ export declare function tryGetHost(childMethods?: ChildMethods, options?: {
64
+ timeoutMs?: number;
65
+ }): Promise<AsyncMethodReturns<HostMethods> | null>;
66
+ /**
67
+ * Get host connection (throws if not available).
68
+ */
69
+ export declare function getHost(): Promise<AsyncMethodReturns<HostMethods>>;
70
+ /**
71
+ * Check if connected to host.
72
+ */
73
+ export declare function isConnected(): boolean;
74
+ /**
75
+ * Check if connection failed.
76
+ */
77
+ export declare function hasConnectionFailed(): boolean;
78
+ /**
79
+ * Initialize connection immediately.
80
+ */
81
+ export declare function initConnection(childMethods?: ChildMethods, options?: {
82
+ timeoutMs?: number;
83
+ }): void;
84
+ /**
85
+ * Generic host call with optional fallback.
86
+ */
87
+ export declare function callHost<T>(methodName: keyof HostMethods, args?: any[], fallback?: (...args: any[]) => T | Promise<T>): Promise<T>;
88
+ /**
89
+ * Create a simple RPC proxy for a set of methods.
90
+ */
91
+ export declare function createRPCProxy<T extends Record<string, any>>(methodNames: readonly (keyof T)[], config?: {
92
+ mapping?: Record<string, keyof HostMethods>;
93
+ fallbacks?: Record<string, (...args: any[]) => any>;
94
+ }): T;
95
+ /**
96
+ * Wrap an async function with a fallback.
97
+ * If the primary function throws, the fallback is called with the same arguments.
98
+ */
99
+ export declare function withFallback<TArgs extends unknown[], TResult>(primary: (...args: TArgs) => Promise<TResult>, fallback: (...args: TArgs) => TResult | Promise<TResult>): (...args: TArgs) => Promise<TResult>;
@@ -0,0 +1,77 @@
1
+ import { ExtensionAPI } from '../types';
2
+ export type EventHandler<T extends unknown[] = unknown[]> = (...args: T) => void;
3
+ export interface EventBus<TEvents extends Record<string, unknown[]>> {
4
+ /**
5
+ * Subscribe to an event
6
+ * @returns Unsubscribe function
7
+ */
8
+ on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void;
9
+ /**
10
+ * Emit an event to all subscribers
11
+ */
12
+ emit<K extends keyof TEvents>(event: K, ...args: TEvents[K]): void;
13
+ /**
14
+ * Remove all subscribers for an event (or all events)
15
+ */
16
+ off<K extends keyof TEvents>(event?: K): void;
17
+ }
18
+ /**
19
+ * Create a type-safe event bus
20
+ */
21
+ export declare function createEventBus<TEvents extends Record<string, unknown[]>>(): EventBus<TEvents>;
22
+ /**
23
+ * SDK-level event types
24
+ * Add new event types here as the SDK grows
25
+ */
26
+ export type SDKEvents = {
27
+ onContextMenu: Parameters<Parameters<ExtensionAPI['onContextMenu']>[0]>;
28
+ onSelectionChange: Parameters<Parameters<ExtensionAPI['onSelectionChange']>[0]>;
29
+ };
30
+ /**
31
+ * Shared SDK event bus instance
32
+ * Use this for SDK-wide event communication
33
+ */
34
+ export declare const sdkEventBus: EventBus<SDKEvents>;
35
+ /**
36
+ * Create a callback handler that subscribes to the SDK event bus.
37
+ * Useful for building callback APIs like onContextMenu, onSelectionChange, etc.
38
+ *
39
+ * @param eventName - The SDK event to subscribe to
40
+ * @param ensureConnection - Optional function to ensure host connection (e.g., tryGetHost)
41
+ * @returns A function that accepts a callback and returns an unsubscribe function
42
+ *
43
+ * @example
44
+ * const onContextMenu = createCallbackHandler('extension:contextMenu', tryGetHost);
45
+ */
46
+ export declare function createCallbackHandler<K extends keyof SDKEvents>(eventName: K, ensureConnection?: () => void): (callback: EventHandler<SDKEvents[K]>) => () => void;
47
+ /**
48
+ * Create both emitter (for childMethods) and subscriber (for callbackAPI) from a single config.
49
+ * This ensures event names and signatures stay in sync.
50
+ *
51
+ * @param config - Map of local method names to SDK event names
52
+ * @param ensureConnection - Optional function to ensure host connection
53
+ * @returns Object with emitters and subscribers
54
+ *
55
+ * @example
56
+ * const { emitters, subscribers } = createEventPair({
57
+ * onContextMenuEvent: 'extension:contextMenu',
58
+ * onSelectionChange: 'extension:selectionChange',
59
+ * }, tryGetHost);
60
+ *
61
+ * // Use emitters in childMethods
62
+ * export const childMethods = emitters;
63
+ *
64
+ * // Use subscribers in callbackAPI
65
+ * export const callbackAPI = {
66
+ * onContextMenu: subscribers.onContextMenuEvent,
67
+ * onSelectionChange: subscribers.onSelectionChange,
68
+ * };
69
+ */
70
+ export declare function createEventPair<TConfig extends Record<string, keyof SDKEvents>>(config: TConfig, ensureConnection?: () => void): {
71
+ emitters: {
72
+ [K in keyof TConfig]: (...args: SDKEvents[TConfig[K]]) => void;
73
+ };
74
+ subscribers: {
75
+ [K in keyof TConfig]: (callback: EventHandler<SDKEvents[TConfig[K]]>) => () => void;
76
+ };
77
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Core Module
3
+ */
4
+ export { getHost, tryGetHost, initConnection, isConnected, hasConnectionFailed, callHost, createRPCProxy, withFallback, } from './connection';
5
+ export { createEventBus, sdkEventBus, createCallbackHandler, createEventPair } from './event-bus';
6
+ export type { EventBus, EventHandler, SDKEvents } from './event-bus';
7
+ export { createUnifiedAPI, createRPCAction, createSDK, bootstrapSDK } from './api-factory';
8
+ export type { APIConfig } from './api-factory';
9
+ export type { HostMethods, ChildMethods } from './connection';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Fallback Implementations
3
+ *
4
+ * Used when no host is available.
5
+ */
6
+ export { fallbackStorage } from './storage';
7
+ export { fallbackNotify } from './notify';
8
+ export { fallbackNetwork } from './network';
@@ -0,0 +1,2 @@
1
+ import { NetworkAPI } from '../types';
2
+ export declare const fallbackNetwork: NetworkAPI;
@@ -0,0 +1,2 @@
1
+ import { NotifyOptions, NotifyResult } from '../types';
2
+ export declare const fallbackNotify: (options: NotifyOptions) => Promise<NotifyResult>;