@omnikit-ai/sdk 2.0.9 → 2.2.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.
- package/dist/index.d.mts +333 -6
- package/dist/index.d.ts +333 -6
- package/dist/index.js +467 -55
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +464 -56
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -433,6 +433,53 @@ var LiveVoiceSessionImpl = class {
|
|
|
433
433
|
}
|
|
434
434
|
};
|
|
435
435
|
|
|
436
|
+
// src/connectors.ts
|
|
437
|
+
function createConnectorsModule(makeRequest, appId, baseUrl, getServiceToken) {
|
|
438
|
+
return {
|
|
439
|
+
async getAccessToken(connectorType) {
|
|
440
|
+
const serviceToken = getServiceToken();
|
|
441
|
+
if (!serviceToken) {
|
|
442
|
+
throw new Error(
|
|
443
|
+
"Service token is required to get connector access token. This method is only available in backend functions. Make sure you created the client with a serviceToken."
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
return makeRequest(
|
|
447
|
+
`${baseUrl}/apps/${appId}/connectors/${connectorType}/access-token`,
|
|
448
|
+
"GET",
|
|
449
|
+
null,
|
|
450
|
+
{ useServiceToken: true }
|
|
451
|
+
);
|
|
452
|
+
},
|
|
453
|
+
async isConnected(connectorType) {
|
|
454
|
+
try {
|
|
455
|
+
const response = await makeRequest(
|
|
456
|
+
`${baseUrl}/apps/${appId}/connectors/${connectorType}`,
|
|
457
|
+
"GET"
|
|
458
|
+
);
|
|
459
|
+
return response?.connector?.status === "connected";
|
|
460
|
+
} catch {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
async getStatus(connectorType) {
|
|
465
|
+
try {
|
|
466
|
+
const response = await makeRequest(
|
|
467
|
+
`${baseUrl}/apps/${appId}/connectors/${connectorType}`,
|
|
468
|
+
"GET"
|
|
469
|
+
);
|
|
470
|
+
return {
|
|
471
|
+
success: true,
|
|
472
|
+
connector: response?.connector
|
|
473
|
+
};
|
|
474
|
+
} catch (error) {
|
|
475
|
+
return {
|
|
476
|
+
success: false
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
436
483
|
// src/client.ts
|
|
437
484
|
var LLM_MODEL_MAP = {
|
|
438
485
|
// Gemini 2.5 models
|
|
@@ -527,10 +574,96 @@ var APIClient = class {
|
|
|
527
574
|
this.userToken = detectedToken;
|
|
528
575
|
}
|
|
529
576
|
}
|
|
577
|
+
this.initializeBuiltInServices();
|
|
530
578
|
this.ensureInitialized().catch((err) => {
|
|
531
579
|
console.warn("[Omnikit SDK] Background initialization failed:", err);
|
|
532
580
|
});
|
|
533
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* Initialize built-in services with their definitions
|
|
584
|
+
* These services don't require backend schema - they're defined in the SDK
|
|
585
|
+
*/
|
|
586
|
+
initializeBuiltInServices() {
|
|
587
|
+
const builtInServices = [
|
|
588
|
+
{
|
|
589
|
+
name: "SendEmail",
|
|
590
|
+
path: "/services/email",
|
|
591
|
+
description: "Send an email",
|
|
592
|
+
method: "POST",
|
|
593
|
+
params: { to: "string", subject: "string", body: "string" }
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
name: "InvokeLLM",
|
|
597
|
+
path: "/services/llm",
|
|
598
|
+
description: "Invoke a language model",
|
|
599
|
+
method: "POST",
|
|
600
|
+
params: { messages: "array", model: "string" }
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
name: "GenerateImage",
|
|
604
|
+
path: "/services/images",
|
|
605
|
+
description: "Generate an image from a prompt",
|
|
606
|
+
method: "POST",
|
|
607
|
+
async: true,
|
|
608
|
+
params: { prompt: "string" }
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
name: "GenerateSpeech",
|
|
612
|
+
path: "/services/speech",
|
|
613
|
+
description: "Generate speech from text",
|
|
614
|
+
method: "POST",
|
|
615
|
+
async: true,
|
|
616
|
+
params: { text: "string" }
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
name: "GenerateVideo",
|
|
620
|
+
path: "/services/video",
|
|
621
|
+
description: "Generate a video from a prompt",
|
|
622
|
+
method: "POST",
|
|
623
|
+
async: true,
|
|
624
|
+
params: { prompt: "string" }
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
name: "ExtractData",
|
|
628
|
+
path: "/services/extract-text",
|
|
629
|
+
description: "Extract structured data from text or files",
|
|
630
|
+
method: "POST",
|
|
631
|
+
async: true,
|
|
632
|
+
params: { file_url: "string" }
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
name: "SendSMS",
|
|
636
|
+
path: "/services/sms",
|
|
637
|
+
description: "Send an SMS message",
|
|
638
|
+
method: "POST",
|
|
639
|
+
params: { to: "string", body: "string" }
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
name: "UploadFile",
|
|
643
|
+
path: "/services/files",
|
|
644
|
+
description: "Upload a file (public)",
|
|
645
|
+
method: "POST",
|
|
646
|
+
params: { file: "File" }
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
name: "UploadPrivateFile",
|
|
650
|
+
path: "/services/files/private",
|
|
651
|
+
description: "Upload a private file",
|
|
652
|
+
method: "POST",
|
|
653
|
+
params: { file: "File" }
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
name: "CreateFileSignedUrl",
|
|
657
|
+
path: "/services/files/signed-url",
|
|
658
|
+
description: "Create a signed URL for a private file",
|
|
659
|
+
method: "POST",
|
|
660
|
+
params: { file_uri: "string" }
|
|
661
|
+
}
|
|
662
|
+
];
|
|
663
|
+
builtInServices.forEach((service) => {
|
|
664
|
+
this._services[service.name] = this.createServiceMethod(service);
|
|
665
|
+
});
|
|
666
|
+
}
|
|
534
667
|
/**
|
|
535
668
|
* Load metadata from localStorage cache, falling back to initial config
|
|
536
669
|
* Guards localStorage access for Deno/Node compatibility
|
|
@@ -670,13 +803,13 @@ var APIClient = class {
|
|
|
670
803
|
return this.createAuthProxy();
|
|
671
804
|
}
|
|
672
805
|
/**
|
|
673
|
-
*
|
|
674
|
-
* Only available when serviceToken is provided
|
|
806
|
+
* Service-level operations (elevated privileges).
|
|
807
|
+
* Only available when serviceToken is provided (e.g., via createServerClient).
|
|
675
808
|
*/
|
|
676
|
-
get
|
|
809
|
+
get service() {
|
|
677
810
|
if (!this._serviceToken) {
|
|
678
811
|
throw new OmnikitError(
|
|
679
|
-
"Service token is required
|
|
812
|
+
"Service token is required. Use createServerClient(req) in backend functions.",
|
|
680
813
|
403,
|
|
681
814
|
"SERVICE_TOKEN_REQUIRED"
|
|
682
815
|
);
|
|
@@ -689,12 +822,51 @@ var APIClient = class {
|
|
|
689
822
|
// Service role collections
|
|
690
823
|
services: this.createServicesProxy(true),
|
|
691
824
|
// Service role services (new flat structure)
|
|
692
|
-
integrations: this.createIntegrationsProxy(true)
|
|
825
|
+
integrations: this.createIntegrationsProxy(true),
|
|
693
826
|
// Service role integrations (legacy)
|
|
827
|
+
connectors: this.connectors
|
|
828
|
+
// Connectors module (requires service token)
|
|
694
829
|
// Note: auth not available in service role for security
|
|
695
830
|
};
|
|
696
831
|
return this._asServiceRole;
|
|
697
832
|
}
|
|
833
|
+
/**
|
|
834
|
+
* @deprecated Use service instead
|
|
835
|
+
*/
|
|
836
|
+
get asServiceRole() {
|
|
837
|
+
return this.service;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Lazy getter for connectors module
|
|
841
|
+
* Like Base44's connectors - provides access to external service tokens
|
|
842
|
+
*
|
|
843
|
+
* SECURITY: getAccessToken requires service token authentication.
|
|
844
|
+
* Only use in backend functions, not frontend code.
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* ```typescript
|
|
848
|
+
* // In a backend function
|
|
849
|
+
* const { access_token } = await omnikit.connectors.getAccessToken('slack');
|
|
850
|
+
*
|
|
851
|
+
* // Make direct Slack API call
|
|
852
|
+
* const response = await fetch('https://slack.com/api/chat.postMessage', {
|
|
853
|
+
* method: 'POST',
|
|
854
|
+
* headers: { Authorization: `Bearer ${access_token}` },
|
|
855
|
+
* body: JSON.stringify({ channel: '#general', text: 'Hello!' })
|
|
856
|
+
* });
|
|
857
|
+
* ```
|
|
858
|
+
*/
|
|
859
|
+
get connectors() {
|
|
860
|
+
if (!this._connectors) {
|
|
861
|
+
this._connectors = createConnectorsModule(
|
|
862
|
+
this.makeRequest.bind(this),
|
|
863
|
+
this.appId,
|
|
864
|
+
this.baseUrl,
|
|
865
|
+
() => this._serviceToken
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
return this._connectors;
|
|
869
|
+
}
|
|
698
870
|
/**
|
|
699
871
|
* Create auth proxy that auto-initializes
|
|
700
872
|
*/
|
|
@@ -1189,57 +1361,11 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
1189
1361
|
if (method) {
|
|
1190
1362
|
response = await method(params, useServiceToken);
|
|
1191
1363
|
} else {
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
"
|
|
1196
|
-
"GenerateSpeech": "services/speech",
|
|
1197
|
-
"GenerateVideo": "services/video",
|
|
1198
|
-
"ExtractData": "services/extract-text",
|
|
1199
|
-
"SendSMS": "services/sms",
|
|
1200
|
-
"UploadFile": "services/files",
|
|
1201
|
-
"UploadPrivateFile": "services/files/private/init",
|
|
1202
|
-
"CreateFileSignedUrl": "services/files/signed-url"
|
|
1203
|
-
};
|
|
1204
|
-
const servicePath = servicePathMap[normalizedName];
|
|
1205
|
-
if (!servicePath) {
|
|
1206
|
-
throw new OmnikitError(
|
|
1207
|
-
`Service '${serviceName}' not found. Known services: ${Object.keys(servicePathMap).join(", ")} (camelCase also supported)`,
|
|
1208
|
-
404,
|
|
1209
|
-
"SERVICE_NOT_FOUND"
|
|
1210
|
-
);
|
|
1211
|
-
}
|
|
1212
|
-
const headers = {
|
|
1213
|
-
"Content-Type": "application/json"
|
|
1214
|
-
};
|
|
1215
|
-
if (client._apiKey) {
|
|
1216
|
-
headers["X-API-Key"] = client._apiKey;
|
|
1217
|
-
} else if (client.userToken) {
|
|
1218
|
-
headers["Authorization"] = `Bearer ${client.userToken}`;
|
|
1219
|
-
}
|
|
1220
|
-
if ((normalizedName === "UploadFile" || normalizedName === "uploadFile") && params?.file instanceof File) {
|
|
1221
|
-
return client.handleFileUpload(params.file, servicePath, useServiceToken);
|
|
1222
|
-
}
|
|
1223
|
-
if ((normalizedName === "UploadPrivateFile" || normalizedName === "uploadPrivateFile") && params?.file instanceof File) {
|
|
1224
|
-
return client.handleFileUpload(params.file, servicePath, useServiceToken);
|
|
1225
|
-
}
|
|
1226
|
-
const fetchResponse = await fetch(
|
|
1227
|
-
`${client.baseUrl}/apps/${client.appId}/${servicePath}`,
|
|
1228
|
-
{
|
|
1229
|
-
method: "POST",
|
|
1230
|
-
headers,
|
|
1231
|
-
body: JSON.stringify(params || {})
|
|
1232
|
-
}
|
|
1364
|
+
throw new OmnikitError(
|
|
1365
|
+
`Service '${serviceName}' not found. Known services: SendEmail, InvokeLLM, GenerateImage, GenerateSpeech, GenerateVideo, ExtractData, SendSMS, UploadFile, UploadPrivateFile, CreateFileSignedUrl (camelCase also supported)`,
|
|
1366
|
+
404,
|
|
1367
|
+
"SERVICE_NOT_FOUND"
|
|
1233
1368
|
);
|
|
1234
|
-
if (!fetchResponse.ok) {
|
|
1235
|
-
const error = await fetchResponse.json().catch(() => ({}));
|
|
1236
|
-
throw new OmnikitError(
|
|
1237
|
-
error.detail || `Service call failed: ${fetchResponse.statusText}`,
|
|
1238
|
-
fetchResponse.status,
|
|
1239
|
-
"SERVICE_CALL_FAILED"
|
|
1240
|
-
);
|
|
1241
|
-
}
|
|
1242
|
-
response = await fetchResponse.json();
|
|
1243
1369
|
}
|
|
1244
1370
|
if (response && response.async && response.job_id) {
|
|
1245
1371
|
if (asyncOptions?.returnJobId) {
|
|
@@ -2194,7 +2320,289 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
2194
2320
|
function createClient(config) {
|
|
2195
2321
|
return new APIClient(config);
|
|
2196
2322
|
}
|
|
2323
|
+
function createServerClient(request) {
|
|
2324
|
+
const getHeader = (name) => {
|
|
2325
|
+
if (typeof request.headers.get === "function") {
|
|
2326
|
+
return request.headers.get(name);
|
|
2327
|
+
}
|
|
2328
|
+
return request.headers[name] || request.headers[name.toLowerCase()] || null;
|
|
2329
|
+
};
|
|
2330
|
+
const authHeader = getHeader("Authorization") || getHeader("authorization");
|
|
2331
|
+
const userToken = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
2332
|
+
const serviceToken = getHeader("X-Omnikit-Service-Authorization") || getHeader("x-omnikit-service-authorization");
|
|
2333
|
+
const appId = getHeader("X-Omnikit-App-Id") || getHeader("x-omnikit-app-id");
|
|
2334
|
+
const serverUrl = getHeader("X-Omnikit-Server-Url") || getHeader("x-omnikit-server-url") || "https://omnikit.ai/api";
|
|
2335
|
+
if (!appId) {
|
|
2336
|
+
throw new OmnikitError(
|
|
2337
|
+
"X-Omnikit-App-Id header is required. This function should be invoked through the Omnikit platform.",
|
|
2338
|
+
400,
|
|
2339
|
+
"MISSING_APP_ID"
|
|
2340
|
+
);
|
|
2341
|
+
}
|
|
2342
|
+
return createClient({
|
|
2343
|
+
appId,
|
|
2344
|
+
serverUrl,
|
|
2345
|
+
token: userToken || void 0,
|
|
2346
|
+
serviceToken: serviceToken || void 0,
|
|
2347
|
+
autoInitAuth: false
|
|
2348
|
+
// Don't auto-detect from localStorage in backend
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
var createClientFromRequest = createServerClient;
|
|
2352
|
+
|
|
2353
|
+
// src/analytics.ts
|
|
2354
|
+
var STORAGE_KEY = "omnikit_session";
|
|
2355
|
+
var SESSION_TIMEOUT = 30 * 60 * 1e3;
|
|
2356
|
+
var FLUSH_INTERVAL = 5e3;
|
|
2357
|
+
var MAX_RETRIES = 3;
|
|
2358
|
+
var Analytics = class {
|
|
2359
|
+
constructor(config) {
|
|
2360
|
+
this.eventQueue = [];
|
|
2361
|
+
this.config = config;
|
|
2362
|
+
this.enabled = config.enabled !== false;
|
|
2363
|
+
this.sessionId = config.sessionId || this.initSession();
|
|
2364
|
+
this.userId = config.userId;
|
|
2365
|
+
if (this.enabled && typeof window !== "undefined") {
|
|
2366
|
+
this.startFlushTimer();
|
|
2367
|
+
window.addEventListener("beforeunload", () => this.flush());
|
|
2368
|
+
window.addEventListener("pagehide", () => this.flush());
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
// ==========================================================================
|
|
2372
|
+
// Session Management
|
|
2373
|
+
// ==========================================================================
|
|
2374
|
+
initSession() {
|
|
2375
|
+
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
2376
|
+
return this.generateId();
|
|
2377
|
+
}
|
|
2378
|
+
try {
|
|
2379
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
2380
|
+
if (stored) {
|
|
2381
|
+
const { id, timestamp } = JSON.parse(stored);
|
|
2382
|
+
if (Date.now() - timestamp < SESSION_TIMEOUT) {
|
|
2383
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
2384
|
+
id,
|
|
2385
|
+
timestamp: Date.now()
|
|
2386
|
+
}));
|
|
2387
|
+
return id;
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
} catch {
|
|
2391
|
+
}
|
|
2392
|
+
const newId = this.generateId();
|
|
2393
|
+
this.saveSession(newId);
|
|
2394
|
+
return newId;
|
|
2395
|
+
}
|
|
2396
|
+
generateId() {
|
|
2397
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
2398
|
+
return crypto.randomUUID();
|
|
2399
|
+
}
|
|
2400
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
2401
|
+
const r = Math.random() * 16 | 0;
|
|
2402
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
2403
|
+
return v.toString(16);
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
saveSession(id) {
|
|
2407
|
+
if (typeof localStorage === "undefined") return;
|
|
2408
|
+
try {
|
|
2409
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
2410
|
+
id,
|
|
2411
|
+
timestamp: Date.now()
|
|
2412
|
+
}));
|
|
2413
|
+
} catch {
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
/**
|
|
2417
|
+
* Get the current session ID
|
|
2418
|
+
*/
|
|
2419
|
+
getSessionId() {
|
|
2420
|
+
return this.sessionId;
|
|
2421
|
+
}
|
|
2422
|
+
/**
|
|
2423
|
+
* Start a new session (e.g., after logout)
|
|
2424
|
+
*/
|
|
2425
|
+
startNewSession() {
|
|
2426
|
+
this.sessionId = this.generateId();
|
|
2427
|
+
this.saveSession(this.sessionId);
|
|
2428
|
+
return this.sessionId;
|
|
2429
|
+
}
|
|
2430
|
+
// ==========================================================================
|
|
2431
|
+
// User Identification
|
|
2432
|
+
// ==========================================================================
|
|
2433
|
+
/**
|
|
2434
|
+
* Associate events with a user ID
|
|
2435
|
+
*/
|
|
2436
|
+
setUserId(userId) {
|
|
2437
|
+
this.userId = userId;
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* Clear user association (e.g., on logout)
|
|
2441
|
+
*/
|
|
2442
|
+
clearUserId() {
|
|
2443
|
+
this.userId = void 0;
|
|
2444
|
+
}
|
|
2445
|
+
// ==========================================================================
|
|
2446
|
+
// Core Logging Methods
|
|
2447
|
+
// ==========================================================================
|
|
2448
|
+
/**
|
|
2449
|
+
* Log a custom event
|
|
2450
|
+
*/
|
|
2451
|
+
async logEvent(eventType, payload = {}) {
|
|
2452
|
+
if (!this.enabled) return;
|
|
2453
|
+
this.eventQueue.push({
|
|
2454
|
+
eventType,
|
|
2455
|
+
payload,
|
|
2456
|
+
timestamp: Date.now()
|
|
2457
|
+
});
|
|
2458
|
+
if (eventType === "error" || eventType === "api_error") {
|
|
2459
|
+
await this.flush();
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Log a page view event
|
|
2464
|
+
*/
|
|
2465
|
+
async logPageView(pageName, metadata) {
|
|
2466
|
+
if (!this.enabled) return;
|
|
2467
|
+
const url = typeof window !== "undefined" ? window.location.href : "";
|
|
2468
|
+
const referrer = typeof document !== "undefined" ? document.referrer : "";
|
|
2469
|
+
await this.logEvent("page_view", {
|
|
2470
|
+
page_name: pageName,
|
|
2471
|
+
metadata: {
|
|
2472
|
+
url,
|
|
2473
|
+
referrer,
|
|
2474
|
+
...metadata
|
|
2475
|
+
}
|
|
2476
|
+
});
|
|
2477
|
+
}
|
|
2478
|
+
/**
|
|
2479
|
+
* Log an error event
|
|
2480
|
+
*/
|
|
2481
|
+
async logError(error, componentStack) {
|
|
2482
|
+
if (!this.enabled) return;
|
|
2483
|
+
const url = typeof window !== "undefined" ? window.location.href : "";
|
|
2484
|
+
await this.logEvent("error", {
|
|
2485
|
+
error_message: error.message,
|
|
2486
|
+
error_stack: error.stack,
|
|
2487
|
+
metadata: {
|
|
2488
|
+
name: error.name,
|
|
2489
|
+
component_stack: componentStack,
|
|
2490
|
+
url
|
|
2491
|
+
}
|
|
2492
|
+
});
|
|
2493
|
+
}
|
|
2494
|
+
/**
|
|
2495
|
+
* Log an API error event
|
|
2496
|
+
*/
|
|
2497
|
+
async logApiError(endpoint, statusCode, errorMessage, metadata) {
|
|
2498
|
+
if (!this.enabled) return;
|
|
2499
|
+
await this.logEvent("api_error", {
|
|
2500
|
+
error_message: errorMessage,
|
|
2501
|
+
metadata: {
|
|
2502
|
+
endpoint,
|
|
2503
|
+
status_code: statusCode,
|
|
2504
|
+
...metadata
|
|
2505
|
+
}
|
|
2506
|
+
});
|
|
2507
|
+
}
|
|
2508
|
+
// ==========================================================================
|
|
2509
|
+
// Event Batching & Flushing
|
|
2510
|
+
// ==========================================================================
|
|
2511
|
+
startFlushTimer() {
|
|
2512
|
+
if (this.flushTimer) return;
|
|
2513
|
+
this.flushTimer = setInterval(() => {
|
|
2514
|
+
if (this.eventQueue.length > 0) {
|
|
2515
|
+
this.flush();
|
|
2516
|
+
}
|
|
2517
|
+
}, FLUSH_INTERVAL);
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Flush all queued events to the server
|
|
2521
|
+
*/
|
|
2522
|
+
async flush() {
|
|
2523
|
+
if (this.eventQueue.length === 0) return;
|
|
2524
|
+
const events = [...this.eventQueue];
|
|
2525
|
+
this.eventQueue = [];
|
|
2526
|
+
const sendPromises = events.map(
|
|
2527
|
+
({ eventType, payload }) => this.sendEvent(eventType, payload)
|
|
2528
|
+
);
|
|
2529
|
+
await Promise.allSettled(sendPromises);
|
|
2530
|
+
}
|
|
2531
|
+
async sendEvent(eventType, payload) {
|
|
2532
|
+
const pageName = payload.page_name || (typeof window !== "undefined" ? window.location.pathname : "/");
|
|
2533
|
+
const url = `${this.config.apiUrl}/api/app-logs/${this.config.appId}/log-event`;
|
|
2534
|
+
const body = {
|
|
2535
|
+
session_id: this.sessionId,
|
|
2536
|
+
user_id: this.userId,
|
|
2537
|
+
event_type: eventType,
|
|
2538
|
+
page_name: pageName,
|
|
2539
|
+
action: payload.action,
|
|
2540
|
+
inputs: payload.inputs,
|
|
2541
|
+
metadata: payload.metadata,
|
|
2542
|
+
is_error: eventType === "error" || eventType === "api_error",
|
|
2543
|
+
error_message: payload.error_message,
|
|
2544
|
+
error_stack: payload.error_stack
|
|
2545
|
+
};
|
|
2546
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
2547
|
+
try {
|
|
2548
|
+
const response = await fetch(url, {
|
|
2549
|
+
method: "POST",
|
|
2550
|
+
headers: { "Content-Type": "application/json" },
|
|
2551
|
+
body: JSON.stringify(body),
|
|
2552
|
+
keepalive: true
|
|
2553
|
+
// Ensures request completes even on page unload
|
|
2554
|
+
});
|
|
2555
|
+
if (response.ok) {
|
|
2556
|
+
return;
|
|
2557
|
+
}
|
|
2558
|
+
if (response.status >= 400 && response.status < 500) {
|
|
2559
|
+
console.warn(`[Omnikit Analytics] Event rejected: ${response.status}`);
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
} catch (err) {
|
|
2563
|
+
}
|
|
2564
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
2565
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3));
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
console.warn("[Omnikit Analytics] Failed to send event after retries");
|
|
2569
|
+
}
|
|
2570
|
+
// ==========================================================================
|
|
2571
|
+
// Lifecycle
|
|
2572
|
+
// ==========================================================================
|
|
2573
|
+
/**
|
|
2574
|
+
* Enable or disable analytics
|
|
2575
|
+
*/
|
|
2576
|
+
setEnabled(enabled) {
|
|
2577
|
+
this.enabled = enabled;
|
|
2578
|
+
if (enabled && typeof window !== "undefined") {
|
|
2579
|
+
this.startFlushTimer();
|
|
2580
|
+
} else if (this.flushTimer) {
|
|
2581
|
+
clearInterval(this.flushTimer);
|
|
2582
|
+
this.flushTimer = void 0;
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
/**
|
|
2586
|
+
* Check if analytics is enabled
|
|
2587
|
+
*/
|
|
2588
|
+
isEnabled() {
|
|
2589
|
+
return this.enabled;
|
|
2590
|
+
}
|
|
2591
|
+
/**
|
|
2592
|
+
* Clean up resources
|
|
2593
|
+
*/
|
|
2594
|
+
destroy() {
|
|
2595
|
+
if (this.flushTimer) {
|
|
2596
|
+
clearInterval(this.flushTimer);
|
|
2597
|
+
this.flushTimer = void 0;
|
|
2598
|
+
}
|
|
2599
|
+
this.flush();
|
|
2600
|
+
}
|
|
2601
|
+
};
|
|
2602
|
+
function createAnalytics(config) {
|
|
2603
|
+
return new Analytics(config);
|
|
2604
|
+
}
|
|
2197
2605
|
|
|
2198
|
-
export { APIClient, LiveVoiceSessionImpl, OmnikitError, cleanTokenFromUrl, createClient, getAccessToken, isTokenInUrl, removeAccessToken, saveAccessToken, setAccessToken };
|
|
2606
|
+
export { APIClient, Analytics, LiveVoiceSessionImpl, OmnikitError, cleanTokenFromUrl, createAnalytics, createClient, createClientFromRequest, createServerClient, getAccessToken, isTokenInUrl, removeAccessToken, saveAccessToken, setAccessToken };
|
|
2199
2607
|
//# sourceMappingURL=index.mjs.map
|
|
2200
2608
|
//# sourceMappingURL=index.mjs.map
|