bypilot-business-signup-sdk 0.1.0-beta.1
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/chunk-ARDHIAFU.cjs +811 -0
- package/dist/chunk-ARDHIAFU.cjs.map +1 -0
- package/dist/chunk-B3CUULGV.js +805 -0
- package/dist/chunk-B3CUULGV.js.map +1 -0
- package/dist/index-DzVvaEqu.d.cts +493 -0
- package/dist/index-DzVvaEqu.d.ts +493 -0
- package/dist/index.cjs +30 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/whatsapp.cjs +12 -0
- package/dist/whatsapp.cjs.map +1 -0
- package/dist/whatsapp.d.cts +1 -0
- package/dist/whatsapp.d.ts +1 -0
- package/dist/whatsapp.js +3 -0
- package/dist/whatsapp.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/TokenManager.ts
|
|
4
|
+
var TokenManager = class {
|
|
5
|
+
constructor(providerName, strategy = "memory") {
|
|
6
|
+
this.memoryStorage = /* @__PURE__ */ new Map();
|
|
7
|
+
this.strategy = strategy;
|
|
8
|
+
this.storageKey = `bypilot_${providerName}_token`;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Token'ı storage'a kaydet
|
|
12
|
+
*/
|
|
13
|
+
save(token) {
|
|
14
|
+
const serialized = JSON.stringify(token);
|
|
15
|
+
switch (this.strategy) {
|
|
16
|
+
case "localStorage":
|
|
17
|
+
if (typeof localStorage !== "undefined") {
|
|
18
|
+
localStorage.setItem(this.storageKey, serialized);
|
|
19
|
+
}
|
|
20
|
+
break;
|
|
21
|
+
case "sessionStorage":
|
|
22
|
+
if (typeof sessionStorage !== "undefined") {
|
|
23
|
+
sessionStorage.setItem(this.storageKey, serialized);
|
|
24
|
+
}
|
|
25
|
+
break;
|
|
26
|
+
case "memory":
|
|
27
|
+
default:
|
|
28
|
+
this.memoryStorage.set(this.storageKey, serialized);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Token'ı storage'dan getir
|
|
34
|
+
*/
|
|
35
|
+
get() {
|
|
36
|
+
let serialized = null;
|
|
37
|
+
switch (this.strategy) {
|
|
38
|
+
case "localStorage":
|
|
39
|
+
if (typeof localStorage !== "undefined") {
|
|
40
|
+
serialized = localStorage.getItem(this.storageKey);
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
case "sessionStorage":
|
|
44
|
+
if (typeof sessionStorage !== "undefined") {
|
|
45
|
+
serialized = sessionStorage.getItem(this.storageKey);
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
case "memory":
|
|
49
|
+
default:
|
|
50
|
+
serialized = this.memoryStorage.get(this.storageKey) ?? null;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
if (!serialized) return null;
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(serialized);
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Token'ı sil
|
|
62
|
+
*/
|
|
63
|
+
clear() {
|
|
64
|
+
switch (this.strategy) {
|
|
65
|
+
case "localStorage":
|
|
66
|
+
if (typeof localStorage !== "undefined") {
|
|
67
|
+
localStorage.removeItem(this.storageKey);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
case "sessionStorage":
|
|
71
|
+
if (typeof sessionStorage !== "undefined") {
|
|
72
|
+
sessionStorage.removeItem(this.storageKey);
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case "memory":
|
|
76
|
+
default:
|
|
77
|
+
this.memoryStorage.delete(this.storageKey);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Token'ın geçerli olup olmadığını kontrol et
|
|
83
|
+
*/
|
|
84
|
+
isValid() {
|
|
85
|
+
const token = this.get();
|
|
86
|
+
if (!token) return false;
|
|
87
|
+
if (token.expiresAt) {
|
|
88
|
+
return Date.now() < token.expiresAt;
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Token'ın süresinin dolmasına kalan süre (ms)
|
|
94
|
+
*/
|
|
95
|
+
getTimeUntilExpiry() {
|
|
96
|
+
const token = this.get();
|
|
97
|
+
if (!token?.expiresAt) return null;
|
|
98
|
+
return Math.max(0, token.expiresAt - Date.now());
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/core/EventEmitter.ts
|
|
103
|
+
var EventEmitter = class {
|
|
104
|
+
constructor() {
|
|
105
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Event listener ekle
|
|
109
|
+
*/
|
|
110
|
+
on(event, listener) {
|
|
111
|
+
if (!this.listeners.has(event)) {
|
|
112
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
113
|
+
}
|
|
114
|
+
this.listeners.get(event).add(listener);
|
|
115
|
+
return () => this.off(event, listener);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Event listener kaldır
|
|
119
|
+
*/
|
|
120
|
+
off(event, listener) {
|
|
121
|
+
const eventListeners = this.listeners.get(event);
|
|
122
|
+
if (eventListeners) {
|
|
123
|
+
eventListeners.delete(listener);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Event tetikle
|
|
128
|
+
*/
|
|
129
|
+
emit(event, data) {
|
|
130
|
+
const eventListeners = this.listeners.get(event);
|
|
131
|
+
if (eventListeners) {
|
|
132
|
+
eventListeners.forEach((listener) => {
|
|
133
|
+
try {
|
|
134
|
+
listener(data);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error(`[ByPilot SDK] Event listener error for ${event}:`, error);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Tek seferlik event listener
|
|
143
|
+
*/
|
|
144
|
+
once(event, listener) {
|
|
145
|
+
const onceListener = (data) => {
|
|
146
|
+
this.off(event, onceListener);
|
|
147
|
+
listener(data);
|
|
148
|
+
};
|
|
149
|
+
return this.on(event, onceListener);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Tüm listener'ları temizle
|
|
153
|
+
*/
|
|
154
|
+
removeAllListeners(event) {
|
|
155
|
+
if (event) {
|
|
156
|
+
this.listeners.delete(event);
|
|
157
|
+
} else {
|
|
158
|
+
this.listeners.clear();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// src/core/PopupManager.ts
|
|
164
|
+
var PopupManager = class {
|
|
165
|
+
constructor() {
|
|
166
|
+
this.popup = null;
|
|
167
|
+
this.checkInterval = null;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Popup aç ve URL'e yönlendir
|
|
171
|
+
*/
|
|
172
|
+
open(url, config = {}) {
|
|
173
|
+
const {
|
|
174
|
+
width = 600,
|
|
175
|
+
height = 700,
|
|
176
|
+
left = window.screenX + (window.outerWidth - width) / 2,
|
|
177
|
+
top = window.screenY + (window.outerHeight - height) / 2
|
|
178
|
+
} = config;
|
|
179
|
+
const features = [
|
|
180
|
+
`width=${width}`,
|
|
181
|
+
`height=${height}`,
|
|
182
|
+
`left=${left}`,
|
|
183
|
+
`top=${top}`,
|
|
184
|
+
"toolbar=no",
|
|
185
|
+
"menubar=no",
|
|
186
|
+
"scrollbars=yes",
|
|
187
|
+
"resizable=yes"
|
|
188
|
+
].join(",");
|
|
189
|
+
this.popup = window.open(url, "bypilot_oauth", features);
|
|
190
|
+
return this.popup;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Popup'ın kapanmasını bekle
|
|
194
|
+
*/
|
|
195
|
+
waitForClose() {
|
|
196
|
+
return new Promise((resolve) => {
|
|
197
|
+
if (!this.popup) {
|
|
198
|
+
resolve();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
this.checkInterval = window.setInterval(() => {
|
|
202
|
+
if (!this.popup || this.popup.closed) {
|
|
203
|
+
this.cleanup();
|
|
204
|
+
resolve();
|
|
205
|
+
}
|
|
206
|
+
}, 100);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Popup'tan callback al (postMessage ile)
|
|
211
|
+
*/
|
|
212
|
+
waitForCallback(origin, timeout = 3e5) {
|
|
213
|
+
return new Promise((resolve, reject) => {
|
|
214
|
+
const timeoutId = window.setTimeout(() => {
|
|
215
|
+
cleanup();
|
|
216
|
+
reject(new Error("OAuth callback timeout"));
|
|
217
|
+
}, timeout);
|
|
218
|
+
const messageHandler = (event) => {
|
|
219
|
+
if (event.origin !== origin) return;
|
|
220
|
+
if (event.data?.type === "bypilot_oauth_callback") {
|
|
221
|
+
cleanup();
|
|
222
|
+
resolve(event.data.payload);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const cleanup = () => {
|
|
226
|
+
window.clearTimeout(timeoutId);
|
|
227
|
+
window.removeEventListener("message", messageHandler);
|
|
228
|
+
this.cleanup();
|
|
229
|
+
};
|
|
230
|
+
window.addEventListener("message", messageHandler);
|
|
231
|
+
this.checkInterval = window.setInterval(() => {
|
|
232
|
+
if (!this.popup || this.popup.closed) {
|
|
233
|
+
cleanup();
|
|
234
|
+
reject(new Error("OAuth popup closed by user"));
|
|
235
|
+
}
|
|
236
|
+
}, 100);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Popup'ı kapat ve temizle
|
|
241
|
+
*/
|
|
242
|
+
close() {
|
|
243
|
+
if (this.popup && !this.popup.closed) {
|
|
244
|
+
this.popup.close();
|
|
245
|
+
}
|
|
246
|
+
this.cleanup();
|
|
247
|
+
}
|
|
248
|
+
cleanup() {
|
|
249
|
+
if (this.checkInterval) {
|
|
250
|
+
window.clearInterval(this.checkInterval);
|
|
251
|
+
this.checkInterval = null;
|
|
252
|
+
}
|
|
253
|
+
this.popup = null;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Popup aktif mi?
|
|
257
|
+
*/
|
|
258
|
+
isOpen() {
|
|
259
|
+
return this.popup !== null && !this.popup.closed;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// src/providers/BaseProvider.ts
|
|
264
|
+
var BaseProvider = class extends EventEmitter {
|
|
265
|
+
constructor(config) {
|
|
266
|
+
super();
|
|
267
|
+
this.config = config;
|
|
268
|
+
this.tokenManager = new TokenManager(
|
|
269
|
+
this.constructor.name.toLowerCase(),
|
|
270
|
+
config.storage ?? "memory"
|
|
271
|
+
);
|
|
272
|
+
this.popupManager = new PopupManager();
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Random state oluştur
|
|
276
|
+
*/
|
|
277
|
+
generateState() {
|
|
278
|
+
const array = new Uint8Array(32);
|
|
279
|
+
crypto.getRandomValues(array);
|
|
280
|
+
return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Popup ile login başlat
|
|
284
|
+
*/
|
|
285
|
+
async loginWithPopup(popupConfig) {
|
|
286
|
+
this.emit("auth:start");
|
|
287
|
+
const state = this.config.state ?? this.generateState();
|
|
288
|
+
const authUrl = this.buildAuthorizationUrl(state);
|
|
289
|
+
sessionStorage.setItem(`bypilot_state_${this.name}`, state);
|
|
290
|
+
try {
|
|
291
|
+
this.popupManager.open(authUrl, popupConfig);
|
|
292
|
+
const callbackData = await this.popupManager.waitForCallback(
|
|
293
|
+
window.location.origin
|
|
294
|
+
);
|
|
295
|
+
const savedState = sessionStorage.getItem(`bypilot_state_${this.name}`);
|
|
296
|
+
if (callbackData.state !== savedState) {
|
|
297
|
+
throw new Error("State mismatch - possible CSRF attack");
|
|
298
|
+
}
|
|
299
|
+
const result = await this.handleCallback(callbackData);
|
|
300
|
+
if (result.success && result.token) {
|
|
301
|
+
this.tokenManager.save(result.token);
|
|
302
|
+
this.emit("auth:success", result);
|
|
303
|
+
} else {
|
|
304
|
+
this.emit("auth:error", result);
|
|
305
|
+
}
|
|
306
|
+
return result;
|
|
307
|
+
} catch (error) {
|
|
308
|
+
const errorResult = {
|
|
309
|
+
success: false,
|
|
310
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
311
|
+
};
|
|
312
|
+
if (error instanceof Error && error.message.includes("closed by user")) {
|
|
313
|
+
this.emit("auth:cancel");
|
|
314
|
+
} else {
|
|
315
|
+
this.emit("auth:error", errorResult);
|
|
316
|
+
}
|
|
317
|
+
return errorResult;
|
|
318
|
+
} finally {
|
|
319
|
+
sessionStorage.removeItem(`bypilot_state_${this.name}`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Redirect ile login başlat
|
|
324
|
+
*/
|
|
325
|
+
loginWithRedirect() {
|
|
326
|
+
this.emit("auth:start");
|
|
327
|
+
const state = this.config.state ?? this.generateState();
|
|
328
|
+
const authUrl = this.buildAuthorizationUrl(state);
|
|
329
|
+
sessionStorage.setItem(`bypilot_state_${this.name}`, state);
|
|
330
|
+
window.location.href = authUrl;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Redirect callback'ini işle (sayfa yüklendiğinde çağrılmalı)
|
|
334
|
+
*/
|
|
335
|
+
async handleRedirectCallback() {
|
|
336
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
337
|
+
const code = urlParams.get("code");
|
|
338
|
+
const state = urlParams.get("state");
|
|
339
|
+
const error = urlParams.get("error");
|
|
340
|
+
if (!code && !error) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
const savedState = sessionStorage.getItem(`bypilot_state_${this.name}`);
|
|
344
|
+
if (state !== savedState) {
|
|
345
|
+
const result = {
|
|
346
|
+
success: false,
|
|
347
|
+
error: "state_mismatch",
|
|
348
|
+
errorDescription: "State mismatch - possible CSRF attack"
|
|
349
|
+
};
|
|
350
|
+
this.emit("auth:error", result);
|
|
351
|
+
return result;
|
|
352
|
+
}
|
|
353
|
+
sessionStorage.removeItem(`bypilot_state_${this.name}`);
|
|
354
|
+
if (error) {
|
|
355
|
+
const result = {
|
|
356
|
+
success: false,
|
|
357
|
+
error,
|
|
358
|
+
errorDescription: urlParams.get("error_description") ?? void 0
|
|
359
|
+
};
|
|
360
|
+
this.emit("auth:error", result);
|
|
361
|
+
return result;
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
const callbackData = {};
|
|
365
|
+
urlParams.forEach((value, key) => {
|
|
366
|
+
callbackData[key] = value;
|
|
367
|
+
});
|
|
368
|
+
const result = await this.handleCallback(callbackData);
|
|
369
|
+
if (result.success && result.token) {
|
|
370
|
+
this.tokenManager.save(result.token);
|
|
371
|
+
this.emit("auth:success", result);
|
|
372
|
+
} else {
|
|
373
|
+
this.emit("auth:error", result);
|
|
374
|
+
}
|
|
375
|
+
window.history.replaceState({}, document.title, window.location.pathname);
|
|
376
|
+
return result;
|
|
377
|
+
} catch (error2) {
|
|
378
|
+
const errorResult = {
|
|
379
|
+
success: false,
|
|
380
|
+
error: error2 instanceof Error ? error2.message : "Unknown error"
|
|
381
|
+
};
|
|
382
|
+
this.emit("auth:error", errorResult);
|
|
383
|
+
return errorResult;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Mevcut token'ı getir
|
|
388
|
+
*/
|
|
389
|
+
getToken() {
|
|
390
|
+
return this.tokenManager.get();
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Access token'ı getir
|
|
394
|
+
*/
|
|
395
|
+
getAccessToken() {
|
|
396
|
+
return this.tokenManager.get()?.accessToken ?? null;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Token geçerli mi?
|
|
400
|
+
*/
|
|
401
|
+
isAuthenticated() {
|
|
402
|
+
return this.tokenManager.isValid();
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Logout - token'ı temizle
|
|
406
|
+
*/
|
|
407
|
+
logout() {
|
|
408
|
+
this.tokenManager.clear();
|
|
409
|
+
this.emit("token:expire");
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Storage stratejisini değiştir
|
|
413
|
+
*/
|
|
414
|
+
setStorageStrategy(strategy) {
|
|
415
|
+
const currentToken = this.tokenManager.get();
|
|
416
|
+
this.tokenManager = new TokenManager(this.name, strategy);
|
|
417
|
+
if (currentToken) {
|
|
418
|
+
this.tokenManager.save(currentToken);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// src/providers/whatsapp/WhatsAppProvider.ts
|
|
424
|
+
var WhatsAppProvider = class extends BaseProvider {
|
|
425
|
+
constructor(config) {
|
|
426
|
+
super(config);
|
|
427
|
+
this.name = "whatsapp";
|
|
428
|
+
this.authorizationEndpoint = "https://www.facebook.com/v24.0/dialog/oauth";
|
|
429
|
+
this.fbSDKLoaded = false;
|
|
430
|
+
this.fbSDKLoadPromise = null;
|
|
431
|
+
/**
|
|
432
|
+
* Son alınan session info
|
|
433
|
+
*/
|
|
434
|
+
this.lastSessionInfo = null;
|
|
435
|
+
this.whatsappConfig = config;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Facebook SDK'yı yükle
|
|
439
|
+
*/
|
|
440
|
+
async loadFacebookSDK() {
|
|
441
|
+
if (this.fbSDKLoaded && window.FB) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (this.fbSDKLoadPromise) {
|
|
445
|
+
return this.fbSDKLoadPromise;
|
|
446
|
+
}
|
|
447
|
+
this.fbSDKLoadPromise = new Promise((resolve, reject) => {
|
|
448
|
+
if (window.FB) {
|
|
449
|
+
this.fbSDKLoaded = true;
|
|
450
|
+
this.initFacebookSDK();
|
|
451
|
+
resolve();
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const script = document.createElement("script");
|
|
455
|
+
script.id = "facebook-jssdk";
|
|
456
|
+
script.src = `https://connect.facebook.net/en_US/sdk.js`;
|
|
457
|
+
script.async = true;
|
|
458
|
+
script.defer = true;
|
|
459
|
+
window.fbAsyncInit = () => {
|
|
460
|
+
this.initFacebookSDK();
|
|
461
|
+
this.fbSDKLoaded = true;
|
|
462
|
+
resolve();
|
|
463
|
+
};
|
|
464
|
+
script.onerror = () => {
|
|
465
|
+
reject(new Error("Failed to load Facebook SDK"));
|
|
466
|
+
};
|
|
467
|
+
const existingScript = document.getElementById("facebook-jssdk");
|
|
468
|
+
if (existingScript) {
|
|
469
|
+
existingScript.remove();
|
|
470
|
+
}
|
|
471
|
+
document.head.appendChild(script);
|
|
472
|
+
setTimeout(() => {
|
|
473
|
+
if (!this.fbSDKLoaded) {
|
|
474
|
+
reject(new Error("Facebook SDK load timeout"));
|
|
475
|
+
}
|
|
476
|
+
}, 1e4);
|
|
477
|
+
});
|
|
478
|
+
return this.fbSDKLoadPromise;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Facebook SDK'yı başlat
|
|
482
|
+
*/
|
|
483
|
+
initFacebookSDK() {
|
|
484
|
+
if (!window.FB) return;
|
|
485
|
+
window.FB.init({
|
|
486
|
+
appId: this.whatsappConfig.clientId,
|
|
487
|
+
cookie: true,
|
|
488
|
+
xfbml: true,
|
|
489
|
+
version: this.whatsappConfig.sdkVersion ?? "v24.0"
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Authorization URL oluştur (redirect flow için)
|
|
494
|
+
*/
|
|
495
|
+
buildAuthorizationUrl(state) {
|
|
496
|
+
const params = new URLSearchParams({
|
|
497
|
+
client_id: this.whatsappConfig.clientId,
|
|
498
|
+
redirect_uri: this.whatsappConfig.redirectUri,
|
|
499
|
+
state,
|
|
500
|
+
response_type: "code",
|
|
501
|
+
config_id: this.whatsappConfig.configId,
|
|
502
|
+
scope: this.whatsappConfig.scope ?? "whatsapp_business_management,whatsapp_business_messaging"
|
|
503
|
+
});
|
|
504
|
+
return `${this.authorizationEndpoint}?${params.toString()}`;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Callback'i işle
|
|
508
|
+
*/
|
|
509
|
+
async handleCallback(callbackData) {
|
|
510
|
+
const code = callbackData.code;
|
|
511
|
+
const error = callbackData.error;
|
|
512
|
+
if (error) {
|
|
513
|
+
return {
|
|
514
|
+
success: false,
|
|
515
|
+
error,
|
|
516
|
+
errorDescription: callbackData.error_description
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if (!code) {
|
|
520
|
+
return {
|
|
521
|
+
success: false,
|
|
522
|
+
error: "missing_code",
|
|
523
|
+
errorDescription: "Authorization code not found in callback"
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
return {
|
|
527
|
+
success: true,
|
|
528
|
+
raw: { code },
|
|
529
|
+
token: {
|
|
530
|
+
accessToken: code,
|
|
531
|
+
// Bu aslında code, backend'de token'a çevrilmeli
|
|
532
|
+
tokenType: "authorization_code"
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* WhatsApp Embedded Signup popup ile başlat
|
|
538
|
+
*
|
|
539
|
+
* Facebook SDK kullanarak native popup deneyimi sağlar.
|
|
540
|
+
* Session info message event'i ile WABA ID, Phone Number ID ve access token alır.
|
|
541
|
+
*/
|
|
542
|
+
async loginWithPopup(_popupConfig) {
|
|
543
|
+
this.emit("auth:start");
|
|
544
|
+
try {
|
|
545
|
+
await this.loadFacebookSDK();
|
|
546
|
+
if (!window.FB) {
|
|
547
|
+
throw new Error("Facebook SDK not available");
|
|
548
|
+
}
|
|
549
|
+
const sessionInfoPromise = this.waitForSessionInfo();
|
|
550
|
+
const response = await this.launchEmbeddedSignup();
|
|
551
|
+
if (response.status === "not_authorized") {
|
|
552
|
+
this.emit("auth:cancel");
|
|
553
|
+
return {
|
|
554
|
+
success: false,
|
|
555
|
+
error: "not_authorized",
|
|
556
|
+
errorDescription: "User did not authorize the app"
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
const authResponse = response.authResponse;
|
|
560
|
+
let sessionInfo = null;
|
|
561
|
+
try {
|
|
562
|
+
sessionInfo = await Promise.race([
|
|
563
|
+
sessionInfoPromise,
|
|
564
|
+
new Promise((resolve) => setTimeout(() => resolve(null), 5e3))
|
|
565
|
+
]);
|
|
566
|
+
} catch {
|
|
567
|
+
}
|
|
568
|
+
let token;
|
|
569
|
+
if (sessionInfo?.accessToken) {
|
|
570
|
+
token = {
|
|
571
|
+
accessToken: sessionInfo.accessToken,
|
|
572
|
+
tokenType: "bearer",
|
|
573
|
+
scope: this.whatsappConfig.scope
|
|
574
|
+
};
|
|
575
|
+
this.lastSessionInfo = sessionInfo;
|
|
576
|
+
} else if (authResponse?.code) {
|
|
577
|
+
token = {
|
|
578
|
+
accessToken: authResponse.code,
|
|
579
|
+
tokenType: "authorization_code"
|
|
580
|
+
};
|
|
581
|
+
} else if (authResponse?.accessToken) {
|
|
582
|
+
token = this.buildToken(authResponse);
|
|
583
|
+
} else {
|
|
584
|
+
return {
|
|
585
|
+
success: false,
|
|
586
|
+
error: "no_token",
|
|
587
|
+
errorDescription: "No access token or authorization code received"
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
this.tokenManager.save(token);
|
|
591
|
+
const result = {
|
|
592
|
+
success: true,
|
|
593
|
+
token,
|
|
594
|
+
raw: {
|
|
595
|
+
...authResponse,
|
|
596
|
+
sessionInfo
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
this.emit("auth:success", result);
|
|
600
|
+
return result;
|
|
601
|
+
} catch (error) {
|
|
602
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
603
|
+
if (errorMessage.includes("closed") || errorMessage.includes("cancel")) {
|
|
604
|
+
this.emit("auth:cancel");
|
|
605
|
+
} else {
|
|
606
|
+
this.emit("auth:error", { error: errorMessage });
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
success: false,
|
|
610
|
+
error: errorMessage
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Session info için message event bekle
|
|
616
|
+
*/
|
|
617
|
+
waitForSessionInfo() {
|
|
618
|
+
return new Promise((resolve) => {
|
|
619
|
+
const handler = (event) => {
|
|
620
|
+
if (event.origin !== "https://www.facebook.com" && event.origin !== "https://web.facebook.com") {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
try {
|
|
624
|
+
const data = JSON.parse(event.data);
|
|
625
|
+
if (data.type === "WA_EMBEDDED_SIGNUP") {
|
|
626
|
+
window.removeEventListener("message", handler);
|
|
627
|
+
const sessionInfo = {
|
|
628
|
+
accessToken: data.data?.access_token ?? "",
|
|
629
|
+
phoneNumberId: data.data?.phone_number_id,
|
|
630
|
+
wabaId: data.data?.waba_id,
|
|
631
|
+
phoneNumber: data.data?.phone_number,
|
|
632
|
+
businessId: data.data?.business_id
|
|
633
|
+
};
|
|
634
|
+
resolve(sessionInfo);
|
|
635
|
+
}
|
|
636
|
+
} catch {
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
window.addEventListener("message", handler);
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Son session info'yu al
|
|
644
|
+
*/
|
|
645
|
+
getLastSessionInfo() {
|
|
646
|
+
return this.lastSessionInfo;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Embedded Signup akışını başlat
|
|
650
|
+
*/
|
|
651
|
+
launchEmbeddedSignup() {
|
|
652
|
+
return new Promise((resolve) => {
|
|
653
|
+
const extras = {
|
|
654
|
+
...this.whatsappConfig.extras ?? {},
|
|
655
|
+
featureType: this.whatsappConfig.extras?.featureType ?? "whatsapp_embedded_signup",
|
|
656
|
+
sessionInfoVersion: this.whatsappConfig.extras?.sessionInfoVersion ?? 3
|
|
657
|
+
};
|
|
658
|
+
if (this.whatsappConfig.solutionId) {
|
|
659
|
+
extras.solutionID = this.whatsappConfig.solutionId;
|
|
660
|
+
}
|
|
661
|
+
window.FB.login(
|
|
662
|
+
(response) => resolve(response),
|
|
663
|
+
{
|
|
664
|
+
config_id: this.whatsappConfig.configId,
|
|
665
|
+
response_type: "code",
|
|
666
|
+
override_default_response_type: true,
|
|
667
|
+
extras
|
|
668
|
+
}
|
|
669
|
+
);
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Auth response'dan token oluştur
|
|
674
|
+
*/
|
|
675
|
+
buildToken(authResponse) {
|
|
676
|
+
return {
|
|
677
|
+
accessToken: authResponse.accessToken ?? "",
|
|
678
|
+
tokenType: "bearer",
|
|
679
|
+
expiresAt: authResponse.expiresIn ? Date.now() + authResponse.expiresIn * 1e3 : void 0,
|
|
680
|
+
scope: this.whatsappConfig.scope
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Session info al (Embedded Signup sonrası)
|
|
685
|
+
*
|
|
686
|
+
* Facebook SDK message event'i ile session bilgilerini alır
|
|
687
|
+
*/
|
|
688
|
+
getSessionInfoListener(callback) {
|
|
689
|
+
const handler = (event) => {
|
|
690
|
+
if (event.origin !== "https://www.facebook.com" && event.origin !== "https://web.facebook.com") {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
try {
|
|
694
|
+
const data = JSON.parse(event.data);
|
|
695
|
+
if (data.type === "WA_EMBEDDED_SIGNUP") {
|
|
696
|
+
const sessionInfo = {
|
|
697
|
+
accessToken: data.data?.access_token ?? "",
|
|
698
|
+
phoneNumberId: data.data?.phone_number_id,
|
|
699
|
+
wabaId: data.data?.waba_id,
|
|
700
|
+
phoneNumber: data.data?.phone_number
|
|
701
|
+
};
|
|
702
|
+
callback(sessionInfo);
|
|
703
|
+
}
|
|
704
|
+
} catch {
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
window.addEventListener("message", handler);
|
|
708
|
+
return () => window.removeEventListener("message", handler);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Login durumunu kontrol et
|
|
712
|
+
*/
|
|
713
|
+
async checkLoginStatus() {
|
|
714
|
+
try {
|
|
715
|
+
await this.loadFacebookSDK();
|
|
716
|
+
if (!window.FB) return null;
|
|
717
|
+
return new Promise((resolve) => {
|
|
718
|
+
window.FB.getLoginStatus((response) => {
|
|
719
|
+
resolve(response);
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
} catch {
|
|
723
|
+
return null;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Facebook'tan logout
|
|
728
|
+
*/
|
|
729
|
+
logout() {
|
|
730
|
+
super.logout();
|
|
731
|
+
if (window.FB) {
|
|
732
|
+
try {
|
|
733
|
+
window.FB.logout();
|
|
734
|
+
} catch {
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Graph API çağrısı yap (Facebook SDK kullanarak)
|
|
740
|
+
*
|
|
741
|
+
* @param path - API endpoint (örn: 'me' veya 'v24.0/me')
|
|
742
|
+
* @param method - HTTP method
|
|
743
|
+
* @param params - Query/body parametreleri
|
|
744
|
+
*/
|
|
745
|
+
async graphAPI(path, method = "GET", params) {
|
|
746
|
+
await this.loadFacebookSDK();
|
|
747
|
+
if (!window.FB) {
|
|
748
|
+
throw new Error("Facebook SDK not available");
|
|
749
|
+
}
|
|
750
|
+
const version = this.whatsappConfig.graphApiVersion ?? "v24.0";
|
|
751
|
+
const versionedPath = path.startsWith("v") || path.startsWith("/v") ? path : `${version}/${path}`;
|
|
752
|
+
return new Promise((resolve, reject) => {
|
|
753
|
+
const accessToken = this.getAccessToken();
|
|
754
|
+
window.FB.api(
|
|
755
|
+
versionedPath,
|
|
756
|
+
method,
|
|
757
|
+
{ ...params, access_token: accessToken },
|
|
758
|
+
(response) => {
|
|
759
|
+
const resp = response;
|
|
760
|
+
if (resp.error) {
|
|
761
|
+
reject(new Error(resp.error.message ?? "Graph API error"));
|
|
762
|
+
} else {
|
|
763
|
+
resolve(response);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
);
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* WhatsApp Cloud API'ye doğrudan HTTP çağrısı yap
|
|
771
|
+
*
|
|
772
|
+
* @param endpoint - API endpoint (örn: '123456/messages')
|
|
773
|
+
* @param method - HTTP method
|
|
774
|
+
* @param body - Request body
|
|
775
|
+
*/
|
|
776
|
+
async whatsappAPI(endpoint, method = "GET", body) {
|
|
777
|
+
const accessToken = this.getAccessToken();
|
|
778
|
+
const version = this.whatsappConfig.graphApiVersion ?? "v24.0";
|
|
779
|
+
const url = `https://graph.facebook.com/${version}/${endpoint}`;
|
|
780
|
+
const options = {
|
|
781
|
+
method,
|
|
782
|
+
headers: {
|
|
783
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
784
|
+
"Content-Type": "application/json"
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
if (body && (method === "POST" || method === "DELETE")) {
|
|
788
|
+
options.body = JSON.stringify(body);
|
|
789
|
+
}
|
|
790
|
+
const response = await fetch(url, options);
|
|
791
|
+
if (!response.ok) {
|
|
792
|
+
const error = await response.json().catch(() => ({ message: "Unknown error" }));
|
|
793
|
+
throw new Error(error.message || `HTTP ${response.status}`);
|
|
794
|
+
}
|
|
795
|
+
return response.json();
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Graph API version'unu al
|
|
799
|
+
*/
|
|
800
|
+
getGraphApiVersion() {
|
|
801
|
+
return this.whatsappConfig.graphApiVersion ?? "v24.0";
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
exports.BaseProvider = BaseProvider;
|
|
806
|
+
exports.EventEmitter = EventEmitter;
|
|
807
|
+
exports.PopupManager = PopupManager;
|
|
808
|
+
exports.TokenManager = TokenManager;
|
|
809
|
+
exports.WhatsAppProvider = WhatsAppProvider;
|
|
810
|
+
//# sourceMappingURL=chunk-ARDHIAFU.cjs.map
|
|
811
|
+
//# sourceMappingURL=chunk-ARDHIAFU.cjs.map
|