@omnizapi/connect 1.0.0

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.
@@ -0,0 +1,690 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Environment: () => Environment,
24
+ Omnizapi: () => Omnizapi,
25
+ OmnizapiError: () => OmnizapiError,
26
+ default: () => index_default
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/types/index.ts
31
+ var OmnizapiError = class extends Error {
32
+ constructor(code, message) {
33
+ super(message);
34
+ this.code = code;
35
+ this.name = "OmnizapiError";
36
+ }
37
+ };
38
+ var Environment = /* @__PURE__ */ ((Environment2) => {
39
+ Environment2["PRODUCTION"] = "PRODUCTION";
40
+ Environment2["STAGING"] = "STAGING";
41
+ Environment2["SANDBOX"] = "SANDBOX";
42
+ return Environment2;
43
+ })(Environment || {});
44
+
45
+ // src/config/constants.ts
46
+ var environments = {
47
+ ["PRODUCTION" /* PRODUCTION */]: {
48
+ api: "https://api.omni.z-api.io",
49
+ front: "https://app.omni.z-api.io"
50
+ },
51
+ ["STAGING" /* STAGING */]: {
52
+ api: "https://api.staging.omni.z-api.io",
53
+ front: "https://app.staging.omni.z-api.io"
54
+ },
55
+ ["SANDBOX" /* SANDBOX */]: {
56
+ api: "",
57
+ front: ""
58
+ }
59
+ };
60
+ var getConstants = ({
61
+ environment = "PRODUCTION" /* PRODUCTION */,
62
+ apiUrl,
63
+ frontUrl
64
+ } = {}) => {
65
+ if (!Object.prototype.hasOwnProperty.call(environments, environment)) {
66
+ throw new OmnizapiError("INVALID_CONFIGURATION", "Unknown environment.");
67
+ }
68
+ const defaults = environments[environment];
69
+ const urls = {
70
+ api: apiUrl != null ? apiUrl : defaults.api,
71
+ front: frontUrl != null ? frontUrl : defaults.front
72
+ };
73
+ for (const key of ["api", "front"]) {
74
+ let url;
75
+ try {
76
+ url = new URL(urls[key]);
77
+ } catch (e) {
78
+ throw new OmnizapiError(
79
+ "INVALID_CONFIGURATION",
80
+ `A valid ${key}Url is required for this environment.`
81
+ );
82
+ }
83
+ if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("?") || url.href.includes("#")) {
84
+ throw new OmnizapiError(
85
+ "INVALID_CONFIGURATION",
86
+ `${key}Url must be an HTTP(S) base URL without credentials, query or fragment.`
87
+ );
88
+ }
89
+ urls[key] = url.href.replace(/\/+$/, "");
90
+ }
91
+ return urls;
92
+ };
93
+
94
+ // src/core/runtime.ts
95
+ var runtimeKey = /* @__PURE__ */ Symbol.for("omnizapi.connect.runtime.v1");
96
+ function getRuntime(host) {
97
+ const target = host;
98
+ let runtime = target[runtimeKey];
99
+ if (!runtime) {
100
+ runtime = { nativeLoginPending: false, failedFacebookScripts: /* @__PURE__ */ new WeakSet() };
101
+ Object.defineProperty(target, runtimeKey, { configurable: true, value: runtime });
102
+ }
103
+ return runtime;
104
+ }
105
+
106
+ // src/core/facebook-sdk.ts
107
+ function isReadySdk(sdk) {
108
+ return !!sdk && !("__buffer" in sdk) && typeof sdk.init === "function" && typeof sdk.login === "function";
109
+ }
110
+ function loadFacebookSdk(host, signal) {
111
+ if (signal.aborted) {
112
+ return Promise.reject(new OmnizapiError("SDK_LOAD_FAILED", "The Meta SDK load was cancelled."));
113
+ }
114
+ if (isReadySdk(host.FB)) {
115
+ return Promise.resolve(host.FB);
116
+ }
117
+ 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) {
143
+ try {
144
+ script.remove();
145
+ } catch (e) {
146
+ }
147
+ }
148
+ }
149
+ if (runtime.facebookLoading === loading) delete runtime.facebookLoading;
150
+ if (sdk) resolve(sdk);
151
+ else reject(error);
152
+ };
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 = () => {
161
+ if (settled) return;
162
+ try {
163
+ previousCallback == null ? void 0 : previousCallback.call(host);
164
+ } catch (e) {
165
+ }
166
+ onLoad();
167
+ };
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;
212
+ }
213
+
214
+ // src/core/open-popup.ts
215
+ var openPopup = (url, title, width = 600, height = 700) => {
216
+ const host = window;
217
+ const document = host.document;
218
+ const screenLeft = host.screenLeft !== void 0 ? host.screenLeft : host.screenX;
219
+ const screenTop = host.screenTop !== void 0 ? host.screenTop : host.screenY;
220
+ const innerWidth = host.innerWidth ? host.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : host.screen.width;
221
+ const innerHeight = host.innerHeight ? host.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : host.screen.height;
222
+ const left = innerWidth / 2 - width / 2 + screenLeft;
223
+ const top = innerHeight / 2 - height / 2 + screenTop;
224
+ return host.open(
225
+ url,
226
+ title,
227
+ `scrollbars=yes, width=${width}, height=${height}, top=${top}, left=${left}`
228
+ );
229
+ };
230
+
231
+ // src/core/client.ts
232
+ var TOTAL_TIMEOUT_MS = 10 * 60 * 1e3;
233
+ var HTTP_TIMEOUT_MS = 30 * 1e3;
234
+ function isRecord(value) {
235
+ return typeof value === "object" && value !== null && !Array.isArray(value);
236
+ }
237
+ function stringOrNull(value) {
238
+ return typeof value === "string" && value.trim() ? value : null;
239
+ }
240
+ function encodeChannelId(channelId) {
241
+ if (channelId === "." || channelId === "..") {
242
+ throw new OmnizapiError("INVALID_OPTIONS", "The channelId cannot be a URL path navigation segment.");
243
+ }
244
+ try {
245
+ return encodeURIComponent(channelId);
246
+ } catch (e) {
247
+ throw new OmnizapiError("INVALID_OPTIONS", "The channelId cannot be encoded as a URL path.");
248
+ }
249
+ }
250
+ function isChannelType(value) {
251
+ return [
252
+ "META_MESSENGER",
253
+ "META_INSTAGRAM",
254
+ "META_WHATSAPP",
255
+ "BOT_TELEGRAM",
256
+ "Z_API_WHATSAPP"
257
+ ].includes(value);
258
+ }
259
+ function isFailureReason(value) {
260
+ return typeof value === "string" && [
261
+ "cancelled",
262
+ "popup_closed",
263
+ "not_completed",
264
+ "invalid_channel",
265
+ "origin_not_allowed",
266
+ "unsupported_channel"
267
+ ].includes(value);
268
+ }
269
+ function failure(channelId, type, reason) {
270
+ return { success: false, reason, channelId, type, code: null, wabaId: null, phoneId: null };
271
+ }
272
+ function requestJson(url, init, signal) {
273
+ if (typeof fetch !== "function" || typeof AbortController !== "function") {
274
+ return Promise.reject(new OmnizapiError(
275
+ "INVALID_CONFIGURATION",
276
+ "Fetch and AbortController are required."
277
+ ));
278
+ }
279
+ return new Promise((resolve, reject) => {
280
+ const controller = new AbortController();
281
+ let settled = false;
282
+ const complete = (value, error) => {
283
+ if (settled) return;
284
+ settled = true;
285
+ clearTimeout(timer);
286
+ signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
287
+ controller.abort();
288
+ if (error) reject(error);
289
+ else resolve(value);
290
+ };
291
+ const onAbort = () => complete(void 0, new OmnizapiError(
292
+ "NETWORK_ERROR",
293
+ "The API request was cancelled."
294
+ ));
295
+ const timer = setTimeout(() => complete(void 0, new OmnizapiError(
296
+ "TIMEOUT",
297
+ "The API request timed out."
298
+ )), HTTP_TIMEOUT_MS);
299
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
300
+ if (signal == null ? void 0 : signal.aborted) {
301
+ onAbort();
302
+ return;
303
+ }
304
+ const run = async () => {
305
+ let response;
306
+ try {
307
+ response = await fetch(url.href, { ...init, signal: controller.signal });
308
+ } catch (e) {
309
+ complete(void 0, new OmnizapiError("NETWORK_ERROR", "The API request failed."));
310
+ return;
311
+ }
312
+ if (settled) return;
313
+ if (!response || typeof response.ok !== "boolean") {
314
+ complete(void 0, new OmnizapiError("INVALID_RESPONSE", "The API response is invalid."));
315
+ return;
316
+ }
317
+ if (!response.ok) {
318
+ complete(void 0, new OmnizapiError("HTTP_ERROR", "The API returned an unsuccessful status."));
319
+ return;
320
+ }
321
+ try {
322
+ const data = await response.json();
323
+ if (!settled) complete(data);
324
+ } catch (e) {
325
+ complete(void 0, new OmnizapiError("INVALID_RESPONSE", "The API did not return valid JSON."));
326
+ }
327
+ };
328
+ void run().catch(() => complete(void 0, new OmnizapiError(
329
+ "NETWORK_ERROR",
330
+ "The API request failed."
331
+ )));
332
+ });
333
+ }
334
+ var OmnizapiClientImpl = class {
335
+ constructor(props) {
336
+ if (!isRecord(props) || !stringOrNull(props.publicKey) || Array.from(props.publicKey).some((character) => {
337
+ const code = character.charCodeAt(0);
338
+ return code < 32 || code === 127;
339
+ }) || props.logo !== void 0 && typeof props.logo !== "string" || props.apiUrl !== void 0 && !stringOrNull(props.apiUrl) || props.frontUrl !== void 0 && !stringOrNull(props.frontUrl)) {
340
+ throw new OmnizapiError("INVALID_CONFIGURATION", "Valid client properties and a publicKey are required.");
341
+ }
342
+ this.publicKey = props.publicKey;
343
+ this.logo = props.logo;
344
+ this.constants = getConstants({
345
+ environment: props.environment,
346
+ apiUrl: props.apiUrl,
347
+ frontUrl: props.frontUrl
348
+ });
349
+ }
350
+ async getListMessengerPages(channelId, code) {
351
+ if (!stringOrNull(channelId) || !stringOrNull(code)) {
352
+ throw new OmnizapiError("INVALID_OPTIONS", "A channelId and authorization code are required.");
353
+ }
354
+ return requestJson(
355
+ new URL(`${this.constants.api}/v1/channels/${encodeChannelId(channelId)}/list-messenger-pages`),
356
+ {
357
+ method: "POST",
358
+ body: JSON.stringify({
359
+ redirectUri: new URL(`${this.constants.front}/oauth/proxy-messenger`).href,
360
+ code
361
+ }),
362
+ headers: { "Content-Type": "application/json", Authorization: this.publicKey }
363
+ }
364
+ );
365
+ }
366
+ async connect(options) {
367
+ var _a;
368
+ try {
369
+ if (typeof window === "undefined" || !window.document || !window.location) {
370
+ throw new OmnizapiError("BROWSER_REQUIRED", "Connecting requires a browser window.");
371
+ }
372
+ const host = window;
373
+ const runtime = getRuntime(host);
374
+ if (runtime.activeConnection) {
375
+ throw new OmnizapiError("CONNECTION_IN_PROGRESS", "A connection is already in progress in this window.");
376
+ }
377
+ if (!isRecord(options)) {
378
+ throw new OmnizapiError("INVALID_OPTIONS", "Connection options are required.");
379
+ }
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.");
383
+ }
384
+ if (!channelId.trim()) return failure(channelId, null, "invalid_channel");
385
+ const encodedChannelId = encodeChannelId(channelId);
386
+ 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") {
387
+ throw new OmnizapiError("INVALID_CONFIGURATION", "Required browser APIs are unavailable.");
388
+ }
389
+ const currentOrigin = host.location.origin;
390
+ if (currentOrigin === "null") return failure(channelId, null, "origin_not_allowed");
391
+ const currentUrl = host.location.href;
392
+ const frontOrigin = new URL(this.constants.front).origin;
393
+ return await new Promise((resolve, reject) => {
394
+ const owner = /* @__PURE__ */ Symbol("omnizapi-connection");
395
+ const controller = new AbortController();
396
+ const deadline = Date.now() + timeoutMs;
397
+ let settled = false;
398
+ let channelType = null;
399
+ let redirectUri = null;
400
+ let popup = null;
401
+ let timeout;
402
+ let popupTimer;
403
+ let messageListener;
404
+ let nativeLoginStarted = false;
405
+ const globals = [];
406
+ const finish = (outcome) => {
407
+ if (settled) return;
408
+ settled = true;
409
+ clearTimeout(timeout);
410
+ clearInterval(popupTimer);
411
+ if (messageListener) {
412
+ try {
413
+ host.removeEventListener("message", messageListener);
414
+ } catch (e) {
415
+ }
416
+ }
417
+ try {
418
+ controller.abort();
419
+ } catch (e) {
420
+ }
421
+ const ownedPopup = popup;
422
+ popup = null;
423
+ try {
424
+ ownedPopup == null ? void 0 : ownedPopup.close();
425
+ } catch (e) {
426
+ }
427
+ for (const { name, previous, value } of globals) {
428
+ try {
429
+ const descriptor = Object.getOwnPropertyDescriptor(host, name);
430
+ if (!descriptor || !("value" in descriptor) || descriptor.value !== value) continue;
431
+ if (previous) Object.defineProperty(host, name, previous);
432
+ else Reflect.deleteProperty(host, name);
433
+ } catch (e) {
434
+ }
435
+ }
436
+ if (runtime.activeConnection === owner) delete runtime.activeConnection;
437
+ if (nativeLoginStarted && !(outcome instanceof OmnizapiError) && outcome.success) {
438
+ runtime.nativeLoginPending = false;
439
+ }
440
+ if (outcome instanceof OmnizapiError) reject(outcome);
441
+ else resolve(outcome);
442
+ };
443
+ const isLive = () => {
444
+ if (!settled && Date.now() >= deadline) {
445
+ finish(new OmnizapiError("TIMEOUT", "The connection timed out."));
446
+ }
447
+ return !settled;
448
+ };
449
+ const fail = (reason) => finish(failure(channelId, channelType, reason));
450
+ const succeed = (data) => {
451
+ if (!isLive() || !channelType) return;
452
+ finish({
453
+ success: true,
454
+ channelId,
455
+ type: channelType,
456
+ code: stringOrNull(data.code),
457
+ wabaId: stringOrNull(data.wabaId),
458
+ phoneId: stringOrNull(data.phoneId),
459
+ coexistence: data.coexistence === true,
460
+ redirectUri,
461
+ botToken: stringOrNull(data.botToken),
462
+ pageId: stringOrNull(data.pageId),
463
+ accessToken: stringOrNull(data.accessToken)
464
+ });
465
+ };
466
+ try {
467
+ runtime.activeConnection = owner;
468
+ const bytes = host.crypto.getRandomValues(new Uint8Array(16));
469
+ const attemptId = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
470
+ for (const [name, value] of [
471
+ ["__omnizapiPublicKey", this.publicKey],
472
+ ["__omnizapiCurrentChannel", channelId],
473
+ ["__omnizapiGetQrCode", getQRCode]
474
+ ]) {
475
+ const previous = Object.getOwnPropertyDescriptor(host, name);
476
+ Object.defineProperty(host, name, previous && !previous.configurable ? { value } : { configurable: true, enumerable: true, writable: true, value });
477
+ globals.push({ name, previous, value });
478
+ }
479
+ timeout = setTimeout(() => finish(new OmnizapiError(
480
+ "TIMEOUT",
481
+ "The connection timed out."
482
+ )), timeoutMs);
483
+ const run = async () => {
484
+ var _a2, _b, _c;
485
+ const info = await requestJson(
486
+ new URL(`${this.constants.api}/instances/${encodedChannelId}/sdk-info`),
487
+ { headers: { Authorization: this.publicKey, "Content-Type": "application/json" } },
488
+ controller.signal
489
+ );
490
+ if (!isLive()) return;
491
+ if (!isRecord(info) || !stringOrNull(info.middleware)) {
492
+ throw new OmnizapiError("INVALID_RESPONSE", "The channel configuration is invalid.");
493
+ }
494
+ const allowOrigins = (_a2 = info.allowOrigins) != null ? _a2 : [];
495
+ if (!Array.isArray(allowOrigins) || !allowOrigins.every((origin) => typeof origin === "string")) {
496
+ throw new OmnizapiError("INVALID_RESPONSE", "The channel origins are invalid.");
497
+ }
498
+ const middleware = info.middleware;
499
+ channelType = isChannelType(middleware) ? middleware : null;
500
+ if (currentOrigin !== frontOrigin && !allowOrigins.some((origin) => currentOrigin === origin.replace(/\/$/, ""))) {
501
+ fail("origin_not_allowed");
502
+ return;
503
+ }
504
+ if (!channelType) {
505
+ fail("unsupported_channel");
506
+ return;
507
+ }
508
+ const appId = (_b = stringOrNull(channelType === "META_INSTAGRAM" ? info.appInstagramId : info.appId)) != null ? _b : "";
509
+ const configId = (_c = stringOrNull(info.appConfig)) != null ? _c : "";
510
+ if (channelType.startsWith("META_") && !appId || channelType === "META_WHATSAPP" && !configId) {
511
+ throw new OmnizapiError("INVALID_RESPONSE", "The channel provider configuration is invalid.");
512
+ }
513
+ if (channelType === "META_WHATSAPP" && (direct || Boolean(info.appCustom) || currentOrigin === frontOrigin)) {
514
+ if (runtime.nativeLoginPending) {
515
+ throw new OmnizapiError(
516
+ "CONNECTION_IN_PROGRESS",
517
+ "A previous Meta login is incomplete. Reload this window before retrying a native login."
518
+ );
519
+ }
520
+ const fb = await loadFacebookSdk(host, controller.signal);
521
+ if (!isLive()) return;
522
+ try {
523
+ fb.init({ appId, version: "v25.0", autoLogAppEvents: true, xfbml: true });
524
+ } catch (e) {
525
+ throw new OmnizapiError("PROVIDER_ERROR", "The Meta SDK could not be initialized.");
526
+ }
527
+ if (!isLive()) return;
528
+ let code = null;
529
+ let wabaId = null;
530
+ let phoneId = null;
531
+ let coexistence = false;
532
+ let callbackReceived = false;
533
+ const completeNative = () => {
534
+ if (!isLive() || !code || !wabaId) return;
535
+ succeed({ code, wabaId, phoneId, coexistence });
536
+ };
537
+ messageListener = (event) => {
538
+ if (!isLive() || ![
539
+ "https://www.facebook.com",
540
+ "https://web.facebook.com"
541
+ ].includes(event.origin)) return;
542
+ let data = event.data;
543
+ if (typeof data === "string") {
544
+ try {
545
+ data = JSON.parse(data);
546
+ } catch (e) {
547
+ return;
548
+ }
549
+ }
550
+ if (!isRecord(data) || data.type !== "WA_EMBEDDED_SIGNUP") return;
551
+ if (data.event === "CANCEL") {
552
+ fail("cancelled");
553
+ } else if (data.event === "ERROR") {
554
+ finish(new OmnizapiError("PROVIDER_ERROR", "Meta could not complete the connection."));
555
+ } else if (data.event === "FINISH" || data.event === "FINISH_WHATSAPP_BUSINESS_APP_ONBOARDING") {
556
+ if (!isRecord(data.data) || !stringOrNull(data.data.waba_id) || data.data.phone_number_id != null && typeof data.data.phone_number_id !== "string") return;
557
+ wabaId = stringOrNull(data.data.waba_id);
558
+ phoneId = stringOrNull(data.data.phone_number_id);
559
+ coexistence = data.event === "FINISH_WHATSAPP_BUSINESS_APP_ONBOARDING";
560
+ completeNative();
561
+ }
562
+ };
563
+ host.addEventListener("message", messageListener);
564
+ runtime.nativeLoginPending = true;
565
+ nativeLoginStarted = true;
566
+ try {
567
+ fb.login((response) => {
568
+ if (!isLive() || callbackReceived) return;
569
+ callbackReceived = true;
570
+ if (!isRecord(response) || response.error) {
571
+ finish(new OmnizapiError("PROVIDER_ERROR", "Meta returned an invalid login response."));
572
+ return;
573
+ }
574
+ if (response.authResponse == null) {
575
+ fail("not_completed");
576
+ return;
577
+ }
578
+ if (!isRecord(response.authResponse) || !stringOrNull(response.authResponse.code)) {
579
+ fail("not_completed");
580
+ return;
581
+ }
582
+ code = stringOrNull(response.authResponse.code);
583
+ completeNative();
584
+ }, {
585
+ config_id: configId,
586
+ response_type: "code",
587
+ override_default_response_type: true,
588
+ extras: {
589
+ setup: {},
590
+ featureType: "whatsapp_business_app_onboarding",
591
+ sessionInfoVersion: "3"
592
+ }
593
+ });
594
+ } catch (e) {
595
+ throw new OmnizapiError("PROVIDER_ERROR", "The Meta login could not be started.");
596
+ }
597
+ return;
598
+ }
599
+ let url;
600
+ if (channelType === "META_MESSENGER" || channelType === "META_INSTAGRAM") {
601
+ const messenger = channelType === "META_MESSENGER";
602
+ redirectUri = new URL(`${this.constants.front}/oauth/proxy-${messenger ? "messenger" : "instagram"}`).href;
603
+ url = new URL(messenger ? "https://www.facebook.com/dialog/oauth" : "https://www.instagram.com/oauth/authorize");
604
+ url.searchParams.set("client_id", appId);
605
+ if (messenger) url.searchParams.set("display", "popup");
606
+ url.searchParams.set("redirect_uri", redirectUri);
607
+ url.searchParams.set("response_type", "code");
608
+ url.searchParams.set("scope", messenger ? "public_profile,business_management,pages_messaging,pages_show_list,pages_manage_metadata,pages_read_engagement" : "instagram_business_basic,instagram_business_manage_messages");
609
+ url.searchParams.set("state", JSON.stringify({ currentUrl, attemptId, channelId }));
610
+ } else if (channelType === "META_WHATSAPP") {
611
+ url = new URL(`${this.constants.front}/oauth/proxy-cloud-api`);
612
+ url.searchParams.set("configId", configId);
613
+ url.searchParams.set("appId", appId);
614
+ url.searchParams.set("channelId", channelId);
615
+ url.searchParams.set("channelType", channelType);
616
+ url.searchParams.set("logo", this.logo || new URL(`${this.constants.front}/logos/SVG/Ativo%2016.svg`).href);
617
+ url.searchParams.set("pk", this.publicKey);
618
+ } else {
619
+ url = new URL(`${this.constants.front}/connect/${channelType === "BOT_TELEGRAM" ? "telegram" : "whatsapp-web"}`);
620
+ url.searchParams.set("channelId", channelId);
621
+ }
622
+ if (channelType !== "META_MESSENGER" && channelType !== "META_INSTAGRAM") {
623
+ url.searchParams.set("attemptId", attemptId);
624
+ }
625
+ messageListener = (event) => {
626
+ if (!isLive() || !popup || event.origin !== frontOrigin || event.source !== popup) return;
627
+ const data = event.data;
628
+ if (!isRecord(data) || data.type !== "after-connect" || data.attemptId !== attemptId || data.channelId !== channelId || typeof data.success !== "boolean" || data.reason !== void 0 && !isFailureReason(data.reason) || data.coexistence !== void 0 && typeof data.coexistence !== "boolean" || ["code", "wabaId", "phoneId", "botToken", "pageId", "accessToken", "redirectUri"].some(
629
+ (key) => data[key] != null && typeof data[key] !== "string"
630
+ )) return;
631
+ if (!data.success) {
632
+ fail(isFailureReason(data.reason) ? data.reason : "not_completed");
633
+ } else if ((channelType == null ? void 0 : channelType.startsWith("META_")) && !stringOrNull(data.code) || channelType === "BOT_TELEGRAM" && !stringOrNull(data.botToken)) {
634
+ fail("not_completed");
635
+ } else {
636
+ succeed(data);
637
+ }
638
+ };
639
+ host.addEventListener("message", messageListener);
640
+ if (!isLive()) return;
641
+ try {
642
+ const opened = openPopup(url.href, "_blank", 600, 740);
643
+ if (!opened || opened === host) {
644
+ throw new OmnizapiError("POPUP_BLOCKED", "The connection popup was blocked.");
645
+ }
646
+ popup = opened;
647
+ } catch (e) {
648
+ throw new OmnizapiError("POPUP_BLOCKED", "The connection popup could not be opened.");
649
+ }
650
+ popupTimer = setInterval(() => {
651
+ if (!isLive()) return;
652
+ try {
653
+ if (popup == null ? void 0 : popup.closed) fail("popup_closed");
654
+ } catch (e) {
655
+ finish(new OmnizapiError("PROVIDER_ERROR", "The connection popup could not be monitored."));
656
+ }
657
+ }, 500);
658
+ };
659
+ void run().catch((error) => {
660
+ if (!isLive()) return;
661
+ finish(error instanceof OmnizapiError ? error : new OmnizapiError(
662
+ "PROVIDER_ERROR",
663
+ "The connection could not be completed."
664
+ ));
665
+ });
666
+ } catch (e) {
667
+ finish(new OmnizapiError("INVALID_CONFIGURATION", "The connection could not be initialized."));
668
+ }
669
+ });
670
+ } catch (error) {
671
+ if (error instanceof OmnizapiError) throw error;
672
+ throw new OmnizapiError("INVALID_OPTIONS", "The connection could not be started with these options.");
673
+ }
674
+ }
675
+ };
676
+ var client_default = OmnizapiClientImpl;
677
+
678
+ // src/index.ts
679
+ var Omnizapi = class {
680
+ static newClient(props) {
681
+ return new client_default(props);
682
+ }
683
+ };
684
+ var index_default = Omnizapi;
685
+ // Annotate the CommonJS export names for ESM import in node:
686
+ 0 && (module.exports = {
687
+ Environment,
688
+ Omnizapi,
689
+ OmnizapiError
690
+ });