@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.
package/dist/cjs/index.js CHANGED
@@ -94,12 +94,22 @@ var getConstants = ({
94
94
  // src/core/runtime.ts
95
95
  var runtimeKey = /* @__PURE__ */ Symbol.for("omnizapi.connect.runtime.v1");
96
96
  function getRuntime(host) {
97
+ var _a, _b, _c;
97
98
  const target = host;
98
99
  let runtime = target[runtimeKey];
99
100
  if (!runtime) {
100
- runtime = { nativeLoginPending: false, failedFacebookScripts: /* @__PURE__ */ new WeakSet() };
101
+ runtime = {
102
+ nativeLoginPending: false,
103
+ failedFacebookScripts: /* @__PURE__ */ new WeakSet(),
104
+ erroredFacebookScripts: /* @__PURE__ */ new WeakSet(),
105
+ facebookAppIds: /* @__PURE__ */ new WeakMap(),
106
+ facebookInitObservers: /* @__PURE__ */ new WeakMap()
107
+ };
101
108
  Object.defineProperty(target, runtimeKey, { configurable: true, value: runtime });
102
109
  }
110
+ (_a = runtime.facebookAppIds) != null ? _a : runtime.facebookAppIds = /* @__PURE__ */ new WeakMap();
111
+ (_b = runtime.facebookInitObservers) != null ? _b : runtime.facebookInitObservers = /* @__PURE__ */ new WeakMap();
112
+ (_c = runtime.erroredFacebookScripts) != null ? _c : runtime.erroredFacebookScripts = /* @__PURE__ */ new WeakSet();
103
113
  return runtime;
104
114
  }
105
115
 
@@ -107,108 +117,238 @@ function getRuntime(host) {
107
117
  function isReadySdk(sdk) {
108
118
  return !!sdk && !("__buffer" in sdk) && typeof sdk.init === "function" && typeof sdk.login === "function";
109
119
  }
120
+ function observeFacebookInit(runtime, fb) {
121
+ var _a;
122
+ try {
123
+ const descriptor = Object.getOwnPropertyDescriptor(fb, "init");
124
+ const existing = runtime.facebookInitObservers.get(fb);
125
+ if (existing) {
126
+ if ((descriptor == null ? void 0 : descriptor.value) !== existing.init) throw new Error("FB.init was replaced.");
127
+ return existing;
128
+ }
129
+ if (!descriptor || typeof descriptor.value !== "function" || !descriptor.writable && !descriptor.configurable) {
130
+ throw new Error("FB.init cannot be observed.");
131
+ }
132
+ const original = descriptor.value;
133
+ const observer = {
134
+ calls: 0,
135
+ init: function(...args) {
136
+ observer.calls++;
137
+ runtime.facebookAppIds.delete(fb);
138
+ return Reflect.apply(original, this, args);
139
+ }
140
+ };
141
+ Object.defineProperty(fb, "init", { ...descriptor, value: observer.init });
142
+ if (((_a = Object.getOwnPropertyDescriptor(fb, "init")) == null ? void 0 : _a.value) !== observer.init) throw new Error("FB.init was not replaced.");
143
+ runtime.facebookInitObservers.set(fb, observer);
144
+ return observer;
145
+ } catch (e) {
146
+ runtime.facebookAppIds.delete(fb);
147
+ throw new OmnizapiError(
148
+ "INVALID_CONFIGURATION",
149
+ "The Meta SDK initialization cannot be observed safely. Use the popup flow or reload a fresh page."
150
+ );
151
+ }
152
+ }
153
+ function initializeFacebookSdk(host, fb, appId) {
154
+ var _a;
155
+ if (host.FB !== fb || !fb || "__buffer" in fb || typeof fb.login !== "function") {
156
+ throw new OmnizapiError("INVALID_CONFIGURATION", "The Meta SDK is not ready or was replaced before initialization.");
157
+ }
158
+ if (typeof appId !== "string" || !/^[0-9]+$/.test(appId)) {
159
+ throw new OmnizapiError("INVALID_CONFIGURATION", "A numeric Meta appId is required for native login.");
160
+ }
161
+ const runtime = getRuntime(host);
162
+ if (runtime.facebookAppIds.get(fb) === null && (runtime.facebookLoadUncertain || runtime.facebookLoading || typeof host.fbAsyncInit === "function")) {
163
+ runtime.facebookAppIds.delete(fb);
164
+ }
165
+ const initializedAppId = runtime.facebookAppIds.get(fb);
166
+ if (initializedAppId === void 0 || initializedAppId !== null && !runtime.facebookInitObservers.has(fb)) {
167
+ runtime.facebookAppIds.delete(fb);
168
+ throw new OmnizapiError(
169
+ "INVALID_CONFIGURATION",
170
+ "The host Meta SDK configuration is unknown. Use the popup flow or a fresh page without a host-initialized SDK for native login."
171
+ );
172
+ }
173
+ const observer = observeFacebookInit(runtime, fb);
174
+ if (initializedAppId !== null) {
175
+ if (initializedAppId !== appId) {
176
+ throw new OmnizapiError(
177
+ "INVALID_CONFIGURATION",
178
+ "The Meta SDK is already initialized for another app. Use the popup flow or reload a fresh page before changing apps."
179
+ );
180
+ }
181
+ return;
182
+ }
183
+ const calls = observer.calls;
184
+ runtime.facebookAppIds.delete(fb);
185
+ try {
186
+ fb.init({ appId, version: "v25.0", autoLogAppEvents: true, xfbml: true });
187
+ } catch (e) {
188
+ throw new OmnizapiError("PROVIDER_ERROR", "The Meta SDK could not be initialized.");
189
+ }
190
+ if (observer.calls !== calls + 1 || host.FB !== fb || ((_a = Object.getOwnPropertyDescriptor(fb, "init")) == null ? void 0 : _a.value) !== observer.init) {
191
+ throw new OmnizapiError("INVALID_CONFIGURATION", "The Meta SDK changed during initialization. Use the popup flow or reload a fresh page.");
192
+ }
193
+ runtime.facebookAppIds.set(fb, appId);
194
+ }
110
195
  function loadFacebookSdk(host, signal) {
111
196
  if (signal.aborted) {
112
197
  return Promise.reject(new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
113
198
  }
114
- if (isReadySdk(host.FB)) {
115
- return Promise.resolve(host.FB);
116
- }
117
199
  const runtime = getRuntime(host);
118
- const existing = runtime.facebookLoading;
119
- if (existing) return existing;
120
- const loading = Promise.resolve().then(() => new Promise((resolve, reject) => {
121
- let settled = false;
122
- let script;
123
- let ownedScript = false;
124
- let previous;
125
- let previousCallback;
126
- const finish = (sdk, error) => {
127
- if (settled) return;
128
- settled = true;
129
- clearTimeout(timer);
130
- signal.removeEventListener("abort", onAbort);
131
- script == null ? void 0 : script.removeEventListener("load", onLoad);
132
- script == null ? void 0 : script.removeEventListener("error", onError);
133
- try {
134
- if (host.fbAsyncInit === onReady) {
135
- if (previous) Object.defineProperty(host, "fbAsyncInit", previous);
136
- else Reflect.deleteProperty(host, "fbAsyncInit");
137
- }
138
- } catch (e) {
139
- }
140
- if (error && script) {
141
- if (!signal.aborted) runtime.failedFacebookScripts.add(script);
142
- if (ownedScript) {
200
+ let loading = runtime.facebookLoadObserver;
201
+ if (!loading && isReadySdk(host.FB)) {
202
+ loading = { promise: Promise.resolve(host.FB), consumers: 0 };
203
+ }
204
+ if (!loading) {
205
+ const shared2 = {
206
+ consumers: 0,
207
+ // Register the observer and its consumers before setup can fail synchronously.
208
+ promise: Promise.resolve().then(() => new Promise((resolve, reject) => {
209
+ var _a;
210
+ let settled = false;
211
+ let script;
212
+ let ownedScript = false;
213
+ let freshSdk = false;
214
+ let bootstrap;
215
+ let previous;
216
+ let previousCallback;
217
+ const finish = (sdk, error, definitiveFailure = false) => {
218
+ if (settled) return;
219
+ settled = true;
220
+ clearTimeout(timer);
221
+ script == null ? void 0 : script.removeEventListener("load", onLoad);
222
+ script == null ? void 0 : script.removeEventListener("error", onError);
143
223
  try {
144
- script.remove();
224
+ if (host.fbAsyncInit === onReady) {
225
+ if (previous) Object.defineProperty(host, "fbAsyncInit", previous);
226
+ else Reflect.deleteProperty(host, "fbAsyncInit");
227
+ }
145
228
  } catch (e) {
146
229
  }
230
+ if (error && script) {
231
+ runtime.failedFacebookScripts.add(script);
232
+ if (definitiveFailure) runtime.erroredFacebookScripts.add(script);
233
+ else if (!ownedScript) runtime.facebookLoadUncertain = true;
234
+ if (ownedScript) {
235
+ try {
236
+ script.remove();
237
+ } catch (e) {
238
+ }
239
+ }
240
+ }
241
+ if (runtime.facebookLoadObserver === shared2) delete runtime.facebookLoadObserver;
242
+ if (sdk) resolve(sdk);
243
+ else reject(error);
244
+ };
245
+ const onLoad = () => {
246
+ var _a2;
247
+ if (settled) return;
248
+ const sdk = host.FB;
249
+ if (!sdk) return;
250
+ if ("__buffer" in sdk) bootstrap = sdk;
251
+ 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) {
252
+ freshSdk = false;
253
+ if (runtime.facebookAppIds.get(sdk) === null) runtime.facebookAppIds.delete(sdk);
254
+ if (bootstrap && runtime.facebookAppIds.get(bootstrap) === null) runtime.facebookAppIds.delete(bootstrap);
255
+ }
256
+ const ready = isReadySdk(sdk);
257
+ if (freshSdk && runtime.facebookAppIds.get(sdk) == null) {
258
+ if (!ready) runtime.facebookAppIds.set(sdk, null);
259
+ else if (!runtime.facebookInitObservers.has(sdk)) {
260
+ try {
261
+ observeFacebookInit(runtime, sdk);
262
+ runtime.facebookAppIds.set(sdk, null);
263
+ } catch (e) {
264
+ }
265
+ }
266
+ }
267
+ if (ready) finish(sdk);
268
+ };
269
+ const onError = () => finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK could not be loaded."), true);
270
+ const onReady = () => {
271
+ if (settled) return;
272
+ try {
273
+ previousCallback == null ? void 0 : previousCallback.call(host);
274
+ } catch (e) {
275
+ }
276
+ onLoad();
277
+ };
278
+ const timer = setTimeout(() => finish(void 0, new OmnizapiError(
279
+ "SDK_LOAD_FAILED",
280
+ "The Meta SDK load timed out."
281
+ )), 30 * 1e3);
282
+ shared2.cancelIfUnused = () => {
283
+ if (ownedScript && shared2.consumers === 0) {
284
+ finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
285
+ }
286
+ };
287
+ try {
288
+ previous = Object.getOwnPropertyDescriptor(host, "fbAsyncInit");
289
+ previousCallback = typeof host.fbAsyncInit === "function" ? host.fbAsyncInit : void 0;
290
+ const document = host.document;
291
+ const byId = document.getElementById("facebook-jssdk");
292
+ script = Array.from(document.scripts).find((candidate) => {
293
+ try {
294
+ const url = new URL(candidate.src);
295
+ if (url.origin !== "https://connect.facebook.net" || !/^\/[^/]+\/sdk\.js$/.test(url.pathname)) return false;
296
+ if (!runtime.failedFacebookScripts.has(candidate)) return true;
297
+ if (!runtime.erroredFacebookScripts.has(candidate)) runtime.facebookLoadUncertain = true;
298
+ return false;
299
+ } catch (e) {
300
+ return false;
301
+ }
302
+ });
303
+ if (!script) {
304
+ script = document.createElement("script");
305
+ ownedScript = true;
306
+ const initialSdk = host.FB;
307
+ if (initialSdk && "__buffer" in initialSdk) bootstrap = initialSdk;
308
+ freshSdk = !runtime.facebookLoadUncertain && !runtime.facebookLoading && !previousCallback && (!initialSdk || !!bootstrap && runtime.facebookAppIds.get(initialSdk) === null && ((_a = bootstrap.__buffer) == null ? void 0 : _a.opts) == null);
309
+ if (!byId) script.id = "facebook-jssdk";
310
+ script.src = "https://connect.facebook.net/en_US/sdk.js";
311
+ script.crossOrigin = "anonymous";
312
+ script.async = true;
313
+ script.defer = true;
314
+ }
315
+ shared2.cancelIfUnused();
316
+ if (settled) return;
317
+ Object.defineProperty(host, "fbAsyncInit", previous && !previous.configurable ? { value: onReady } : { configurable: true, enumerable: true, writable: true, value: onReady });
318
+ script.addEventListener("load", onLoad);
319
+ script.addEventListener("error", onError);
320
+ onLoad();
321
+ if (!settled && ownedScript) document.head.appendChild(script);
322
+ } catch (e) {
323
+ finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK could not be loaded."));
147
324
  }
148
- }
149
- if (runtime.facebookLoading === loading) delete runtime.facebookLoading;
150
- if (sdk) resolve(sdk);
151
- else reject(error);
325
+ }))
152
326
  };
153
- const onLoad = () => {
154
- if (settled) return;
155
- const sdk = host.FB;
156
- if (isReadySdk(sdk)) finish(sdk);
157
- };
158
- const onError = () => finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK could not be loaded."));
159
- const onAbort = () => finish(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
160
- const onReady = () => {
327
+ runtime.facebookLoadObserver = loading = shared2;
328
+ }
329
+ const shared = loading;
330
+ return new Promise((resolve, reject) => {
331
+ let settled = false;
332
+ shared.consumers++;
333
+ const complete = (sdk, error) => {
334
+ var _a;
161
335
  if (settled) return;
162
- try {
163
- previousCallback == null ? void 0 : previousCallback.call(host);
164
- } catch (e) {
165
- }
166
- onLoad();
336
+ settled = true;
337
+ signal.removeEventListener("abort", onAbort);
338
+ shared.consumers--;
339
+ if (sdk) resolve(sdk);
340
+ else reject(error);
341
+ (_a = shared.cancelIfUnused) == null ? void 0 : _a.call(shared);
167
342
  };
168
- const timer = setTimeout(() => finish(void 0, new OmnizapiError(
169
- "SDK_LOAD_FAILED",
170
- "The Meta SDK load timed out."
171
- )), 30 * 1e3);
172
- try {
173
- signal.addEventListener("abort", onAbort, { once: true });
174
- if (signal.aborted) {
175
- onAbort();
176
- return;
177
- }
178
- previous = Object.getOwnPropertyDescriptor(host, "fbAsyncInit");
179
- previousCallback = typeof host.fbAsyncInit === "function" ? host.fbAsyncInit : void 0;
180
- Object.defineProperty(host, "fbAsyncInit", previous && !previous.configurable ? { value: onReady } : { configurable: true, enumerable: true, writable: true, value: onReady });
181
- const document = host.document;
182
- const byId = document.getElementById("facebook-jssdk");
183
- const existingScript = (byId == null ? void 0 : byId.tagName.toLowerCase()) === "script" ? byId : void 0;
184
- script = (existingScript && !runtime.failedFacebookScripts.has(existingScript) ? existingScript : void 0) || Array.from(document.scripts).find((candidate) => {
185
- if (runtime.failedFacebookScripts.has(candidate)) return false;
186
- try {
187
- const url = new URL(candidate.src);
188
- return url.origin === "https://connect.facebook.net" && /^\/[^/]+\/sdk\.js$/.test(url.pathname);
189
- } catch (e) {
190
- return false;
191
- }
192
- });
193
- if (!script) {
194
- script = document.createElement("script");
195
- ownedScript = true;
196
- if (!byId) script.id = "facebook-jssdk";
197
- script.src = "https://connect.facebook.net/en_US/sdk.js";
198
- script.crossOrigin = "anonymous";
199
- script.async = true;
200
- script.defer = true;
201
- }
202
- script.addEventListener("load", onLoad);
203
- script.addEventListener("error", onError);
204
- onLoad();
205
- if (!settled && ownedScript) document.head.appendChild(script);
206
- } catch (e) {
207
- onError();
208
- }
209
- }));
210
- runtime.facebookLoading = loading;
211
- return loading;
343
+ const onAbort = () => complete(void 0, new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
344
+ void shared.promise.then(
345
+ (sdk) => signal.aborted ? onAbort() : complete(sdk),
346
+ // A shared observer may belong to another module copy's OmnizapiError class.
347
+ (error) => complete(void 0, new OmnizapiError("SDK_LOAD_FAILED", error.message))
348
+ );
349
+ signal.addEventListener("abort", onAbort, { once: true });
350
+ if (signal.aborted) onAbort();
351
+ });
212
352
  }
213
353
 
214
354
  // src/core/open-popup.ts
@@ -289,8 +429,8 @@ function requestJson(url, init, signal) {
289
429
  else resolve(value);
290
430
  };
291
431
  const onAbort = () => complete(void 0, new OmnizapiError(
292
- "NETWORK_ERROR",
293
- "The API request was cancelled."
432
+ "ABORTED",
433
+ "The API request was aborted."
294
434
  ));
295
435
  const timer = setTimeout(() => complete(void 0, new OmnizapiError(
296
436
  "TIMEOUT",
@@ -347,10 +487,14 @@ var OmnizapiClientImpl = class {
347
487
  frontUrl: props.frontUrl
348
488
  });
349
489
  }
350
- async getListMessengerPages(channelId, code) {
490
+ async getListMessengerPages(channelId, code, signal) {
351
491
  if (!stringOrNull(channelId) || !stringOrNull(code)) {
352
492
  throw new OmnizapiError("INVALID_OPTIONS", "A channelId and authorization code are required.");
353
493
  }
494
+ if (signal !== void 0 && (!isRecord(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) {
495
+ throw new OmnizapiError("INVALID_OPTIONS", "The abort signal is invalid.");
496
+ }
497
+ if (signal == null ? void 0 : signal.aborted) throw new OmnizapiError("ABORTED", "The API request was aborted.");
354
498
  return requestJson(
355
499
  new URL(`${this.constants.api}/v1/channels/${encodeChannelId(channelId)}/list-messenger-pages`),
356
500
  {
@@ -360,7 +504,8 @@ var OmnizapiClientImpl = class {
360
504
  code
361
505
  }),
362
506
  headers: { "Content-Type": "application/json", Authorization: this.publicKey }
363
- }
507
+ },
508
+ signal
364
509
  );
365
510
  }
366
511
  async connect(options) {
@@ -377,10 +522,11 @@ var OmnizapiClientImpl = class {
377
522
  if (!isRecord(options)) {
378
523
  throw new OmnizapiError("INVALID_OPTIONS", "Connection options are required.");
379
524
  }
380
- const { channelId, direct, getQRCode, timeoutMs = TOTAL_TIMEOUT_MS } = options;
381
- 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) {
382
- throw new OmnizapiError("INVALID_OPTIONS", "Invalid channelId, direct, getQRCode or timeoutMs option.");
525
+ const { channelId, direct, getQRCode, timeoutMs = TOTAL_TIMEOUT_MS, signal } = options;
526
+ 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")) {
527
+ throw new OmnizapiError("INVALID_OPTIONS", "Invalid channelId, direct, getQRCode, timeoutMs or signal option.");
383
528
  }
529
+ if (signal == null ? void 0 : signal.aborted) throw new OmnizapiError("ABORTED", "The connection was aborted.");
384
530
  if (!channelId.trim()) return failure(channelId, null, "invalid_channel");
385
531
  const encodedChannelId = encodeChannelId(channelId);
386
532
  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") {
@@ -398,6 +544,7 @@ var OmnizapiClientImpl = class {
398
544
  let channelType = null;
399
545
  let redirectUri = null;
400
546
  let popup = null;
547
+ let popupError;
401
548
  let timeout;
402
549
  let popupTimer;
403
550
  let messageListener;
@@ -415,6 +562,10 @@ var OmnizapiClientImpl = class {
415
562
  settled = true;
416
563
  clearTimeout(timeout);
417
564
  clearInterval(popupTimer);
565
+ try {
566
+ signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
567
+ } catch (e) {
568
+ }
418
569
  if (messageListener) {
419
570
  try {
420
571
  host.removeEventListener("message", messageListener);
@@ -447,13 +598,43 @@ var OmnizapiClientImpl = class {
447
598
  if (outcome instanceof OmnizapiError) reject(outcome);
448
599
  else resolve(outcome);
449
600
  };
601
+ const onAbort = () => finish(new OmnizapiError("ABORTED", "The connection was aborted."));
450
602
  const isLive = () => {
603
+ if (!settled && (signal == null ? void 0 : signal.aborted)) onAbort();
451
604
  if (!settled && Date.now() >= deadline) {
452
605
  finish(new OmnizapiError("TIMEOUT", "The connection timed out."));
453
606
  }
454
607
  return !settled;
455
608
  };
456
609
  const fail = (reason) => finish(failure(channelId, channelType, reason));
610
+ const reservePopup = () => {
611
+ try {
612
+ const opened = openPopup("about:blank", "_blank", 600, 740);
613
+ if (!opened || opened === host) throw new Error("Popup unavailable");
614
+ if (!isLive()) {
615
+ opened.close();
616
+ return;
617
+ }
618
+ popup = opened;
619
+ } catch (e) {
620
+ throw new OmnizapiError("POPUP_BLOCKED", "The connection popup could not be opened.");
621
+ }
622
+ };
623
+ const watchPopup = () => {
624
+ if (popupTimer) return;
625
+ popupTimer = setInterval(() => {
626
+ if (!isLive()) return;
627
+ try {
628
+ if (popup == null ? void 0 : popup.closed) fail("popup_closed");
629
+ } catch (e) {
630
+ finish(new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be monitored."));
631
+ }
632
+ }, 500);
633
+ };
634
+ const unwatchPopup = () => {
635
+ clearInterval(popupTimer);
636
+ popupTimer = void 0;
637
+ };
457
638
  const succeed = (data) => {
458
639
  if (!isLive() || !channelType) return;
459
640
  finish({
@@ -472,6 +653,8 @@ var OmnizapiClientImpl = class {
472
653
  };
473
654
  try {
474
655
  runtime.activeConnection = owner;
656
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
657
+ if (!isLive()) return;
475
658
  const bytes = host.crypto.getRandomValues(new Uint8Array(16));
476
659
  const attemptId = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
477
660
  for (const [name, value] of [
@@ -487,6 +670,12 @@ var OmnizapiClientImpl = class {
487
670
  "TIMEOUT",
488
671
  "The connection timed out."
489
672
  )), timeoutMs);
673
+ try {
674
+ reservePopup();
675
+ } catch (error) {
676
+ popupError = error instanceof OmnizapiError ? error : new OmnizapiError("POPUP_BLOCKED", "The connection popup could not be opened.");
677
+ }
678
+ if (!isLive()) return;
490
679
  const run = async () => {
491
680
  var _a2, _b, _c;
492
681
  const info = await requestJson(
@@ -504,7 +693,13 @@ var OmnizapiClientImpl = class {
504
693
  }
505
694
  const middleware = info.middleware;
506
695
  channelType = isChannelType(middleware) ? middleware : null;
507
- if (currentOrigin !== frontOrigin && !allowOrigins.some((origin) => currentOrigin === origin.replace(/\/$/, ""))) {
696
+ if (currentOrigin !== frontOrigin && !allowOrigins.some((origin) => {
697
+ try {
698
+ return currentOrigin === new URL(origin).origin;
699
+ } catch (e) {
700
+ return false;
701
+ }
702
+ })) {
508
703
  fail("origin_not_allowed");
509
704
  return;
510
705
  }
@@ -517,21 +712,30 @@ var OmnizapiClientImpl = class {
517
712
  if (channelType.startsWith("META_") && !appId || channelType === "META_WHATSAPP" && !configId) {
518
713
  throw new OmnizapiError("INVALID_RESPONSE", "The channel provider configuration is invalid.");
519
714
  }
520
- if (channelType === "META_WHATSAPP" && (direct || Boolean(info.appCustom) || currentOrigin === frontOrigin)) {
715
+ const nativeWhatsApp = channelType === "META_WHATSAPP" && (direct || Boolean(info.appCustom) || currentOrigin === frontOrigin);
716
+ let nativeReady = false;
717
+ let fb;
718
+ if (nativeWhatsApp) {
719
+ unwatchPopup();
521
720
  if (runtime.nativeLoginPending) {
522
721
  throw new OmnizapiError(
523
722
  "CONNECTION_IN_PROGRESS",
524
723
  "A previous Meta login is incomplete. Reload this window before retrying a native login."
525
724
  );
526
725
  }
527
- const fb = await loadFacebookSdk(host, controller.signal);
726
+ fb = await loadFacebookSdk(host, controller.signal);
528
727
  if (!isLive()) return;
529
728
  try {
530
- fb.init({ appId, version: "v25.0", autoLogAppEvents: true, xfbml: true });
531
- } catch (e) {
532
- throw new OmnizapiError("PROVIDER_ERROR", "The Meta SDK could not be initialized.");
729
+ initializeFacebookSdk(host, fb, appId);
730
+ nativeReady = true;
731
+ } catch (error) {
732
+ if (!(error instanceof OmnizapiError && error.code === "INVALID_CONFIGURATION")) throw error;
533
733
  }
534
734
  if (!isLive()) return;
735
+ }
736
+ if (nativeReady && fb) {
737
+ popup == null ? void 0 : popup.close();
738
+ popup = null;
535
739
  let code = null;
536
740
  let wabaId = null;
537
741
  let phoneId = null;
@@ -604,6 +808,8 @@ var OmnizapiClientImpl = class {
604
808
  }
605
809
  });
606
810
  } catch (e) {
811
+ releaseNativeLogin();
812
+ nativeLoginStarted = false;
607
813
  throw new OmnizapiError("PROVIDER_ERROR", "The Meta login could not be started.");
608
814
  }
609
815
  return;
@@ -630,6 +836,7 @@ var OmnizapiClientImpl = class {
630
836
  } else {
631
837
  url = new URL(`${this.constants.front}/connect/${channelType === "BOT_TELEGRAM" ? "telegram" : "whatsapp-web"}`);
632
838
  url.searchParams.set("channelId", channelId);
839
+ url.searchParams.set("pk", this.publicKey);
633
840
  }
634
841
  if (channelType !== "META_MESSENGER" && channelType !== "META_INSTAGRAM") {
635
842
  url.searchParams.set("attemptId", attemptId);
@@ -650,23 +857,18 @@ var OmnizapiClientImpl = class {
650
857
  };
651
858
  host.addEventListener("message", messageListener);
652
859
  if (!isLive()) return;
860
+ if (popupError) throw popupError;
861
+ if (!popup) reservePopup();
862
+ if (popup == null ? void 0 : popup.closed) {
863
+ fail("popup_closed");
864
+ return;
865
+ }
866
+ watchPopup();
653
867
  try {
654
- const opened = openPopup(url.href, "_blank", 600, 740);
655
- if (!opened || opened === host) {
656
- throw new OmnizapiError("POPUP_BLOCKED", "The connection popup was blocked.");
657
- }
658
- popup = opened;
868
+ popup == null ? void 0 : popup.location.replace(url.href);
659
869
  } catch (e) {
660
- throw new OmnizapiError("POPUP_BLOCKED", "The connection popup could not be opened.");
870
+ throw new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be navigated.");
661
871
  }
662
- popupTimer = setInterval(() => {
663
- if (!isLive()) return;
664
- try {
665
- if (popup == null ? void 0 : popup.closed) fail("popup_closed");
666
- } catch (e) {
667
- finish(new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be monitored."));
668
- }
669
- }, 500);
670
872
  };
671
873
  void run().catch((error) => {
672
874
  if (!isLive()) return;
@@ -675,8 +877,8 @@ var OmnizapiClientImpl = class {
675
877
  "The connection could not be completed."
676
878
  ));
677
879
  });
678
- } catch (e) {
679
- finish(new OmnizapiError("INVALID_CONFIGURATION", "The connection could not be initialized."));
880
+ } catch (error) {
881
+ finish(error instanceof OmnizapiError ? error : new OmnizapiError("INVALID_CONFIGURATION", "The connection could not be initialized."));
680
882
  }
681
883
  });
682
884
  } catch (error) {