@omnizapi/connect 1.0.0 → 1.0.2

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.
@@ -65,12 +65,22 @@ var getConstants = ({
65
65
  // src/core/runtime.ts
66
66
  var runtimeKey = /* @__PURE__ */ Symbol.for("omnizapi.connect.runtime.v1");
67
67
  function getRuntime(host) {
68
+ var _a, _b, _c;
68
69
  const target = host;
69
70
  let runtime = target[runtimeKey];
70
71
  if (!runtime) {
71
- runtime = { nativeLoginPending: false, failedFacebookScripts: /* @__PURE__ */ new WeakSet() };
72
+ runtime = {
73
+ nativeLoginPending: false,
74
+ failedFacebookScripts: /* @__PURE__ */ new WeakSet(),
75
+ erroredFacebookScripts: /* @__PURE__ */ new WeakSet(),
76
+ facebookAppIds: /* @__PURE__ */ new WeakMap(),
77
+ facebookInitObservers: /* @__PURE__ */ new WeakMap()
78
+ };
72
79
  Object.defineProperty(target, runtimeKey, { configurable: true, value: runtime });
73
80
  }
81
+ (_a = runtime.facebookAppIds) != null ? _a : runtime.facebookAppIds = /* @__PURE__ */ new WeakMap();
82
+ (_b = runtime.facebookInitObservers) != null ? _b : runtime.facebookInitObservers = /* @__PURE__ */ new WeakMap();
83
+ (_c = runtime.erroredFacebookScripts) != null ? _c : runtime.erroredFacebookScripts = /* @__PURE__ */ new WeakSet();
74
84
  return runtime;
75
85
  }
76
86
 
@@ -78,108 +88,238 @@ function getRuntime(host) {
78
88
  function isReadySdk(sdk) {
79
89
  return !!sdk && !("__buffer" in sdk) && typeof sdk.init === "function" && typeof sdk.login === "function";
80
90
  }
91
+ function observeFacebookInit(runtime, fb) {
92
+ var _a;
93
+ try {
94
+ const descriptor = Object.getOwnPropertyDescriptor(fb, "init");
95
+ const existing = runtime.facebookInitObservers.get(fb);
96
+ if (existing) {
97
+ if ((descriptor == null ? void 0 : descriptor.value) !== existing.init) throw new Error("FB.init was replaced.");
98
+ return existing;
99
+ }
100
+ if (!descriptor || typeof descriptor.value !== "function" || !descriptor.writable && !descriptor.configurable) {
101
+ throw new Error("FB.init cannot be observed.");
102
+ }
103
+ const original = descriptor.value;
104
+ const observer = {
105
+ calls: 0,
106
+ init: function(...args) {
107
+ observer.calls++;
108
+ runtime.facebookAppIds.delete(fb);
109
+ return Reflect.apply(original, this, args);
110
+ }
111
+ };
112
+ Object.defineProperty(fb, "init", { ...descriptor, value: observer.init });
113
+ if (((_a = Object.getOwnPropertyDescriptor(fb, "init")) == null ? void 0 : _a.value) !== observer.init) throw new Error("FB.init was not replaced.");
114
+ runtime.facebookInitObservers.set(fb, observer);
115
+ return observer;
116
+ } catch (e) {
117
+ runtime.facebookAppIds.delete(fb);
118
+ throw new OmnizapiError(
119
+ "INVALID_CONFIGURATION",
120
+ "The Meta SDK initialization cannot be observed safely. Use the popup flow or reload a fresh page."
121
+ );
122
+ }
123
+ }
124
+ function initializeFacebookSdk(host, fb, appId) {
125
+ var _a;
126
+ if (host.FB !== fb || !fb || "__buffer" in fb || typeof fb.login !== "function") {
127
+ throw new OmnizapiError("INVALID_CONFIGURATION", "The Meta SDK is not ready or was replaced before initialization.");
128
+ }
129
+ if (typeof appId !== "string" || !/^[0-9]+$/.test(appId)) {
130
+ throw new OmnizapiError("INVALID_CONFIGURATION", "A numeric Meta appId is required for native login.");
131
+ }
132
+ const runtime = getRuntime(host);
133
+ if (runtime.facebookAppIds.get(fb) === null && (runtime.facebookLoadUncertain || runtime.facebookLoading || typeof host.fbAsyncInit === "function")) {
134
+ runtime.facebookAppIds.delete(fb);
135
+ }
136
+ const initializedAppId = runtime.facebookAppIds.get(fb);
137
+ if (initializedAppId === void 0 || initializedAppId !== null && !runtime.facebookInitObservers.has(fb)) {
138
+ runtime.facebookAppIds.delete(fb);
139
+ throw new OmnizapiError(
140
+ "INVALID_CONFIGURATION",
141
+ "The host Meta SDK configuration is unknown. Use the popup flow or a fresh page without a host-initialized SDK for native login."
142
+ );
143
+ }
144
+ const observer = observeFacebookInit(runtime, fb);
145
+ if (initializedAppId !== null) {
146
+ if (initializedAppId !== appId) {
147
+ throw new OmnizapiError(
148
+ "INVALID_CONFIGURATION",
149
+ "The Meta SDK is already initialized for another app. Use the popup flow or reload a fresh page before changing apps."
150
+ );
151
+ }
152
+ return;
153
+ }
154
+ const calls = observer.calls;
155
+ runtime.facebookAppIds.delete(fb);
156
+ try {
157
+ fb.init({ appId, version: "v25.0", autoLogAppEvents: true, xfbml: true });
158
+ } catch (e) {
159
+ throw new OmnizapiError("PROVIDER_ERROR", "The Meta SDK could not be initialized.");
160
+ }
161
+ if (observer.calls !== calls + 1 || host.FB !== fb || ((_a = Object.getOwnPropertyDescriptor(fb, "init")) == null ? void 0 : _a.value) !== observer.init) {
162
+ throw new OmnizapiError("INVALID_CONFIGURATION", "The Meta SDK changed during initialization. Use the popup flow or reload a fresh page.");
163
+ }
164
+ runtime.facebookAppIds.set(fb, appId);
165
+ }
81
166
  function loadFacebookSdk(host, signal) {
82
167
  if (signal.aborted) {
83
168
  return Promise.reject(new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
84
169
  }
85
- if (isReadySdk(host.FB)) {
86
- return Promise.resolve(host.FB);
87
- }
88
170
  const runtime = getRuntime(host);
89
- const existing = runtime.facebookLoading;
90
- if (existing) return existing;
91
- const loading = Promise.resolve().then(() => new Promise((resolve, reject) => {
92
- let settled = false;
93
- let script;
94
- let ownedScript = false;
95
- let previous;
96
- let previousCallback;
97
- const finish = (sdk, error) => {
98
- if (settled) return;
99
- settled = true;
100
- clearTimeout(timer);
101
- signal.removeEventListener("abort", onAbort);
102
- script == null ? void 0 : script.removeEventListener("load", onLoad);
103
- script == null ? void 0 : script.removeEventListener("error", onError);
104
- try {
105
- if (host.fbAsyncInit === onReady) {
106
- if (previous) Object.defineProperty(host, "fbAsyncInit", previous);
107
- else Reflect.deleteProperty(host, "fbAsyncInit");
108
- }
109
- } catch (e) {
110
- }
111
- if (error && script) {
112
- if (!signal.aborted) runtime.failedFacebookScripts.add(script);
113
- if (ownedScript) {
171
+ let loading = runtime.facebookLoadObserver;
172
+ if (!loading && isReadySdk(host.FB)) {
173
+ loading = { promise: Promise.resolve(host.FB), consumers: 0 };
174
+ }
175
+ if (!loading) {
176
+ const shared2 = {
177
+ consumers: 0,
178
+ // Register the observer and its consumers before setup can fail synchronously.
179
+ promise: Promise.resolve().then(() => new Promise((resolve, reject) => {
180
+ var _a;
181
+ let settled = false;
182
+ let script;
183
+ let ownedScript = false;
184
+ let freshSdk = false;
185
+ let bootstrap;
186
+ let previous;
187
+ let previousCallback;
188
+ const finish = (sdk, error, definitiveFailure = false) => {
189
+ if (settled) return;
190
+ settled = true;
191
+ clearTimeout(timer);
192
+ script == null ? void 0 : script.removeEventListener("load", onLoad);
193
+ script == null ? void 0 : script.removeEventListener("error", onError);
114
194
  try {
115
- script.remove();
195
+ if (host.fbAsyncInit === onReady) {
196
+ if (previous) Object.defineProperty(host, "fbAsyncInit", previous);
197
+ else Reflect.deleteProperty(host, "fbAsyncInit");
198
+ }
116
199
  } catch (e) {
117
200
  }
201
+ if (error && script) {
202
+ runtime.failedFacebookScripts.add(script);
203
+ if (definitiveFailure) runtime.erroredFacebookScripts.add(script);
204
+ else if (!ownedScript) runtime.facebookLoadUncertain = true;
205
+ if (ownedScript) {
206
+ try {
207
+ script.remove();
208
+ } catch (e) {
209
+ }
210
+ }
211
+ }
212
+ if (runtime.facebookLoadObserver === shared2) delete runtime.facebookLoadObserver;
213
+ if (sdk) resolve(sdk);
214
+ else reject(error);
215
+ };
216
+ const onLoad = () => {
217
+ var _a2;
218
+ if (settled) return;
219
+ const sdk = host.FB;
220
+ if (!sdk) return;
221
+ if ("__buffer" in sdk) bootstrap = sdk;
222
+ if (((_a2 = bootstrap == null ? void 0 : bootstrap.__buffer) == null ? void 0 : _a2.opts) != null || host.fbAsyncInit !== onReady || (script == null ? void 0 : script.onload) || runtime.facebookLoading || runtime.facebookLoadUncertain) {
223
+ freshSdk = false;
224
+ if (runtime.facebookAppIds.get(sdk) === null) runtime.facebookAppIds.delete(sdk);
225
+ if (bootstrap && runtime.facebookAppIds.get(bootstrap) === null) runtime.facebookAppIds.delete(bootstrap);
226
+ }
227
+ const ready = isReadySdk(sdk);
228
+ if (freshSdk && runtime.facebookAppIds.get(sdk) == null) {
229
+ if (!ready) runtime.facebookAppIds.set(sdk, null);
230
+ else if (!runtime.facebookInitObservers.has(sdk)) {
231
+ try {
232
+ observeFacebookInit(runtime, sdk);
233
+ runtime.facebookAppIds.set(sdk, null);
234
+ } catch (e) {
235
+ }
236
+ }
237
+ }
238
+ if (ready) finish(sdk);
239
+ };
240
+ const onError = () => finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK could not be loaded."), true);
241
+ const onReady = () => {
242
+ if (settled) return;
243
+ try {
244
+ previousCallback == null ? void 0 : previousCallback.call(host);
245
+ } catch (e) {
246
+ }
247
+ onLoad();
248
+ };
249
+ const timer = setTimeout(() => finish(void 0, new OmnizapiError(
250
+ "SDK_LOAD_FAILED",
251
+ "The Meta SDK load timed out."
252
+ )), 30 * 1e3);
253
+ shared2.cancelIfUnused = () => {
254
+ if (ownedScript && shared2.consumers === 0) {
255
+ finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
256
+ }
257
+ };
258
+ try {
259
+ previous = Object.getOwnPropertyDescriptor(host, "fbAsyncInit");
260
+ previousCallback = typeof host.fbAsyncInit === "function" ? host.fbAsyncInit : void 0;
261
+ const document = host.document;
262
+ const byId = document.getElementById("facebook-jssdk");
263
+ script = Array.from(document.scripts).find((candidate) => {
264
+ try {
265
+ const url = new URL(candidate.src);
266
+ if (url.origin !== "https://connect.facebook.net" || !/^\/[^/]+\/sdk\.js$/.test(url.pathname)) return false;
267
+ if (!runtime.failedFacebookScripts.has(candidate)) return true;
268
+ if (!runtime.erroredFacebookScripts.has(candidate)) runtime.facebookLoadUncertain = true;
269
+ return false;
270
+ } catch (e) {
271
+ return false;
272
+ }
273
+ });
274
+ if (!script) {
275
+ script = document.createElement("script");
276
+ ownedScript = true;
277
+ const initialSdk = host.FB;
278
+ if (initialSdk && "__buffer" in initialSdk) bootstrap = initialSdk;
279
+ freshSdk = !runtime.facebookLoadUncertain && !runtime.facebookLoading && !previousCallback && (!initialSdk || !!bootstrap && runtime.facebookAppIds.get(initialSdk) === null && ((_a = bootstrap.__buffer) == null ? void 0 : _a.opts) == null);
280
+ if (!byId) script.id = "facebook-jssdk";
281
+ script.src = "https://connect.facebook.net/en_US/sdk.js";
282
+ script.crossOrigin = "anonymous";
283
+ script.async = true;
284
+ script.defer = true;
285
+ }
286
+ shared2.cancelIfUnused();
287
+ if (settled) return;
288
+ Object.defineProperty(host, "fbAsyncInit", previous && !previous.configurable ? { value: onReady } : { configurable: true, enumerable: true, writable: true, value: onReady });
289
+ script.addEventListener("load", onLoad);
290
+ script.addEventListener("error", onError);
291
+ onLoad();
292
+ if (!settled && ownedScript) document.head.appendChild(script);
293
+ } catch (e) {
294
+ finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK could not be loaded."));
118
295
  }
119
- }
120
- if (runtime.facebookLoading === loading) delete runtime.facebookLoading;
121
- if (sdk) resolve(sdk);
122
- else reject(error);
296
+ }))
123
297
  };
124
- const onLoad = () => {
125
- if (settled) return;
126
- const sdk = host.FB;
127
- if (isReadySdk(sdk)) finish(sdk);
128
- };
129
- const onError = () => finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK could not be loaded."));
130
- const onAbort = () => finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
131
- const onReady = () => {
298
+ runtime.facebookLoadObserver = loading = shared2;
299
+ }
300
+ const shared = loading;
301
+ return new Promise((resolve, reject) => {
302
+ let settled = false;
303
+ shared.consumers++;
304
+ const complete = (sdk, error) => {
305
+ var _a;
132
306
  if (settled) return;
133
- try {
134
- previousCallback == null ? void 0 : previousCallback.call(host);
135
- } catch (e) {
136
- }
137
- onLoad();
307
+ settled = true;
308
+ signal.removeEventListener("abort", onAbort);
309
+ shared.consumers--;
310
+ if (sdk) resolve(sdk);
311
+ else reject(error);
312
+ (_a = shared.cancelIfUnused) == null ? void 0 : _a.call(shared);
138
313
  };
139
- const timer = setTimeout(() => finish(void 0, new OmnizapiError(
140
- "SDK_LOAD_FAILED",
141
- "The Meta SDK load timed out."
142
- )), 30 * 1e3);
143
- try {
144
- signal.addEventListener("abort", onAbort, { once: true });
145
- if (signal.aborted) {
146
- onAbort();
147
- return;
148
- }
149
- previous = Object.getOwnPropertyDescriptor(host, "fbAsyncInit");
150
- previousCallback = typeof host.fbAsyncInit === "function" ? host.fbAsyncInit : void 0;
151
- Object.defineProperty(host, "fbAsyncInit", previous && !previous.configurable ? { value: onReady } : { configurable: true, enumerable: true, writable: true, value: onReady });
152
- const document = host.document;
153
- const byId = document.getElementById("facebook-jssdk");
154
- const existingScript = (byId == null ? void 0 : byId.tagName.toLowerCase()) === "script" ? byId : void 0;
155
- script = (existingScript && !runtime.failedFacebookScripts.has(existingScript) ? existingScript : void 0) || Array.from(document.scripts).find((candidate) => {
156
- if (runtime.failedFacebookScripts.has(candidate)) return false;
157
- try {
158
- const url = new URL(candidate.src);
159
- return url.origin === "https://connect.facebook.net" && /^\/[^/]+\/sdk\.js$/.test(url.pathname);
160
- } catch (e) {
161
- return false;
162
- }
163
- });
164
- if (!script) {
165
- script = document.createElement("script");
166
- ownedScript = true;
167
- if (!byId) script.id = "facebook-jssdk";
168
- script.src = "https://connect.facebook.net/en_US/sdk.js";
169
- script.crossOrigin = "anonymous";
170
- script.async = true;
171
- script.defer = true;
172
- }
173
- script.addEventListener("load", onLoad);
174
- script.addEventListener("error", onError);
175
- onLoad();
176
- if (!settled && ownedScript) document.head.appendChild(script);
177
- } catch (e) {
178
- onError();
179
- }
180
- }));
181
- runtime.facebookLoading = loading;
182
- return loading;
314
+ const onAbort = () => complete(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
315
+ void shared.promise.then(
316
+ (sdk) => signal.aborted ? onAbort() : complete(sdk),
317
+ // A shared observer may belong to another module copy's OmnizapiError class.
318
+ (error) => complete(void 0, new OmnizapiError("SDK_LOAD_FAILED", error.message))
319
+ );
320
+ signal.addEventListener("abort", onAbort, { once: true });
321
+ if (signal.aborted) onAbort();
322
+ });
183
323
  }
184
324
 
185
325
  // src/core/open-popup.ts
@@ -260,8 +400,8 @@ function requestJson(url, init, signal) {
260
400
  else resolve(value);
261
401
  };
262
402
  const onAbort = () => complete(void 0, new OmnizapiError(
263
- "NETWORK_ERROR",
264
- "The API request was cancelled."
403
+ "ABORTED",
404
+ "The API request was aborted."
265
405
  ));
266
406
  const timer = setTimeout(() => complete(void 0, new OmnizapiError(
267
407
  "TIMEOUT",
@@ -318,10 +458,14 @@ var OmnizapiClientImpl = class {
318
458
  frontUrl: props.frontUrl
319
459
  });
320
460
  }
321
- async getListMessengerPages(channelId, code) {
461
+ async getListMessengerPages(channelId, code, signal) {
322
462
  if (!stringOrNull(channelId) || !stringOrNull(code)) {
323
463
  throw new OmnizapiError("INVALID_OPTIONS", "A channelId and authorization code are required.");
324
464
  }
465
+ if (signal !== void 0 && (!isRecord(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) {
466
+ throw new OmnizapiError("INVALID_OPTIONS", "The abort signal is invalid.");
467
+ }
468
+ if (signal == null ? void 0 : signal.aborted) throw new OmnizapiError("ABORTED", "The API request was aborted.");
325
469
  return requestJson(
326
470
  new URL(`${this.constants.api}/v1/channels/${encodeChannelId(channelId)}/list-messenger-pages`),
327
471
  {
@@ -331,7 +475,8 @@ var OmnizapiClientImpl = class {
331
475
  code
332
476
  }),
333
477
  headers: { "Content-Type": "application/json", Authorization: this.publicKey }
334
- }
478
+ },
479
+ signal
335
480
  );
336
481
  }
337
482
  async connect(options) {
@@ -348,10 +493,11 @@ var OmnizapiClientImpl = class {
348
493
  if (!isRecord(options)) {
349
494
  throw new OmnizapiError("INVALID_OPTIONS", "Connection options are required.");
350
495
  }
351
- const { channelId, direct, getQRCode, timeoutMs = TOTAL_TIMEOUT_MS } = options;
352
- if (typeof channelId !== "string" || direct !== void 0 && typeof direct !== "boolean" || getQRCode !== void 0 && typeof getQRCode !== "function" || typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647) {
353
- throw new OmnizapiError("INVALID_OPTIONS", "Invalid channelId, direct, getQRCode or timeoutMs option.");
496
+ const { channelId, direct, getQRCode, timeoutMs = TOTAL_TIMEOUT_MS, signal } = options;
497
+ if (typeof channelId !== "string" || direct !== void 0 && typeof direct !== "boolean" || getQRCode !== void 0 && typeof getQRCode !== "function" || typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647 || signal !== void 0 && (!isRecord(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) {
498
+ throw new OmnizapiError("INVALID_OPTIONS", "Invalid channelId, direct, getQRCode, timeoutMs or signal option.");
354
499
  }
500
+ if (signal == null ? void 0 : signal.aborted) throw new OmnizapiError("ABORTED", "The connection was aborted.");
355
501
  if (!channelId.trim()) return failure(channelId, null, "invalid_channel");
356
502
  const encodedChannelId = encodeChannelId(channelId);
357
503
  if (typeof host.open !== "function" || typeof host.addEventListener !== "function" || typeof host.removeEventListener !== "function" || typeof host.location.origin !== "string" || typeof host.location.href !== "string" || typeof ((_a = host.crypto) == null ? void 0 : _a.getRandomValues) !== "function" || typeof AbortController !== "function" || typeof fetch !== "function") {
@@ -369,16 +515,28 @@ var OmnizapiClientImpl = class {
369
515
  let channelType = null;
370
516
  let redirectUri = null;
371
517
  let popup = null;
518
+ let popupError;
372
519
  let timeout;
373
520
  let popupTimer;
374
521
  let messageListener;
375
522
  let nativeLoginStarted = false;
523
+ let callbackReceived = false;
524
+ const releaseNativeLogin = () => {
525
+ if (runtime.nativeLoginOwner === owner) {
526
+ runtime.nativeLoginPending = false;
527
+ delete runtime.nativeLoginOwner;
528
+ }
529
+ };
376
530
  const globals = [];
377
531
  const finish = (outcome) => {
378
532
  if (settled) return;
379
533
  settled = true;
380
534
  clearTimeout(timeout);
381
535
  clearInterval(popupTimer);
536
+ try {
537
+ signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
538
+ } catch (e) {
539
+ }
382
540
  if (messageListener) {
383
541
  try {
384
542
  host.removeEventListener("message", messageListener);
@@ -405,19 +563,49 @@ var OmnizapiClientImpl = class {
405
563
  }
406
564
  }
407
565
  if (runtime.activeConnection === owner) delete runtime.activeConnection;
408
- if (nativeLoginStarted && !(outcome instanceof OmnizapiError) && outcome.success) {
409
- runtime.nativeLoginPending = false;
566
+ if (nativeLoginStarted && (callbackReceived || !(outcome instanceof OmnizapiError) && outcome.success)) {
567
+ releaseNativeLogin();
410
568
  }
411
569
  if (outcome instanceof OmnizapiError) reject(outcome);
412
570
  else resolve(outcome);
413
571
  };
572
+ const onAbort = () => finish(new OmnizapiError("ABORTED", "The connection was aborted."));
414
573
  const isLive = () => {
574
+ if (!settled && (signal == null ? void 0 : signal.aborted)) onAbort();
415
575
  if (!settled && Date.now() >= deadline) {
416
576
  finish(new OmnizapiError("TIMEOUT", "The connection timed out."));
417
577
  }
418
578
  return !settled;
419
579
  };
420
580
  const fail = (reason) => finish(failure(channelId, channelType, reason));
581
+ const reservePopup = () => {
582
+ try {
583
+ const opened = openPopup("about:blank", "_blank", 600, 740);
584
+ if (!opened || opened === host) throw new Error("Popup unavailable");
585
+ if (!isLive()) {
586
+ opened.close();
587
+ return;
588
+ }
589
+ popup = opened;
590
+ } catch (e) {
591
+ throw new OmnizapiError("POPUP_BLOCKED", "The connection popup could not be opened.");
592
+ }
593
+ };
594
+ const watchPopup = () => {
595
+ if (popupTimer) return;
596
+ popupTimer = setInterval(() => {
597
+ if (!isLive()) return;
598
+ try {
599
+ if (popup == null ? void 0 : popup.closed) fail("popup_closed");
600
+ } catch (e) {
601
+ finish(new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be monitored."));
602
+ }
603
+ }, 500);
604
+ };
605
+ const unwatchPopup = () => {
606
+ clearInterval(popupTimer);
607
+ popupTimer = void 0;
608
+ };
421
609
  const succeed = (data) => {
422
610
  if (!isLive() || !channelType) return;
423
611
  finish({
@@ -436,6 +624,8 @@ var OmnizapiClientImpl = class {
436
624
  };
437
625
  try {
438
626
  runtime.activeConnection = owner;
627
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
628
+ if (!isLive()) return;
439
629
  const bytes = host.crypto.getRandomValues(new Uint8Array(16));
440
630
  const attemptId = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
441
631
  for (const [name, value] of [
@@ -451,6 +641,12 @@ var OmnizapiClientImpl = class {
451
641
  "TIMEOUT",
452
642
  "The connection timed out."
453
643
  )), timeoutMs);
644
+ try {
645
+ reservePopup();
646
+ } catch (error) {
647
+ popupError = error instanceof OmnizapiError ? error : new OmnizapiError("POPUP_BLOCKED", "The connection popup could not be opened.");
648
+ }
649
+ if (!isLive()) return;
454
650
  const run = async () => {
455
651
  var _a2, _b, _c;
456
652
  const info = await requestJson(
@@ -468,7 +664,13 @@ var OmnizapiClientImpl = class {
468
664
  }
469
665
  const middleware = info.middleware;
470
666
  channelType = isChannelType(middleware) ? middleware : null;
471
- if (currentOrigin !== frontOrigin && !allowOrigins.some((origin) => currentOrigin === origin.replace(/\/$/, ""))) {
667
+ if (currentOrigin !== frontOrigin && !allowOrigins.some((origin) => {
668
+ try {
669
+ return currentOrigin === new URL(origin).origin;
670
+ } catch (e) {
671
+ return false;
672
+ }
673
+ })) {
472
674
  fail("origin_not_allowed");
473
675
  return;
474
676
  }
@@ -481,26 +683,34 @@ var OmnizapiClientImpl = class {
481
683
  if (channelType.startsWith("META_") && !appId || channelType === "META_WHATSAPP" && !configId) {
482
684
  throw new OmnizapiError("INVALID_RESPONSE", "The channel provider configuration is invalid.");
483
685
  }
484
- if (channelType === "META_WHATSAPP" && (direct || Boolean(info.appCustom) || currentOrigin === frontOrigin)) {
686
+ const nativeWhatsApp = channelType === "META_WHATSAPP" && (direct || Boolean(info.appCustom) || currentOrigin === frontOrigin);
687
+ let nativeReady = false;
688
+ let fb;
689
+ if (nativeWhatsApp) {
690
+ unwatchPopup();
485
691
  if (runtime.nativeLoginPending) {
486
692
  throw new OmnizapiError(
487
693
  "CONNECTION_IN_PROGRESS",
488
694
  "A previous Meta login is incomplete. Reload this window before retrying a native login."
489
695
  );
490
696
  }
491
- const fb = await loadFacebookSdk(host, controller.signal);
697
+ fb = await loadFacebookSdk(host, controller.signal);
492
698
  if (!isLive()) return;
493
699
  try {
494
- fb.init({ appId, version: "v25.0", autoLogAppEvents: true, xfbml: true });
495
- } catch (e) {
496
- throw new OmnizapiError("PROVIDER_ERROR", "The Meta SDK could not be initialized.");
700
+ initializeFacebookSdk(host, fb, appId);
701
+ nativeReady = true;
702
+ } catch (error) {
703
+ if (!(error instanceof OmnizapiError && error.code === "INVALID_CONFIGURATION")) throw error;
497
704
  }
498
705
  if (!isLive()) return;
706
+ }
707
+ if (nativeReady && fb) {
708
+ popup == null ? void 0 : popup.close();
709
+ popup = null;
499
710
  let code = null;
500
711
  let wabaId = null;
501
712
  let phoneId = null;
502
713
  let coexistence = false;
503
- let callbackReceived = false;
504
714
  const completeNative = () => {
505
715
  if (!isLive() || !code || !wabaId) return;
506
716
  succeed({ code, wabaId, phoneId, coexistence });
@@ -533,11 +743,17 @@ var OmnizapiClientImpl = class {
533
743
  };
534
744
  host.addEventListener("message", messageListener);
535
745
  runtime.nativeLoginPending = true;
746
+ runtime.nativeLoginOwner = owner;
536
747
  nativeLoginStarted = true;
537
748
  try {
538
749
  fb.login((response) => {
539
- if (!isLive() || callbackReceived) return;
750
+ if (callbackReceived) return;
540
751
  callbackReceived = true;
752
+ if (settled) {
753
+ releaseNativeLogin();
754
+ return;
755
+ }
756
+ if (!isLive()) return;
541
757
  if (!isRecord(response) || response.error) {
542
758
  finish(new OmnizapiError("PROVIDER_ERROR", "Meta returned an invalid login response."));
543
759
  return;
@@ -563,6 +779,8 @@ var OmnizapiClientImpl = class {
563
779
  }
564
780
  });
565
781
  } catch (e) {
782
+ releaseNativeLogin();
783
+ nativeLoginStarted = false;
566
784
  throw new OmnizapiError("PROVIDER_ERROR", "The Meta login could not be started.");
567
785
  }
568
786
  return;
@@ -589,6 +807,7 @@ var OmnizapiClientImpl = class {
589
807
  } else {
590
808
  url = new URL(`${this.constants.front}/connect/${channelType === "BOT_TELEGRAM" ? "telegram" : "whatsapp-web"}`);
591
809
  url.searchParams.set("channelId", channelId);
810
+ url.searchParams.set("pk", this.publicKey);
592
811
  }
593
812
  if (channelType !== "META_MESSENGER" && channelType !== "META_INSTAGRAM") {
594
813
  url.searchParams.set("attemptId", attemptId);
@@ -609,23 +828,18 @@ var OmnizapiClientImpl = class {
609
828
  };
610
829
  host.addEventListener("message", messageListener);
611
830
  if (!isLive()) return;
831
+ if (popupError) throw popupError;
832
+ if (!popup) reservePopup();
833
+ if (popup == null ? void 0 : popup.closed) {
834
+ fail("popup_closed");
835
+ return;
836
+ }
837
+ watchPopup();
612
838
  try {
613
- const opened = openPopup(url.href, "_blank", 600, 740);
614
- if (!opened || opened === host) {
615
- throw new OmnizapiError("POPUP_BLOCKED", "The connection popup was blocked.");
616
- }
617
- popup = opened;
839
+ popup == null ? void 0 : popup.location.replace(url.href);
618
840
  } catch (e) {
619
- throw new OmnizapiError("POPUP_BLOCKED", "The connection popup could not be opened.");
841
+ throw new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be navigated.");
620
842
  }
621
- popupTimer = setInterval(() => {
622
- if (!isLive()) return;
623
- try {
624
- if (popup == null ? void 0 : popup.closed) fail("popup_closed");
625
- } catch (e) {
626
- finish(new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be monitored."));
627
- }
628
- }, 500);
629
843
  };
630
844
  void run().catch((error) => {
631
845
  if (!isLive()) return;
@@ -634,8 +848,8 @@ var OmnizapiClientImpl = class {
634
848
  "The connection could not be completed."
635
849
  ));
636
850
  });
637
- } catch (e) {
638
- finish(new OmnizapiError("INVALID_CONFIGURATION", "The connection could not be initialized."));
851
+ } catch (error) {
852
+ finish(error instanceof OmnizapiError ? error : new OmnizapiError("INVALID_CONFIGURATION", "The connection could not be initialized."));
639
853
  }
640
854
  });
641
855
  } catch (error) {