@omnizapi/connect 1.0.1 → 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,6 +515,7 @@ 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;
@@ -386,6 +533,10 @@ var OmnizapiClientImpl = class {
386
533
  settled = true;
387
534
  clearTimeout(timeout);
388
535
  clearInterval(popupTimer);
536
+ try {
537
+ signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
538
+ } catch (e) {
539
+ }
389
540
  if (messageListener) {
390
541
  try {
391
542
  host.removeEventListener("message", messageListener);
@@ -418,13 +569,43 @@ var OmnizapiClientImpl = class {
418
569
  if (outcome instanceof OmnizapiError) reject(outcome);
419
570
  else resolve(outcome);
420
571
  };
572
+ const onAbort = () => finish(new OmnizapiError("ABORTED", "The connection was aborted."));
421
573
  const isLive = () => {
574
+ if (!settled && (signal == null ? void 0 : signal.aborted)) onAbort();
422
575
  if (!settled && Date.now() >= deadline) {
423
576
  finish(new OmnizapiError("TIMEOUT", "The connection timed out."));
424
577
  }
425
578
  return !settled;
426
579
  };
427
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
+ };
428
609
  const succeed = (data) => {
429
610
  if (!isLive() || !channelType) return;
430
611
  finish({
@@ -443,6 +624,8 @@ var OmnizapiClientImpl = class {
443
624
  };
444
625
  try {
445
626
  runtime.activeConnection = owner;
627
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
628
+ if (!isLive()) return;
446
629
  const bytes = host.crypto.getRandomValues(new Uint8Array(16));
447
630
  const attemptId = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
448
631
  for (const [name, value] of [
@@ -458,6 +641,12 @@ var OmnizapiClientImpl = class {
458
641
  "TIMEOUT",
459
642
  "The connection timed out."
460
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;
461
650
  const run = async () => {
462
651
  var _a2, _b, _c;
463
652
  const info = await requestJson(
@@ -475,7 +664,13 @@ var OmnizapiClientImpl = class {
475
664
  }
476
665
  const middleware = info.middleware;
477
666
  channelType = isChannelType(middleware) ? middleware : null;
478
- 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
+ })) {
479
674
  fail("origin_not_allowed");
480
675
  return;
481
676
  }
@@ -488,21 +683,30 @@ var OmnizapiClientImpl = class {
488
683
  if (channelType.startsWith("META_") && !appId || channelType === "META_WHATSAPP" && !configId) {
489
684
  throw new OmnizapiError("INVALID_RESPONSE", "The channel provider configuration is invalid.");
490
685
  }
491
- 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();
492
691
  if (runtime.nativeLoginPending) {
493
692
  throw new OmnizapiError(
494
693
  "CONNECTION_IN_PROGRESS",
495
694
  "A previous Meta login is incomplete. Reload this window before retrying a native login."
496
695
  );
497
696
  }
498
- const fb = await loadFacebookSdk(host, controller.signal);
697
+ fb = await loadFacebookSdk(host, controller.signal);
499
698
  if (!isLive()) return;
500
699
  try {
501
- fb.init({ appId, version: "v25.0", autoLogAppEvents: true, xfbml: true });
502
- } catch (e) {
503
- 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;
504
704
  }
505
705
  if (!isLive()) return;
706
+ }
707
+ if (nativeReady && fb) {
708
+ popup == null ? void 0 : popup.close();
709
+ popup = null;
506
710
  let code = null;
507
711
  let wabaId = null;
508
712
  let phoneId = null;
@@ -575,6 +779,8 @@ var OmnizapiClientImpl = class {
575
779
  }
576
780
  });
577
781
  } catch (e) {
782
+ releaseNativeLogin();
783
+ nativeLoginStarted = false;
578
784
  throw new OmnizapiError("PROVIDER_ERROR", "The Meta login could not be started.");
579
785
  }
580
786
  return;
@@ -601,6 +807,7 @@ var OmnizapiClientImpl = class {
601
807
  } else {
602
808
  url = new URL(`${this.constants.front}/connect/${channelType === "BOT_TELEGRAM" ? "telegram" : "whatsapp-web"}`);
603
809
  url.searchParams.set("channelId", channelId);
810
+ url.searchParams.set("pk", this.publicKey);
604
811
  }
605
812
  if (channelType !== "META_MESSENGER" && channelType !== "META_INSTAGRAM") {
606
813
  url.searchParams.set("attemptId", attemptId);
@@ -621,23 +828,18 @@ var OmnizapiClientImpl = class {
621
828
  };
622
829
  host.addEventListener("message", messageListener);
623
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();
624
838
  try {
625
- const opened = openPopup(url.href, "_blank", 600, 740);
626
- if (!opened || opened === host) {
627
- throw new OmnizapiError("POPUP_BLOCKED", "The connection popup was blocked.");
628
- }
629
- popup = opened;
839
+ popup == null ? void 0 : popup.location.replace(url.href);
630
840
  } catch (e) {
631
- 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.");
632
842
  }
633
- popupTimer = setInterval(() => {
634
- if (!isLive()) return;
635
- try {
636
- if (popup == null ? void 0 : popup.closed) fail("popup_closed");
637
- } catch (e) {
638
- finish(new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be monitored."));
639
- }
640
- }, 500);
641
843
  };
642
844
  void run().catch((error) => {
643
845
  if (!isLive()) return;
@@ -646,8 +848,8 @@ var OmnizapiClientImpl = class {
646
848
  "The connection could not be completed."
647
849
  ));
648
850
  });
649
- } catch (e) {
650
- 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."));
651
853
  }
652
854
  });
653
855
  } catch (error) {