@gemigo/app-sdk 0.2.5 → 0.2.6

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.
@@ -1,82 +1,82 @@
1
1
  import { i as tryGetHost, n as createRPCProxy, t as callHost } from "./connection-DwOg1Kh5.js";
2
2
  function createEventBus() {
3
- let e = /* @__PURE__ */ new Map();
3
+ let c = /* @__PURE__ */ new Map();
4
4
  return {
5
- on(x, S) {
6
- return e.has(x) || e.set(x, /* @__PURE__ */ new Set()), e.get(x).add(S), () => e.get(x)?.delete(S);
5
+ on(N, P) {
6
+ return c.has(N) || c.set(N, /* @__PURE__ */ new Set()), c.get(N).add(P), () => c.get(N)?.delete(P);
7
7
  },
8
- emit(x, ...S) {
9
- e.get(x)?.forEach((e) => e(...S));
8
+ emit(N, ...P) {
9
+ c.get(N)?.forEach((c) => c(...P));
10
10
  },
11
- off(x) {
12
- x ? e.delete(x) : e.clear();
11
+ off(N) {
12
+ N ? c.delete(N) : c.clear();
13
13
  }
14
14
  };
15
15
  }
16
16
  const sdkEventBus = createEventBus();
17
- function createUnifiedAPI(S) {
18
- let C = tryGetHost, T = {}, E = {};
19
- if (S.rpc) {
20
- let e = createRPCProxy(S.rpc.methods, {
21
- mapping: S.rpc.mapping,
22
- fallbacks: S.rpc.fallbacks
17
+ function createUnifiedAPI(P) {
18
+ let F = tryGetHost, L = {}, R = {};
19
+ if (P.rpc) {
20
+ let c = createRPCProxy(P.rpc.methods, {
21
+ mapping: P.rpc.mapping,
22
+ fallbacks: P.rpc.fallbacks
23
23
  });
24
- Object.assign(T, e);
24
+ Object.assign(L, c);
25
25
  }
26
- if (S.events) if (Array.isArray(S.events)) for (let e of S.events) {
27
- let x = e;
28
- T[e] = (e) => (C?.(), sdkEventBus.on(x, e)), E[e] = (...e) => {
29
- sdkEventBus.emit(x, ...e);
26
+ if (P.events) if (Array.isArray(P.events)) for (let c of P.events) {
27
+ let N = c;
28
+ L[c] = (c) => (F?.(), sdkEventBus.on(N, c)), R[c] = (...c) => {
29
+ sdkEventBus.emit(N, ...c);
30
30
  };
31
31
  }
32
- else for (let [e, x] of Object.entries(S.events)) {
33
- if (!x) continue;
34
- let S = x, D = typeof S == "string" ? S : S.event, O = typeof S == "object" && "childMethod" in S && S.childMethod ? S.childMethod : e;
35
- T[e] = (e) => (C?.(), sdkEventBus.on(D, e)), E[O] = (...e) => {
36
- sdkEventBus.emit(D, ...e);
32
+ else for (let [c, N] of Object.entries(P.events)) {
33
+ if (!N) continue;
34
+ let P = N, z = typeof P == "string" ? P : P.event, B = typeof P == "object" && "childMethod" in P && P.childMethod ? P.childMethod : c;
35
+ L[c] = (c) => (F?.(), sdkEventBus.on(z, c)), R[B] = (...c) => {
36
+ sdkEventBus.emit(z, ...c);
37
37
  };
38
38
  }
39
39
  return {
40
- api: T,
41
- childMethods: E
40
+ api: L,
41
+ childMethods: R
42
42
  };
43
43
  }
44
- function createRPCAction(e, x) {
45
- return async (...C) => {
44
+ function createRPCAction(c, N) {
45
+ return async (...F) => {
46
46
  try {
47
- let w = await callHost(e, x.transform ? x.transform(...C) : C);
48
- return x.onSuccess ? x.onSuccess(w) : w;
47
+ let I = await callHost(c, N.transform ? N.transform(...F) : F);
48
+ return N.onSuccess ? N.onSuccess(I) : I;
49
49
  } catch {
50
- return x.fallback(...C);
50
+ return N.fallback(...F);
51
51
  }
52
52
  };
53
53
  }
54
- function createSDK(e) {
55
- let x = e.statics ? { ...e.statics } : {}, S = {};
56
- if (e.modules) for (let [C, w] of Object.entries(e.modules)) {
57
- let { api: e, childMethods: E } = createUnifiedAPI(w);
58
- x[C] = e, Object.assign(S, E);
54
+ function createSDK(c) {
55
+ let N = c.statics ? { ...c.statics } : {}, P = {};
56
+ if (c.modules) for (let [F, I] of Object.entries(c.modules)) {
57
+ let { api: c, childMethods: R } = createUnifiedAPI(I);
58
+ N[F] = c, Object.assign(P, R);
59
59
  }
60
- if (e.actions) for (let [S, C] of Object.entries(e.actions)) {
61
- let e = C;
62
- x[S] = createRPCAction(e.method, e);
60
+ if (c.actions) for (let [P, F] of Object.entries(c.actions)) {
61
+ let c = F;
62
+ N[P] = createRPCAction(c.method, c);
63
63
  }
64
- if (e.getters) for (let [S, C] of Object.entries(e.getters)) Object.defineProperty(x, S, {
65
- get: C,
64
+ if (c.getters) for (let [P, F] of Object.entries(c.getters)) Object.defineProperty(N, P, {
65
+ get: F,
66
66
  enumerable: !0,
67
67
  configurable: !0
68
68
  });
69
69
  return {
70
- sdk: x,
71
- childMethods: S
70
+ sdk: N,
71
+ childMethods: P
72
72
  };
73
73
  }
74
- async function bootstrapSDK(x, S = {}) {
75
- let { initConnection: C } = await import("./connection-C-IGR2wz.js");
76
- C(x, S);
77
- let w = await tryGetHost();
78
- if (w && typeof w.getProtocolInfo == "function") try {
79
- return await w.getProtocolInfo();
74
+ async function bootstrapSDK(N, P = {}) {
75
+ let { initConnection: F } = await import("./connection-C-IGR2wz.js");
76
+ F(N, P);
77
+ let I = await tryGetHost();
78
+ if (I && typeof I.getProtocolInfo == "function") try {
79
+ return await I.getProtocolInfo();
80
80
  } catch {
81
81
  return null;
82
82
  }
@@ -84,31 +84,31 @@ async function bootstrapSDK(x, S = {}) {
84
84
  }
85
85
  var localStoragePrefix = () => `gemigo:${typeof window > "u" ? "unknown" : window.location.origin.replace(/[:/]/g, "_")}:`;
86
86
  const fallbackStorage = {
87
- get: async (e) => {
87
+ get: async (c) => {
88
88
  if (typeof window > "u" || !window.localStorage) return null;
89
- let x = window.localStorage.getItem(`${localStoragePrefix()}${e}`);
90
- if (!x) return null;
89
+ let N = window.localStorage.getItem(`${localStoragePrefix()}${c}`);
90
+ if (!N) return null;
91
91
  try {
92
- return JSON.parse(x);
92
+ return JSON.parse(N);
93
93
  } catch {
94
94
  return null;
95
95
  }
96
96
  },
97
- set: async (e, x) => {
98
- typeof window > "u" || !window.localStorage || window.localStorage.setItem(`${localStoragePrefix()}${e}`, JSON.stringify(x));
97
+ set: async (c, N) => {
98
+ typeof window > "u" || !window.localStorage || window.localStorage.setItem(`${localStoragePrefix()}${c}`, JSON.stringify(N));
99
99
  },
100
- delete: async (e) => {
101
- typeof window > "u" || !window.localStorage || window.localStorage.removeItem(`${localStoragePrefix()}${e}`);
100
+ delete: async (c) => {
101
+ typeof window > "u" || !window.localStorage || window.localStorage.removeItem(`${localStoragePrefix()}${c}`);
102
102
  },
103
103
  clear: async () => {
104
104
  if (typeof window > "u" || !window.localStorage) return;
105
- let e = localStoragePrefix();
106
- for (let x = window.localStorage.length - 1; x >= 0; --x) {
107
- let S = window.localStorage.key(x);
108
- S && S.startsWith(e) && window.localStorage.removeItem(S);
105
+ let c = localStoragePrefix();
106
+ for (let N = window.localStorage.length - 1; N >= 0; --N) {
107
+ let P = window.localStorage.key(N);
108
+ P && P.startsWith(c) && window.localStorage.removeItem(P);
109
109
  }
110
110
  }
111
- }, fallbackNotify = async (e) => {
111
+ }, fallbackNotify = async (c) => {
112
112
  if (typeof window > "u" || typeof Notification > "u") return {
113
113
  success: !1,
114
114
  reason: "not_supported"
@@ -118,9 +118,9 @@ const fallbackStorage = {
118
118
  reason: "permission_not_granted"
119
119
  };
120
120
  try {
121
- return new Notification(e.title, {
122
- body: e.message,
123
- icon: e.icon
121
+ return new Notification(c.title, {
122
+ body: c.message,
123
+ icon: c.icon
124
124
  }), { success: !0 };
125
125
  } catch {
126
126
  return {
@@ -128,25 +128,283 @@ const fallbackStorage = {
128
128
  reason: "failed_to_notify"
129
129
  };
130
130
  }
131
- }, fallbackNetwork = { request: async (e, x) => {
132
- let { method: S = "GET", headers: C, body: w, responseType: T } = x ?? {}, E = await fetch(e, {
133
- method: S,
134
- headers: C,
135
- body: w ? typeof w == "string" ? w : JSON.stringify(w) : void 0
136
- }), D = {};
137
- E.headers.forEach((e, x) => D[x] = e);
138
- let O = T === "text" ? await E.text() : T === "arraybuffer" ? await E.arrayBuffer() : await E.json();
131
+ }, fallbackNetwork = { request: async (c, N) => {
132
+ let { method: P = "GET", headers: F, body: I, responseType: L } = N ?? {}, R = await fetch(c, {
133
+ method: P,
134
+ headers: F,
135
+ body: I ? typeof I == "string" ? I : JSON.stringify(I) : void 0
136
+ }), z = {};
137
+ R.headers.forEach((c, N) => z[N] = c);
138
+ let B = L === "text" ? await R.text() : L === "arraybuffer" ? await R.arrayBuffer() : await R.json();
139
139
  return {
140
- status: E.status,
141
- data: O,
142
- headers: D
140
+ status: R.status,
141
+ data: B,
142
+ headers: z
143
143
  };
144
144
  } };
145
- var SDKError = class e extends Error {
146
- constructor(x, S) {
147
- super(S), this.code = x, this.name = "SDKError", Object.setPrototypeOf(this, e.prototype);
145
+ var SDKError = class c extends Error {
146
+ constructor(N, P) {
147
+ super(P), this.code = N, this.name = "SDKError", Object.setPrototypeOf(this, c.prototype);
148
148
  }
149
- }, hostInfo = null, defaultCapabilities = {
149
+ }, currentToken = null, currentApiBaseUrl = null;
150
+ function base64UrlEncode(c) {
151
+ let N = "";
152
+ for (let P of c) N += String.fromCharCode(P);
153
+ let P = globalThis.btoa;
154
+ if (!P) throw Error("base64 encoder not available");
155
+ return P(N).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
156
+ }
157
+ function randomString(c = 32) {
158
+ let N = new Uint8Array(c);
159
+ return crypto.getRandomValues(N), base64UrlEncode(N);
160
+ }
161
+ async function sha256Base64Url(c) {
162
+ let N = new TextEncoder().encode(c), P = await crypto.subtle.digest("SHA-256", N);
163
+ return base64UrlEncode(new Uint8Array(P));
164
+ }
165
+ function deriveDefaultAppId() {
166
+ if (typeof window > "u") return "unknown";
167
+ let c = window.location.hostname.toLowerCase();
168
+ return c.endsWith(".gemigo.app") ? c.replace(/\.gemigo\.app$/, "") : c;
169
+ }
170
+ function normalizeScopes(c) {
171
+ let N = (c ?? ["identity:basic"]).map((c) => String(c).trim()).filter(Boolean);
172
+ return N.length > 0 ? N : ["identity:basic"];
173
+ }
174
+ function buildBrokerUrl(c) {
175
+ let N = new URL("/sdk/broker", c.platformOrigin);
176
+ return N.searchParams.set("app_id", c.appId), N.searchParams.set("scope", c.scopes.join(" ")), N.searchParams.set("state", c.state), N.searchParams.set("code_challenge", c.codeChallenge), N.searchParams.set("code_challenge_method", "S256"), N.searchParams.set("origin", c.openerOrigin), N.toString();
177
+ }
178
+ async function exchangeCode(c, N, P) {
179
+ let F = await fetch(`${c.replace(/\/+$/, "")}/sdk/token`, {
180
+ method: "POST",
181
+ headers: { "Content-Type": "application/json" },
182
+ body: JSON.stringify({
183
+ code: N,
184
+ codeVerifier: P
185
+ })
186
+ });
187
+ if (!F.ok) {
188
+ let c = await F.json().catch(() => ({}));
189
+ throw Error(c.error || "Failed to exchange code");
190
+ }
191
+ return await F.json();
192
+ }
193
+ function getWebApiBaseUrl() {
194
+ return currentApiBaseUrl || "https://gemigo.io/api/v1";
195
+ }
196
+ const webAuth = {
197
+ async login(c = {}) {
198
+ if (typeof window > "u") throw new SDKError("NOT_SUPPORTED", "auth.login is only supported in browser environments.");
199
+ let N = c.platformOrigin?.trim() || "https://gemigo.io", P = c.apiBaseUrl?.trim() || `${N.replace(/\/+$/, "")}/api/v1`, F = c.appId?.trim() || deriveDefaultAppId(), I = normalizeScopes(c.scopes), L = typeof c.timeoutMs == "number" ? c.timeoutMs : 120 * 1e3, R = randomString(16), z = randomString(48), B = window.location.origin, V = Math.max(0, (window.screen.width - 520) / 2), H = Math.max(0, (window.screen.height - 720) / 2), U = window.open("about:blank", "gemigo_sdk_auth", `popup=yes,width=520,height=720,left=${V},top=${H}`);
200
+ if (!U) throw Error("Popup blocked. Please allow popups and retry.");
201
+ try {
202
+ U.document.title = "GemiGo Auth", U.document.body.innerHTML = "<div style=\"font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;padding:24px;\">Loading…</div>";
203
+ } catch {}
204
+ let W = buildBrokerUrl({
205
+ platformOrigin: N,
206
+ appId: F,
207
+ scopes: I,
208
+ state: R,
209
+ codeChallenge: await sha256Base64Url(z),
210
+ openerOrigin: B
211
+ });
212
+ try {
213
+ U.location.href = W;
214
+ } catch {
215
+ if (!window.open(W, "gemigo_sdk_auth")) throw Error("Popup navigation failed. Please allow popups and retry.");
216
+ }
217
+ let G = await exchangeCode(P, (await new Promise((c, P) => {
218
+ let F = window.setTimeout(() => {
219
+ I(), P(/* @__PURE__ */ Error("Login timeout."));
220
+ }, L), I = () => {
221
+ window.clearTimeout(F), window.removeEventListener("message", z);
222
+ try {
223
+ U.close();
224
+ } catch {}
225
+ }, z = (F) => {
226
+ if (F.origin !== new URL(N).origin) return;
227
+ let L = F.data;
228
+ if (!(!L || typeof L != "object") && L.state === R) {
229
+ if (L.type === "gemigo:sdk-auth-error") {
230
+ I(), P(Error(String(L.error || "auth_error")));
231
+ return;
232
+ }
233
+ L.type === "gemigo:sdk-auth-code" && typeof L.code == "string" && (I(), c({ code: L.code }));
234
+ }
235
+ };
236
+ window.addEventListener("message", z);
237
+ })).code, z);
238
+ return currentToken = G, currentApiBaseUrl = P, G;
239
+ },
240
+ getAccessToken() {
241
+ return currentToken?.accessToken ?? null;
242
+ },
243
+ logout() {
244
+ currentToken = null;
245
+ }
246
+ };
247
+ function requireAccessToken() {
248
+ let c = webAuth.getAccessToken();
249
+ if (!c) throw new SDKError("PERMISSION_DENIED", "Login required. Call gemigo.auth.login() first.");
250
+ return c;
251
+ }
252
+ async function fetchJson(c, N = {}) {
253
+ let P = requireAccessToken(), F = getWebApiBaseUrl().replace(/\/+$/, ""), I = await fetch(`${F}${c}`, {
254
+ ...N,
255
+ headers: {
256
+ ...N.headers ?? {},
257
+ Authorization: `Bearer ${P}`
258
+ }
259
+ });
260
+ if (!I.ok) {
261
+ let c = (await I.json().catch(() => ({}))).error || `Request failed: ${I.status}`;
262
+ throw I.status === 401 || I.status === 403 ? new SDKError("PERMISSION_DENIED", c) : new SDKError("INTERNAL_ERROR", c);
263
+ }
264
+ return await I.json();
265
+ }
266
+ var WebCloudKv = class {
267
+ async get(c) {
268
+ return fetchJson(`/cloud/kv/get?key=${encodeURIComponent(c)}`);
269
+ }
270
+ async set(c, N, P) {
271
+ return fetchJson("/cloud/kv/set", {
272
+ method: "POST",
273
+ headers: { "Content-Type": "application/json" },
274
+ body: JSON.stringify({
275
+ key: c,
276
+ value: N,
277
+ ifMatch: P?.ifMatch
278
+ })
279
+ });
280
+ }
281
+ async delete(c, N) {
282
+ await fetchJson("/cloud/kv/delete", {
283
+ method: "POST",
284
+ headers: { "Content-Type": "application/json" },
285
+ body: JSON.stringify({
286
+ key: c,
287
+ ifMatch: N?.ifMatch
288
+ })
289
+ });
290
+ }
291
+ async list(c) {
292
+ let N = new URLSearchParams();
293
+ c?.prefix && N.set("prefix", c.prefix), typeof c?.limit == "number" && N.set("limit", String(c.limit)), c?.cursor && N.set("cursor", c.cursor);
294
+ let P = N.toString();
295
+ return fetchJson(`/cloud/kv/list${P ? `?${P}` : ""}`);
296
+ }
297
+ }, WebCloudDbQueryBuilder = class c {
298
+ constructor(c, N) {
299
+ this.collectionName = c, this.state = {
300
+ where: N?.where ?? [],
301
+ orderBy: N?.orderBy ?? {
302
+ field: "createdAt",
303
+ direction: "desc"
304
+ },
305
+ limit: N?.limit ?? 20,
306
+ cursor: N?.cursor ?? null
307
+ };
308
+ }
309
+ where(N, P, F) {
310
+ return new c(this.collectionName, {
311
+ ...this.state,
312
+ where: [...this.state.where, {
313
+ field: N,
314
+ op: P,
315
+ value: F
316
+ }]
317
+ });
318
+ }
319
+ orderBy(N, P = "desc") {
320
+ return new c(this.collectionName, {
321
+ ...this.state,
322
+ orderBy: {
323
+ field: N,
324
+ direction: P
325
+ }
326
+ });
327
+ }
328
+ limit(N) {
329
+ return new c(this.collectionName, {
330
+ ...this.state,
331
+ limit: N
332
+ });
333
+ }
334
+ startAfter(N) {
335
+ return new c(this.collectionName, {
336
+ ...this.state,
337
+ cursor: N
338
+ });
339
+ }
340
+ async get() {
341
+ return fetchJson(`/cloud/db/collections/${encodeURIComponent(this.collectionName)}/query`, {
342
+ method: "POST",
343
+ headers: { "Content-Type": "application/json" },
344
+ body: JSON.stringify({
345
+ where: this.state.where,
346
+ orderBy: this.state.orderBy,
347
+ limit: this.state.limit,
348
+ cursor: this.state.cursor
349
+ })
350
+ });
351
+ }
352
+ }, WebCloudDbCollection = class {
353
+ constructor(c) {
354
+ this.name = c;
355
+ }
356
+ async add(c, N) {
357
+ return fetchJson(`/cloud/db/collections/${encodeURIComponent(this.name)}/docs`, {
358
+ method: "POST",
359
+ headers: { "Content-Type": "application/json" },
360
+ body: JSON.stringify({
361
+ id: N?.id,
362
+ visibility: N?.visibility,
363
+ refType: N?.refType,
364
+ refId: N?.refId,
365
+ data: c
366
+ })
367
+ });
368
+ }
369
+ doc(c) {
370
+ let N = this.name;
371
+ return {
372
+ get: async () => fetchJson(`/cloud/db/collections/${encodeURIComponent(N)}/docs/${encodeURIComponent(c)}`),
373
+ update: async (P, F) => fetchJson(`/cloud/db/collections/${encodeURIComponent(N)}/docs/${encodeURIComponent(c)}`, {
374
+ method: "PATCH",
375
+ headers: { "Content-Type": "application/json" },
376
+ body: JSON.stringify({
377
+ patch: P,
378
+ ifMatch: F?.ifMatch
379
+ })
380
+ }),
381
+ delete: async () => fetchJson(`/cloud/db/collections/${encodeURIComponent(N)}/docs/${encodeURIComponent(c)}`, { method: "DELETE" }).then(() => void 0)
382
+ };
383
+ }
384
+ query() {
385
+ return new WebCloudDbQueryBuilder(this.name);
386
+ }
387
+ };
388
+ const webCloud = {
389
+ kv: new WebCloudKv(),
390
+ db: { collection(c) {
391
+ let N = String(c).trim();
392
+ if (!N) throw new SDKError("INTERNAL_ERROR", "collection name is required");
393
+ return new WebCloudDbCollection(N);
394
+ } },
395
+ blob: {
396
+ async createUploadUrl() {
397
+ throw new SDKError("NOT_SUPPORTED", "cloud.blob is not implemented yet.");
398
+ },
399
+ async getDownloadUrl() {
400
+ throw new SDKError("NOT_SUPPORTED", "cloud.blob is not implemented yet.");
401
+ }
402
+ },
403
+ functions: { async call() {
404
+ throw new SDKError("NOT_SUPPORTED", "cloud.functions is not implemented yet.");
405
+ } }
406
+ };
407
+ var hostInfo = null, defaultCapabilities = {
150
408
  storage: !0,
151
409
  network: !1,
152
410
  scheduler: !1,
@@ -163,12 +421,12 @@ var SDKError = class e extends Error {
163
421
  capture: !1
164
422
  }
165
423
  };
166
- const updateHostInfo = (e) => {
167
- hostInfo = e;
424
+ const updateHostInfo = (c) => {
425
+ hostInfo = c;
168
426
  };
169
- var throwNotSupported = (e) => {
170
- throw new SDKError("NOT_SUPPORTED", `${e} is not supported in this environment.`);
171
- }, stubAsync = (e) => async () => throwNotSupported(e), stubHandler = (e) => () => throwNotSupported(e), aiAPI = {
427
+ var throwNotSupported = (c) => {
428
+ throw new SDKError("NOT_SUPPORTED", `${c} is not supported in this environment.`);
429
+ }, stubAsync = (c) => async () => throwNotSupported(c), stubHandler = (c) => () => throwNotSupported(c), aiAPI = {
172
430
  chat: stubAsync("ai.chat"),
173
431
  summarize: stubAsync("ai.summarize"),
174
432
  translate: stubAsync("ai.translate")
@@ -257,6 +515,8 @@ const { sdk, childMethods } = createSDK({
257
515
  } },
258
516
  statics: {
259
517
  SDKError,
518
+ auth: webAuth,
519
+ cloud: webCloud,
260
520
  ai: aiAPI,
261
521
  clipboard: clipboardAPI,
262
522
  dialog: dialogAPI,
@@ -265,8 +525,8 @@ const { sdk, childMethods } = createSDK({
265
525
  onFileDrop
266
526
  }
267
527
  });
268
- bootstrapSDK(childMethods, { timeoutMs: 1500 }).then((e) => {
269
- e && updateHostInfo(e);
528
+ bootstrapSDK(childMethods, { timeoutMs: 1500 }).then((c) => {
529
+ c && updateHostInfo(c);
270
530
  }), sdk.SDKError = SDKError;
271
531
  var src_default = sdk;
272
532
  export { src_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=Object.defineProperty,t=(e,t)=>()=>(e&&(t=e(e=0)),t),n=t=>{let n={};for(var r in t)e(n,r,{get:t[r],enumerable:!0});return n},r,i,a,o,s,c=t((()=>{(function(e){e.Call=`call`,e.Reply=`reply`,e.Syn=`syn`,e.SynAck=`synAck`,e.Ack=`ack`})(r||={}),(function(e){e.Fulfilled=`fulfilled`,e.Rejected=`rejected`})(i||={}),(function(e){e.ConnectionDestroyed=`ConnectionDestroyed`,e.ConnectionTimeout=`ConnectionTimeout`,e.NoIframeSrc=`NoIframeSrc`})(a||={}),(function(e){e.DataCloneError=`DataCloneError`})(o||={}),(function(e){e.Message=`message`})(s||={})})),l,u=t((()=>{l=(e,t)=>{let n=[],r=!1;return{destroy(i){r||(r=!0,t(`${e}: Destroying connection`),n.forEach(e=>{e(i)}))},onDestroy(e){r?e():n.push(e)}}}})),d,f=t((()=>{d=e=>(...t)=>{e&&console.log(`[Penpal]`,...t)}})),p,m,h=t((()=>{p=({name:e,message:t,stack:n})=>({name:e,message:t,stack:n}),m=e=>{let t=Error();return Object.keys(e).forEach(n=>t[n]=e[n]),t}})),g,_=t((()=>{h(),c(),g=(e,t,n)=>{let{localName:a,local:c,remote:l,originForSending:u,originForReceiving:d}=e,f=!1,m=e=>{if(e.source!==l||e.data.penpal!==r.Call)return;if(d!==`*`&&e.origin!==d){n(`${a} received message from origin ${e.origin} which did not match expected origin ${d}`);return}let{methodName:s,args:c,id:m}=e.data;n(`${a}: Received ${s}() call`);let h=e=>t=>{if(n(`${a}: Sending ${s}() reply`),f){n(`${a}: Unable to send ${s}() reply due to destroyed connection`);return}let c={penpal:r.Reply,id:m,resolution:e,returnValue:t};e===i.Rejected&&t instanceof Error&&(c.returnValue=p(t),c.returnValueIsError=!0);try{l.postMessage(c,u)}catch(e){if(e.name===o.DataCloneError){let t={penpal:r.Reply,id:m,resolution:i.Rejected,returnValue:p(e),returnValueIsError:!0};l.postMessage(t,u)}throw e}};new Promise(e=>e(t[s].apply(t,c))).then(h(i.Fulfilled),h(i.Rejected))};return c.addEventListener(s.Message,m),()=>{f=!0,c.removeEventListener(s.Message,m)}}})),v,y,ee=t((()=>{v=0,y=()=>++v})),b,x,S,C,w,T,E,D=t((()=>{b=`.`,x=e=>e?e.split(b):[],S=e=>e.join(b),C=(e,t)=>{let n=x(t||``);return n.push(e),S(n)},w=(e,t,n)=>{let r=x(t);return r.reduce((e,t,i)=>(e[t]===void 0&&(e[t]={}),i===r.length-1&&(e[t]=n),e[t]),e),e},T=(e,t)=>{let n={};return Object.keys(e).forEach(r=>{let i=e[r],a=C(r,t);typeof i==`object`&&Object.assign(n,T(i,a)),typeof i==`function`&&(n[a]=i)}),n},E=e=>{let t={};for(let n in e)w(t,n,e[n]);return t}})),O,k=t((()=>{ee(),h(),D(),c(),O=(e,t,n,o,c)=>{let{localName:l,local:u,remote:d,originForSending:f,originForReceiving:p}=t,h=!1;c(`${l}: Connecting call sender`);let g=e=>(...t)=>{c(`${l}: Sending ${e}() call`);let n;try{d.closed&&(n=!0)}catch{n=!0}if(n&&o(),h){let t=Error(`Unable to send ${e}() call due to destroyed connection`);throw t.code=a.ConnectionDestroyed,t}return new Promise((n,a)=>{let o=y(),h=t=>{if(t.source!==d||t.data.penpal!==r.Reply||t.data.id!==o)return;if(p!==`*`&&t.origin!==p){c(`${l} received message from origin ${t.origin} which did not match expected origin ${p}`);return}let f=t.data;c(`${l}: Received ${e}() reply`),u.removeEventListener(s.Message,h);let g=f.returnValue;f.returnValueIsError&&(g=m(g)),(f.resolution===i.Fulfilled?n:a)(g)};u.addEventListener(s.Message,h);let g={penpal:r.Call,id:o,methodName:e,args:t};d.postMessage(g,f)})},_=n.reduce((e,t)=>(e[t]=g(t),e),{});return Object.assign(e,E(_)),()=>{h=!0}}})),te=t((()=>{_(),k()})),ne=t((()=>{c()})),A,j=t((()=>{c(),A=(e,t)=>{let n;return e!==void 0&&(n=window.setTimeout(()=>{let n=Error(`Connection timed out after ${e}ms`);n.code=a.ConnectionTimeout,t(n)},e)),()=>{clearTimeout(n)}}})),re=t((()=>{c()})),ie=t((()=>{c(),te(),ne(),j(),re()})),M,ae=t((()=>{c(),_(),k(),M=(e,t,n,i)=>{let{destroy:a,onDestroy:o}=n;return n=>{if(!(e instanceof RegExp?e.test(n.origin):e===`*`||e===n.origin)){i(`Child: Handshake - Received SYN-ACK from origin ${n.origin} which did not match expected origin ${e}`);return}i(`Child: Handshake - Received SYN-ACK, responding with ACK`);let s=n.origin===`null`?`*`:n.origin,c={penpal:r.Ack,methodNames:Object.keys(t)};window.parent.postMessage(c,s);let l={localName:`Child`,local:window,remote:window.parent,originForSending:s,originForReceiving:n.origin};o(g(l,t,i));let u={};return o(O(u,l,n.data.methodNames,a,i)),u}}})),N,P,oe=t((()=>{u(),f(),c(),ae(),D(),j(),N=()=>{try{clearTimeout()}catch{return!1}return!0},P=(e={})=>{let{parentOrigin:t=`*`,methods:n={},timeout:i,debug:a=!1}=e,o=d(a),c=l(`Child`,o),{destroy:u,onDestroy:f}=c,p=M(t,T(n),c,o),m=()=>{o(`Child: Handshake - Sending SYN`);let e={penpal:r.Syn},n=t instanceof RegExp?`*`:t;window.parent.postMessage(e,n)};return{promise:new Promise((e,t)=>{let n=A(i,u),a=t=>{if(N()&&!(t.source!==parent||!t.data)&&t.data.penpal===r.SynAck){let r=p(t);r&&(window.removeEventListener(s.Message,a),n(),e(r))}};window.addEventListener(s.Message,a),m(),f(e=>{window.removeEventListener(s.Message,a),e&&t(e)})}),destroy(){u()}}}})),se=t((()=>{ie(),oe(),c()})),ce=n({callHost:()=>I,createRPCProxy:()=>L,getHost:()=>ue,hasConnectionFailed:()=>fe,initConnection:()=>pe,isConnected:()=>de,tryGetHost:()=>F,withFallback:()=>me});function le(){try{return window.self!==window.top}catch{return!0}}async function F(e,t){if(z)return z;if(B)return null;if(!le())return B=!0,null;if(!R){let n={},r=e??V;r&&Object.assign(n,r),R=P({methods:n,timeout:t?.timeoutMs??H}).promise.then(e=>(z=e,e)).catch(e=>(console.error(`[GemiGo Connection] Promise failed:`,e),B=!0,R=null,null))}return R}async function ue(){let e=await F();if(!e)throw Error(`Not connected to host. SDK may be running outside of a supported environment.`);return e}function de(){return z!==null}function fe(){return B}function pe(e,t){V=e,F(e,t)}async function I(e,t=[],n){let r=await F();if(r&&typeof r[e]==`function`){let i=await r[e](...t);if(i?.success!==!1)return i?.data===void 0?i?.value===void 0?i:i.value:i.data;if(n)return n(...t);throw Error(i?.error||`Host method ${String(e)} failed`)}if(n)return n(...t);throw Error(`Method ${String(e)} not supported in this environment`)}function L(e,t={}){let n={};for(let r of e){let e=t.mapping?.[r]||r,i=t.fallbacks?.[r];n[r]=(...t)=>I(e,t,i)}return n}function me(e,t){return async(...n)=>{try{return await e(...n)}catch{return t(...n)}}}var R,z,B,V,H,U=t((()=>{se(),R=null,z=null,B=!1,H=1500}));U();function W(){let e=new Map;return{on(t,n){return e.has(t)||e.set(t,new Set),e.get(t).add(n),()=>e.get(t)?.delete(n)},emit(t,...n){e.get(t)?.forEach(e=>e(...n))},off(t){t?e.delete(t):e.clear()}}}let G=W();function he(e){let t=F,n={},r={};if(e.rpc){let t=L(e.rpc.methods,{mapping:e.rpc.mapping,fallbacks:e.rpc.fallbacks});Object.assign(n,t)}if(e.events)if(Array.isArray(e.events))for(let i of e.events){let e=i;n[i]=n=>(t?.(),G.on(e,n)),r[i]=(...t)=>{G.emit(e,...t)}}else for(let[i,a]of Object.entries(e.events)){if(!a)continue;let e=a,o=typeof e==`string`?e:e.event,s=typeof e==`object`&&`childMethod`in e&&e.childMethod?e.childMethod:i;n[i]=e=>(t?.(),G.on(o,e)),r[s]=(...e)=>{G.emit(o,...e)}}return{api:n,childMethods:r}}function ge(e,t){return async(...n)=>{try{let r=await I(e,t.transform?t.transform(...n):n);return t.onSuccess?t.onSuccess(r):r}catch{return t.fallback(...n)}}}function _e(e){let t=e.statics?{...e.statics}:{},n={};if(e.modules)for(let[r,i]of Object.entries(e.modules)){let{api:e,childMethods:a}=he(i);t[r]=e,Object.assign(n,a)}if(e.actions)for(let[n,r]of Object.entries(e.actions)){let e=r;t[n]=ge(e.method,e)}if(e.getters)for(let[n,r]of Object.entries(e.getters))Object.defineProperty(t,n,{get:r,enumerable:!0,configurable:!0});return{sdk:t,childMethods:n}}async function ve(e,t={}){let{initConnection:n}=await Promise.resolve().then(()=>(U(),ce));n(e,t);let r=await F();if(r&&typeof r.getProtocolInfo==`function`)try{return await r.getProtocolInfo()}catch{return null}return null}U();var K=()=>`gemigo:${typeof window>`u`?`unknown`:window.location.origin.replace(/[:/]/g,`_`)}:`;let q={get:async e=>{if(typeof window>`u`||!window.localStorage)return null;let t=window.localStorage.getItem(`${K()}${e}`);if(!t)return null;try{return JSON.parse(t)}catch{return null}},set:async(e,t)=>{typeof window>`u`||!window.localStorage||window.localStorage.setItem(`${K()}${e}`,JSON.stringify(t))},delete:async e=>{typeof window>`u`||!window.localStorage||window.localStorage.removeItem(`${K()}${e}`)},clear:async()=>{if(typeof window>`u`||!window.localStorage)return;let e=K();for(let t=window.localStorage.length-1;t>=0;--t){let n=window.localStorage.key(t);n&&n.startsWith(e)&&window.localStorage.removeItem(n)}}},ye=async e=>{if(typeof window>`u`||typeof Notification>`u`)return{success:!1,reason:`not_supported`};if(Notification.permission!==`granted`)return{success:!1,reason:`permission_not_granted`};try{return new Notification(e.title,{body:e.message,icon:e.icon}),{success:!0}}catch{return{success:!1,reason:`failed_to_notify`}}},be={request:async(e,t)=>{let{method:n=`GET`,headers:r,body:i,responseType:a}=t??{},o=await fetch(e,{method:n,headers:r,body:i?typeof i==`string`?i:JSON.stringify(i):void 0}),s={};o.headers.forEach((e,t)=>s[t]=e);let c=a===`text`?await o.text():a===`arraybuffer`?await o.arrayBuffer():await o.json();return{status:o.status,data:c,headers:s}}};var J=class e extends Error{constructor(t,n){super(n),this.code=t,this.name=`SDKError`,Object.setPrototypeOf(this,e.prototype)}},Y=null,xe={storage:!0,network:!1,scheduler:!1,fileWatch:!1,fileWrite:!1,notification:!0,clipboard:!1,ai:!1,shell:!1,extension:{read:!1,events:!1,modify:!1,capture:!1}};let Se=e=>{Y=e};var X=e=>{throw new J(`NOT_SUPPORTED`,`${e} is not supported in this environment.`)},Z=e=>async()=>X(e),Q=e=>()=>X(e),Ce={chat:Z(`ai.chat`),summarize:Z(`ai.summarize`),translate:Z(`ai.translate`)},we={readText:Z(`clipboard.readText`),writeText:Z(`clipboard.writeText`),readImage:Z(`clipboard.readImage`),writeImage:Z(`clipboard.writeImage`),onChange:Q(`clipboard.onChange`)},Te={openFile:Z(`dialog.openFile`),openDirectory:Z(`dialog.openDirectory`),saveFile:Z(`dialog.saveFile`),message:Z(`dialog.message`)},Ee={readText:Z(`file.readText`),readBinary:Z(`file.readBinary`),write:Z(`file.write`),append:Z(`file.append`),exists:Z(`file.exists`),stat:Z(`file.stat`),copy:Z(`file.copy`),move:Z(`file.move`),remove:Z(`file.remove`),list:Z(`file.list`),mkdir:Z(`file.mkdir`),persistPermission:Z(`file.persistPermission`)},De=Q(`onNotificationAction`),Oe=Q(`onFileDrop`);let{sdk:$,childMethods:ke}=_e({getters:{platform:()=>Y?.platform??`web`,capabilities:()=>Y?.capabilities??xe},modules:{storage:{rpc:{methods:[`get`,`set`,`delete`,`clear`],mapping:{get:`storageGet`,set:`storageSet`,delete:`storageDelete`,clear:`storageClear`},fallbacks:{get:q.get,set:q.set,delete:q.delete,clear:q.clear}}},network:{rpc:{methods:[`request`],mapping:{request:`networkRequest`},fallbacks:{request:be.request}}},extension:{rpc:{methods:[`getPageInfo`,`getPageHTML`,`getPageText`,`getSelection`,`extractArticle`,`extractLinks`,`extractImages`,`queryElement`,`highlight`,`removeHighlight`,`insertWidget`,`updateWidget`,`removeWidget`,`injectCSS`,`removeCSS`,`captureVisible`,`getContextMenuEvent`]},events:[`onContextMenu`,`onSelectionChange`]}},actions:{notify:{method:`notify`,fallback:ye}},statics:{SDKError:J,ai:Ce,clipboard:we,dialog:Te,file:Ee,onNotificationAction:De,onFileDrop:Oe}});return ve(ke,{timeoutMs:1500}).then(e=>{e&&Se(e)}),$.SDKError=J,$});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?module.exports=t():typeof define==`function`&&define.amd?define([],t):(e=typeof globalThis<`u`?globalThis:e||self,e.gemigo=t())})(this,function(){var e=Object.defineProperty,t=(e,t)=>()=>(e&&(t=e(e=0)),t),n=t=>{let n={};for(var r in t)e(n,r,{get:t[r],enumerable:!0});return n},r,i,a,o,s,c=t((()=>{(function(e){e.Call=`call`,e.Reply=`reply`,e.Syn=`syn`,e.SynAck=`synAck`,e.Ack=`ack`})(r||={}),(function(e){e.Fulfilled=`fulfilled`,e.Rejected=`rejected`})(i||={}),(function(e){e.ConnectionDestroyed=`ConnectionDestroyed`,e.ConnectionTimeout=`ConnectionTimeout`,e.NoIframeSrc=`NoIframeSrc`})(a||={}),(function(e){e.DataCloneError=`DataCloneError`})(o||={}),(function(e){e.Message=`message`})(s||={})})),l,u=t((()=>{l=(e,t)=>{let n=[],r=!1;return{destroy(i){r||(r=!0,t(`${e}: Destroying connection`),n.forEach(e=>{e(i)}))},onDestroy(e){r?e():n.push(e)}}}})),d,f=t((()=>{d=e=>(...t)=>{e&&console.log(`[Penpal]`,...t)}})),p,m,h=t((()=>{p=({name:e,message:t,stack:n})=>({name:e,message:t,stack:n}),m=e=>{let t=Error();return Object.keys(e).forEach(n=>t[n]=e[n]),t}})),g,_=t((()=>{h(),c(),g=(e,t,n)=>{let{localName:a,local:c,remote:l,originForSending:u,originForReceiving:d}=e,f=!1,m=e=>{if(e.source!==l||e.data.penpal!==r.Call)return;if(d!==`*`&&e.origin!==d){n(`${a} received message from origin ${e.origin} which did not match expected origin ${d}`);return}let{methodName:s,args:c,id:m}=e.data;n(`${a}: Received ${s}() call`);let h=e=>t=>{if(n(`${a}: Sending ${s}() reply`),f){n(`${a}: Unable to send ${s}() reply due to destroyed connection`);return}let c={penpal:r.Reply,id:m,resolution:e,returnValue:t};e===i.Rejected&&t instanceof Error&&(c.returnValue=p(t),c.returnValueIsError=!0);try{l.postMessage(c,u)}catch(e){if(e.name===o.DataCloneError){let t={penpal:r.Reply,id:m,resolution:i.Rejected,returnValue:p(e),returnValueIsError:!0};l.postMessage(t,u)}throw e}};new Promise(e=>e(t[s].apply(t,c))).then(h(i.Fulfilled),h(i.Rejected))};return c.addEventListener(s.Message,m),()=>{f=!0,c.removeEventListener(s.Message,m)}}})),v,ee,te=t((()=>{v=0,ee=()=>++v})),y,b,ne,x,S,C,w,T=t((()=>{y=`.`,b=e=>e?e.split(y):[],ne=e=>e.join(y),x=(e,t)=>{let n=b(t||``);return n.push(e),ne(n)},S=(e,t,n)=>{let r=b(t);return r.reduce((e,t,i)=>(e[t]===void 0&&(e[t]={}),i===r.length-1&&(e[t]=n),e[t]),e),e},C=(e,t)=>{let n={};return Object.keys(e).forEach(r=>{let i=e[r],a=x(r,t);typeof i==`object`&&Object.assign(n,C(i,a)),typeof i==`function`&&(n[a]=i)}),n},w=e=>{let t={};for(let n in e)S(t,n,e[n]);return t}})),E,D=t((()=>{te(),h(),T(),c(),E=(e,t,n,o,c)=>{let{localName:l,local:u,remote:d,originForSending:f,originForReceiving:p}=t,h=!1;c(`${l}: Connecting call sender`);let g=e=>(...t)=>{c(`${l}: Sending ${e}() call`);let n;try{d.closed&&(n=!0)}catch{n=!0}if(n&&o(),h){let t=Error(`Unable to send ${e}() call due to destroyed connection`);throw t.code=a.ConnectionDestroyed,t}return new Promise((n,a)=>{let o=ee(),h=t=>{if(t.source!==d||t.data.penpal!==r.Reply||t.data.id!==o)return;if(p!==`*`&&t.origin!==p){c(`${l} received message from origin ${t.origin} which did not match expected origin ${p}`);return}let f=t.data;c(`${l}: Received ${e}() reply`),u.removeEventListener(s.Message,h);let g=f.returnValue;f.returnValueIsError&&(g=m(g)),(f.resolution===i.Fulfilled?n:a)(g)};u.addEventListener(s.Message,h);let g={penpal:r.Call,id:o,methodName:e,args:t};d.postMessage(g,f)})},_=n.reduce((e,t)=>(e[t]=g(t),e),{});return Object.assign(e,w(_)),()=>{h=!0}}})),re=t((()=>{_(),D()})),ie=t((()=>{c()})),O,k=t((()=>{c(),O=(e,t)=>{let n;return e!==void 0&&(n=window.setTimeout(()=>{let n=Error(`Connection timed out after ${e}ms`);n.code=a.ConnectionTimeout,t(n)},e)),()=>{clearTimeout(n)}}})),ae=t((()=>{c()})),oe=t((()=>{c(),re(),ie(),k(),ae()})),A,se=t((()=>{c(),_(),D(),A=(e,t,n,i)=>{let{destroy:a,onDestroy:o}=n;return n=>{if(!(e instanceof RegExp?e.test(n.origin):e===`*`||e===n.origin)){i(`Child: Handshake - Received SYN-ACK from origin ${n.origin} which did not match expected origin ${e}`);return}i(`Child: Handshake - Received SYN-ACK, responding with ACK`);let s=n.origin===`null`?`*`:n.origin,c={penpal:r.Ack,methodNames:Object.keys(t)};window.parent.postMessage(c,s);let l={localName:`Child`,local:window,remote:window.parent,originForSending:s,originForReceiving:n.origin};o(g(l,t,i));let u={};return o(E(u,l,n.data.methodNames,a,i)),u}}})),j,M,ce=t((()=>{u(),f(),c(),se(),T(),k(),j=()=>{try{clearTimeout()}catch{return!1}return!0},M=(e={})=>{let{parentOrigin:t=`*`,methods:n={},timeout:i,debug:a=!1}=e,o=d(a),c=l(`Child`,o),{destroy:u,onDestroy:f}=c,p=A(t,C(n),c,o),m=()=>{o(`Child: Handshake - Sending SYN`);let e={penpal:r.Syn},n=t instanceof RegExp?`*`:t;window.parent.postMessage(e,n)};return{promise:new Promise((e,t)=>{let n=O(i,u),a=t=>{if(j()&&!(t.source!==parent||!t.data)&&t.data.penpal===r.SynAck){let r=p(t);r&&(window.removeEventListener(s.Message,a),n(),e(r))}};window.addEventListener(s.Message,a),m(),f(e=>{window.removeEventListener(s.Message,a),e&&t(e)})}),destroy(){u()}}}})),le=t((()=>{oe(),ce(),c()})),ue=n({callHost:()=>P,createRPCProxy:()=>ge,getHost:()=>fe,hasConnectionFailed:()=>me,initConnection:()=>he,isConnected:()=>pe,tryGetHost:()=>N,withFallback:()=>_e});function de(){try{return window.self!==window.top}catch{return!0}}async function N(e,t){if(I)return I;if(L)return null;if(!de())return L=!0,null;if(!F){let n={},r=e??R;r&&Object.assign(n,r),F=M({methods:n,timeout:t?.timeoutMs??z}).promise.then(e=>(I=e,e)).catch(e=>(console.error(`[GemiGo Connection] Promise failed:`,e),L=!0,F=null,null))}return F}async function fe(){let e=await N();if(!e)throw Error(`Not connected to host. SDK may be running outside of a supported environment.`);return e}function pe(){return I!==null}function me(){return L}function he(e,t){R=e,N(e,t)}async function P(e,t=[],n){let r=await N();if(r&&typeof r[e]==`function`){let i=await r[e](...t);if(i?.success!==!1)return i?.data===void 0?i?.value===void 0?i:i.value:i.data;if(n)return n(...t);throw Error(i?.error||`Host method ${String(e)} failed`)}if(n)return n(...t);throw Error(`Method ${String(e)} not supported in this environment`)}function ge(e,t={}){let n={};for(let r of e){let e=t.mapping?.[r]||r,i=t.fallbacks?.[r];n[r]=(...t)=>P(e,t,i)}return n}function _e(e,t){return async(...n)=>{try{return await e(...n)}catch{return t(...n)}}}var F,I,L,R,z,B=t((()=>{le(),F=null,I=null,L=!1,z=1500}));B();function ve(){let e=new Map;return{on(t,n){return e.has(t)||e.set(t,new Set),e.get(t).add(n),()=>e.get(t)?.delete(n)},emit(t,...n){e.get(t)?.forEach(e=>e(...n))},off(t){t?e.delete(t):e.clear()}}}let V=ve();function ye(e){let t=N,n={},r={};if(e.rpc){let t=ge(e.rpc.methods,{mapping:e.rpc.mapping,fallbacks:e.rpc.fallbacks});Object.assign(n,t)}if(e.events)if(Array.isArray(e.events))for(let i of e.events){let e=i;n[i]=n=>(t?.(),V.on(e,n)),r[i]=(...t)=>{V.emit(e,...t)}}else for(let[i,a]of Object.entries(e.events)){if(!a)continue;let e=a,o=typeof e==`string`?e:e.event,s=typeof e==`object`&&`childMethod`in e&&e.childMethod?e.childMethod:i;n[i]=e=>(t?.(),V.on(o,e)),r[s]=(...e)=>{V.emit(o,...e)}}return{api:n,childMethods:r}}function be(e,t){return async(...n)=>{try{let r=await P(e,t.transform?t.transform(...n):n);return t.onSuccess?t.onSuccess(r):r}catch{return t.fallback(...n)}}}function xe(e){let t=e.statics?{...e.statics}:{},n={};if(e.modules)for(let[r,i]of Object.entries(e.modules)){let{api:e,childMethods:a}=ye(i);t[r]=e,Object.assign(n,a)}if(e.actions)for(let[n,r]of Object.entries(e.actions)){let e=r;t[n]=be(e.method,e)}if(e.getters)for(let[n,r]of Object.entries(e.getters))Object.defineProperty(t,n,{get:r,enumerable:!0,configurable:!0});return{sdk:t,childMethods:n}}async function Se(e,t={}){let{initConnection:n}=await Promise.resolve().then(()=>(B(),ue));n(e,t);let r=await N();if(r&&typeof r.getProtocolInfo==`function`)try{return await r.getProtocolInfo()}catch{return null}return null}B();var H=()=>`gemigo:${typeof window>`u`?`unknown`:window.location.origin.replace(/[:/]/g,`_`)}:`;let U={get:async e=>{if(typeof window>`u`||!window.localStorage)return null;let t=window.localStorage.getItem(`${H()}${e}`);if(!t)return null;try{return JSON.parse(t)}catch{return null}},set:async(e,t)=>{typeof window>`u`||!window.localStorage||window.localStorage.setItem(`${H()}${e}`,JSON.stringify(t))},delete:async e=>{typeof window>`u`||!window.localStorage||window.localStorage.removeItem(`${H()}${e}`)},clear:async()=>{if(typeof window>`u`||!window.localStorage)return;let e=H();for(let t=window.localStorage.length-1;t>=0;--t){let n=window.localStorage.key(t);n&&n.startsWith(e)&&window.localStorage.removeItem(n)}}},Ce=async e=>{if(typeof window>`u`||typeof Notification>`u`)return{success:!1,reason:`not_supported`};if(Notification.permission!==`granted`)return{success:!1,reason:`permission_not_granted`};try{return new Notification(e.title,{body:e.message,icon:e.icon}),{success:!0}}catch{return{success:!1,reason:`failed_to_notify`}}},we={request:async(e,t)=>{let{method:n=`GET`,headers:r,body:i,responseType:a}=t??{},o=await fetch(e,{method:n,headers:r,body:i?typeof i==`string`?i:JSON.stringify(i):void 0}),s={};o.headers.forEach((e,t)=>s[t]=e);let c=a===`text`?await o.text():a===`arraybuffer`?await o.arrayBuffer():await o.json();return{status:o.status,data:c,headers:s}}};var W=class e extends Error{constructor(t,n){super(n),this.code=t,this.name=`SDKError`,Object.setPrototypeOf(this,e.prototype)}},G=null,K=null;function q(e){let t=``;for(let n of e)t+=String.fromCharCode(n);let n=globalThis.btoa;if(!n)throw Error(`base64 encoder not available`);return n(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function J(e=32){let t=new Uint8Array(e);return crypto.getRandomValues(t),q(t)}async function Te(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t);return q(new Uint8Array(n))}function Ee(){if(typeof window>`u`)return`unknown`;let e=window.location.hostname.toLowerCase();return e.endsWith(`.gemigo.app`)?e.replace(/\.gemigo\.app$/,``):e}function De(e){let t=(e??[`identity:basic`]).map(e=>String(e).trim()).filter(Boolean);return t.length>0?t:[`identity:basic`]}function Oe(e){let t=new URL(`/sdk/broker`,e.platformOrigin);return t.searchParams.set(`app_id`,e.appId),t.searchParams.set(`scope`,e.scopes.join(` `)),t.searchParams.set(`state`,e.state),t.searchParams.set(`code_challenge`,e.codeChallenge),t.searchParams.set(`code_challenge_method`,`S256`),t.searchParams.set(`origin`,e.openerOrigin),t.toString()}async function ke(e,t,n){let r=await fetch(`${e.replace(/\/+$/,``)}/sdk/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({code:t,codeVerifier:n})});if(!r.ok){let e=await r.json().catch(()=>({}));throw Error(e.error||`Failed to exchange code`)}return await r.json()}function Ae(){return K||`https://gemigo.io/api/v1`}let Y={async login(e={}){if(typeof window>`u`)throw new W(`NOT_SUPPORTED`,`auth.login is only supported in browser environments.`);let t=e.platformOrigin?.trim()||`https://gemigo.io`,n=e.apiBaseUrl?.trim()||`${t.replace(/\/+$/,``)}/api/v1`,r=e.appId?.trim()||Ee(),i=De(e.scopes),a=typeof e.timeoutMs==`number`?e.timeoutMs:120*1e3,o=J(16),s=J(48),c=window.location.origin,l=Math.max(0,(window.screen.width-520)/2),u=Math.max(0,(window.screen.height-720)/2),d=window.open(`about:blank`,`gemigo_sdk_auth`,`popup=yes,width=520,height=720,left=${l},top=${u}`);if(!d)throw Error(`Popup blocked. Please allow popups and retry.`);try{d.document.title=`GemiGo Auth`,d.document.body.innerHTML=`<div style="font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;padding:24px;">Loading…</div>`}catch{}let f=Oe({platformOrigin:t,appId:r,scopes:i,state:o,codeChallenge:await Te(s),openerOrigin:c});try{d.location.href=f}catch{if(!window.open(f,`gemigo_sdk_auth`))throw Error(`Popup navigation failed. Please allow popups and retry.`)}let p=await ke(n,(await new Promise((e,n)=>{let r=window.setTimeout(()=>{i(),n(Error(`Login timeout.`))},a),i=()=>{window.clearTimeout(r),window.removeEventListener(`message`,s);try{d.close()}catch{}},s=r=>{if(r.origin!==new URL(t).origin)return;let a=r.data;if(!(!a||typeof a!=`object`)&&a.state===o){if(a.type===`gemigo:sdk-auth-error`){i(),n(Error(String(a.error||`auth_error`)));return}a.type===`gemigo:sdk-auth-code`&&typeof a.code==`string`&&(i(),e({code:a.code}))}};window.addEventListener(`message`,s)})).code,s);return G=p,K=n,p},getAccessToken(){return G?.accessToken??null},logout(){G=null}};function je(){let e=Y.getAccessToken();if(!e)throw new W(`PERMISSION_DENIED`,`Login required. Call gemigo.auth.login() first.`);return e}async function X(e,t={}){let n=je(),r=Ae().replace(/\/+$/,``),i=await fetch(`${r}${e}`,{...t,headers:{...t.headers??{},Authorization:`Bearer ${n}`}});if(!i.ok){let e=(await i.json().catch(()=>({}))).error||`Request failed: ${i.status}`;throw i.status===401||i.status===403?new W(`PERMISSION_DENIED`,e):new W(`INTERNAL_ERROR`,e)}return await i.json()}var Me=class{async get(e){return X(`/cloud/kv/get?key=${encodeURIComponent(e)}`)}async set(e,t,n){return X(`/cloud/kv/set`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:e,value:t,ifMatch:n?.ifMatch})})}async delete(e,t){await X(`/cloud/kv/delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:e,ifMatch:t?.ifMatch})})}async list(e){let t=new URLSearchParams;e?.prefix&&t.set(`prefix`,e.prefix),typeof e?.limit==`number`&&t.set(`limit`,String(e.limit)),e?.cursor&&t.set(`cursor`,e.cursor);let n=t.toString();return X(`/cloud/kv/list${n?`?${n}`:``}`)}},Ne=class e{constructor(e,t){this.collectionName=e,this.state={where:t?.where??[],orderBy:t?.orderBy??{field:`createdAt`,direction:`desc`},limit:t?.limit??20,cursor:t?.cursor??null}}where(t,n,r){return new e(this.collectionName,{...this.state,where:[...this.state.where,{field:t,op:n,value:r}]})}orderBy(t,n=`desc`){return new e(this.collectionName,{...this.state,orderBy:{field:t,direction:n}})}limit(t){return new e(this.collectionName,{...this.state,limit:t})}startAfter(t){return new e(this.collectionName,{...this.state,cursor:t})}async get(){return X(`/cloud/db/collections/${encodeURIComponent(this.collectionName)}/query`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({where:this.state.where,orderBy:this.state.orderBy,limit:this.state.limit,cursor:this.state.cursor})})}},Pe=class{constructor(e){this.name=e}async add(e,t){return X(`/cloud/db/collections/${encodeURIComponent(this.name)}/docs`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({id:t?.id,visibility:t?.visibility,refType:t?.refType,refId:t?.refId,data:e})})}doc(e){let t=this.name;return{get:async()=>X(`/cloud/db/collections/${encodeURIComponent(t)}/docs/${encodeURIComponent(e)}`),update:async(n,r)=>X(`/cloud/db/collections/${encodeURIComponent(t)}/docs/${encodeURIComponent(e)}`,{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify({patch:n,ifMatch:r?.ifMatch})}),delete:async()=>X(`/cloud/db/collections/${encodeURIComponent(t)}/docs/${encodeURIComponent(e)}`,{method:`DELETE`}).then(()=>void 0)}}query(){return new Ne(this.name)}};let Fe={kv:new Me,db:{collection(e){let t=String(e).trim();if(!t)throw new W(`INTERNAL_ERROR`,`collection name is required`);return new Pe(t)}},blob:{async createUploadUrl(){throw new W(`NOT_SUPPORTED`,`cloud.blob is not implemented yet.`)},async getDownloadUrl(){throw new W(`NOT_SUPPORTED`,`cloud.blob is not implemented yet.`)}},functions:{async call(){throw new W(`NOT_SUPPORTED`,`cloud.functions is not implemented yet.`)}}};var Z=null,Ie={storage:!0,network:!1,scheduler:!1,fileWatch:!1,fileWrite:!1,notification:!0,clipboard:!1,ai:!1,shell:!1,extension:{read:!1,events:!1,modify:!1,capture:!1}};let Le=e=>{Z=e};var Re=e=>{throw new W(`NOT_SUPPORTED`,`${e} is not supported in this environment.`)},Q=e=>async()=>Re(e),$=e=>()=>Re(e),ze={chat:Q(`ai.chat`),summarize:Q(`ai.summarize`),translate:Q(`ai.translate`)},Be={readText:Q(`clipboard.readText`),writeText:Q(`clipboard.writeText`),readImage:Q(`clipboard.readImage`),writeImage:Q(`clipboard.writeImage`),onChange:$(`clipboard.onChange`)},Ve={openFile:Q(`dialog.openFile`),openDirectory:Q(`dialog.openDirectory`),saveFile:Q(`dialog.saveFile`),message:Q(`dialog.message`)},He={readText:Q(`file.readText`),readBinary:Q(`file.readBinary`),write:Q(`file.write`),append:Q(`file.append`),exists:Q(`file.exists`),stat:Q(`file.stat`),copy:Q(`file.copy`),move:Q(`file.move`),remove:Q(`file.remove`),list:Q(`file.list`),mkdir:Q(`file.mkdir`),persistPermission:Q(`file.persistPermission`)},Ue=$(`onNotificationAction`),We=$(`onFileDrop`);let{sdk:Ge,childMethods:Ke}=xe({getters:{platform:()=>Z?.platform??`web`,capabilities:()=>Z?.capabilities??Ie},modules:{storage:{rpc:{methods:[`get`,`set`,`delete`,`clear`],mapping:{get:`storageGet`,set:`storageSet`,delete:`storageDelete`,clear:`storageClear`},fallbacks:{get:U.get,set:U.set,delete:U.delete,clear:U.clear}}},network:{rpc:{methods:[`request`],mapping:{request:`networkRequest`},fallbacks:{request:we.request}}},extension:{rpc:{methods:[`getPageInfo`,`getPageHTML`,`getPageText`,`getSelection`,`extractArticle`,`extractLinks`,`extractImages`,`queryElement`,`highlight`,`removeHighlight`,`insertWidget`,`updateWidget`,`removeWidget`,`injectCSS`,`removeCSS`,`captureVisible`,`getContextMenuEvent`]},events:[`onContextMenu`,`onSelectionChange`]}},actions:{notify:{method:`notify`,fallback:Ce}},statics:{SDKError:W,auth:Y,cloud:Fe,ai:ze,clipboard:Be,dialog:Ve,file:He,onNotificationAction:Ue,onFileDrop:We}});return Se(Ke,{timeoutMs:1500}).then(e=>{e&&Le(e)}),Ge.SDKError=W,Ge});
@@ -0,0 +1,35 @@
1
+ export type AuthScope = 'identity:basic' | 'storage:rw' | string;
2
+ export interface AuthLoginOptions {
3
+ /**
4
+ * App identifier used for consent + app-scoped identity.
5
+ * In GemiGo hosted apps, default is derived from `<slug>.gemigo.app`.
6
+ */
7
+ appId?: string;
8
+ scopes?: AuthScope[];
9
+ /**
10
+ * Platform origin that hosts the broker page, e.g. `https://gemigo.io`.
11
+ * Defaults to `https://gemigo.io`.
12
+ */
13
+ platformOrigin?: string;
14
+ /**
15
+ * API base URL, e.g. `https://gemigo.io/api/v1` (or `https://api.gemigo.io/api/v1`).
16
+ * Defaults to `${platformOrigin}/api/v1`.
17
+ */
18
+ apiBaseUrl?: string;
19
+ /**
20
+ * Popup wait timeout.
21
+ */
22
+ timeoutMs?: number;
23
+ }
24
+ export interface AuthTokenResponse {
25
+ accessToken: string;
26
+ expiresIn: number;
27
+ appId: string;
28
+ appUserId: string;
29
+ scopes: string[];
30
+ }
31
+ export interface AuthAPI {
32
+ login(options?: AuthLoginOptions): Promise<AuthTokenResponse>;
33
+ getAccessToken(): string | null;
34
+ logout(): void;
35
+ }
@@ -0,0 +1,104 @@
1
+ export type CloudScope = 'identity:basic' | 'storage:rw' | 'db:rw' | 'blob:rw' | 'functions:invoke' | string;
2
+ export type CloudVisibility = 'private' | 'public' | string;
3
+ export interface CloudKvItemMeta {
4
+ key: string;
5
+ etag: string;
6
+ updatedAt: number;
7
+ valueBytes: number;
8
+ }
9
+ export interface CloudKvAPI {
10
+ get<T = unknown>(key: string): Promise<{
11
+ key: string;
12
+ value: T;
13
+ etag: string;
14
+ updatedAt: number;
15
+ }>;
16
+ set(key: string, value: unknown, options?: {
17
+ ifMatch?: string;
18
+ }): Promise<{
19
+ key: string;
20
+ etag: string;
21
+ updatedAt: number;
22
+ }>;
23
+ delete(key: string, options?: {
24
+ ifMatch?: string;
25
+ }): Promise<void>;
26
+ list(options?: {
27
+ prefix?: string;
28
+ limit?: number;
29
+ cursor?: string | null;
30
+ }): Promise<{
31
+ items: CloudKvItemMeta[];
32
+ nextCursor: string | null;
33
+ }>;
34
+ }
35
+ export interface CloudDbDoc<T = unknown> {
36
+ id: string;
37
+ ownerId: string;
38
+ visibility: CloudVisibility;
39
+ refType: string | null;
40
+ refId: string | null;
41
+ data: T;
42
+ createdAt: number;
43
+ updatedAt: number;
44
+ etag: string;
45
+ }
46
+ export type CloudDbWhereOp = '==';
47
+ export interface CloudDbWhere {
48
+ field: 'ownerId' | 'visibility' | 'refType' | 'refId';
49
+ op: CloudDbWhereOp;
50
+ value: string;
51
+ }
52
+ export interface CloudDbQueryInput {
53
+ where?: CloudDbWhere[];
54
+ orderBy?: {
55
+ field: 'createdAt' | 'updatedAt';
56
+ direction: 'asc' | 'desc';
57
+ };
58
+ limit?: number;
59
+ cursor?: string | null;
60
+ }
61
+ export interface CloudDbQueryResult<T = unknown> {
62
+ items: Array<CloudDbDoc<T>>;
63
+ nextCursor: string | null;
64
+ }
65
+ export interface CloudDbDocumentRef<T = unknown> {
66
+ get(): Promise<CloudDbDoc<T>>;
67
+ update(patch: Partial<T>, options?: {
68
+ ifMatch?: string;
69
+ }): Promise<CloudDbDoc<T>>;
70
+ delete(): Promise<void>;
71
+ }
72
+ export interface CloudDbQueryBuilder<T = unknown> {
73
+ where(field: CloudDbWhere['field'], op: CloudDbWhereOp, value: string): CloudDbQueryBuilder<T>;
74
+ orderBy(field: 'createdAt' | 'updatedAt', direction?: 'asc' | 'desc'): CloudDbQueryBuilder<T>;
75
+ limit(n: number): CloudDbQueryBuilder<T>;
76
+ startAfter(cursor: string): CloudDbQueryBuilder<T>;
77
+ get(): Promise<CloudDbQueryResult<T>>;
78
+ }
79
+ export interface CloudDbCollection<T = unknown> {
80
+ add(data: T, options?: {
81
+ id?: string;
82
+ visibility?: CloudVisibility;
83
+ refType?: string;
84
+ refId?: string;
85
+ }): Promise<CloudDbDoc<T>>;
86
+ doc(id: string): CloudDbDocumentRef<T>;
87
+ query(): CloudDbQueryBuilder<T>;
88
+ }
89
+ export interface CloudDbAPI {
90
+ collection<T = unknown>(name: string): CloudDbCollection<T>;
91
+ }
92
+ export interface CloudBlobAPI {
93
+ createUploadUrl(_input: unknown): Promise<never>;
94
+ getDownloadUrl(_input: unknown): Promise<never>;
95
+ }
96
+ export interface CloudFunctionsAPI {
97
+ call(_name: string, _payload: unknown): Promise<never>;
98
+ }
99
+ export interface CloudAPI {
100
+ kv: CloudKvAPI;
101
+ db: CloudDbAPI;
102
+ blob: CloudBlobAPI;
103
+ functions: CloudFunctionsAPI;
104
+ }
@@ -1,5 +1,7 @@
1
1
  import { Platform, Capabilities, SDKError, FileEntry } from './common';
2
2
  import { StorageAPI } from './storage';
3
+ import { AuthAPI } from './auth';
4
+ import { CloudAPI } from './cloud';
3
5
  import { NotifyOptions, NotifyResult } from './notify';
4
6
  import { AIAPI } from './ai';
5
7
  import { ClipboardAPI } from './clipboard';
@@ -16,6 +18,8 @@ import { ExtensionAPI } from './extension';
16
18
  export type { Platform, Capabilities, FileEntry, FileStat, RPCResult, RPCResultWithData, SDKErrorCode, } from './common';
17
19
  export { SDKError } from './common';
18
20
  export type { StorageAPI } from './storage';
21
+ export type { AuthAPI, AuthLoginOptions, AuthScope, AuthTokenResponse } from './auth';
22
+ export type { CloudAPI, CloudScope, CloudVisibility, CloudKvAPI, CloudKvItemMeta, CloudDbAPI, CloudDbCollection, CloudDbDoc, CloudDbDocumentRef, CloudDbQueryBuilder, CloudDbQueryInput, CloudDbQueryResult, CloudDbWhere, CloudDbWhereOp, CloudBlobAPI, CloudFunctionsAPI, } from './cloud';
19
23
  export type { NotifyAction, NotifyOptions, NotifyResult, NotifyFn, NotificationActionHandler, } from './notify';
20
24
  export type { ChatMessage, ChatResponse, TranslateOptions, TranslateResult, AIAPI } from './ai';
21
25
  export type { ClipboardContent, ClipboardChangeCallback, ClipboardAPI } from './clipboard';
@@ -42,6 +46,10 @@ export interface GemigoSDK {
42
46
  readonly SDKError: typeof SDKError;
43
47
  /** Persistent key-value storage */
44
48
  storage: StorageAPI;
49
+ /** App identity & login (App SDK V0) */
50
+ auth: AuthAPI;
51
+ /** Gemigo Cloud (hosted backend) */
52
+ cloud: CloudAPI;
45
53
  /**
46
54
  * Send system notification
47
55
  * @param options - Notification options
@@ -0,0 +1,3 @@
1
+ import { AuthAPI } from '../types/auth';
2
+ export declare function getWebApiBaseUrl(): string;
3
+ export declare const webAuth: AuthAPI;
@@ -0,0 +1,2 @@
1
+ import { CloudAPI } from '../types/cloud';
2
+ export declare const webCloud: CloudAPI;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gemigo/app-sdk",
3
3
  "private": false,
4
- "version": "0.2.5",
4
+ "version": "0.2.6",
5
5
  "type": "module",
6
6
  "description": "GemiGo App SDK (auto-adapts for web/desktop/extension)",
7
7
  "main": "dist/gemigo-app-sdk.umd.js",