@omnikit-ai/sdk 2.0.10 → 2.2.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/index.d.mts +573 -13
- package/dist/index.d.ts +573 -13
- package/dist/index.js +571 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +568 -65
- 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
|
|
@@ -611,6 +658,20 @@ var APIClient = class {
|
|
|
611
658
|
description: "Create a signed URL for a private file",
|
|
612
659
|
method: "POST",
|
|
613
660
|
params: { file_uri: "string" }
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
name: "DownloadPrivateFile",
|
|
664
|
+
path: "/services/files/private/download",
|
|
665
|
+
description: "Download a private file via backend proxy (solves CORS issues)",
|
|
666
|
+
method: "POST",
|
|
667
|
+
params: { file_uri: "string" }
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
name: "DownloadFile",
|
|
671
|
+
path: "/services/files/{file_id}/download",
|
|
672
|
+
description: "Download a public file via backend proxy (like Supabase ?download)",
|
|
673
|
+
method: "GET",
|
|
674
|
+
params: { file_id: "string", download: "boolean", filename: "string" }
|
|
614
675
|
}
|
|
615
676
|
];
|
|
616
677
|
builtInServices.forEach((service) => {
|
|
@@ -756,13 +817,13 @@ var APIClient = class {
|
|
|
756
817
|
return this.createAuthProxy();
|
|
757
818
|
}
|
|
758
819
|
/**
|
|
759
|
-
*
|
|
760
|
-
* Only available when serviceToken is provided
|
|
820
|
+
* Service-level operations (elevated privileges).
|
|
821
|
+
* Only available when serviceToken is provided (e.g., via createServerClient).
|
|
761
822
|
*/
|
|
762
|
-
get
|
|
823
|
+
get service() {
|
|
763
824
|
if (!this._serviceToken) {
|
|
764
825
|
throw new OmnikitError(
|
|
765
|
-
"Service token is required
|
|
826
|
+
"Service token is required. Use createServerClient(req) in backend functions.",
|
|
766
827
|
403,
|
|
767
828
|
"SERVICE_TOKEN_REQUIRED"
|
|
768
829
|
);
|
|
@@ -775,12 +836,70 @@ var APIClient = class {
|
|
|
775
836
|
// Service role collections
|
|
776
837
|
services: this.createServicesProxy(true),
|
|
777
838
|
// Service role services (new flat structure)
|
|
778
|
-
integrations: this.createIntegrationsProxy(true)
|
|
839
|
+
integrations: this.createIntegrationsProxy(true),
|
|
779
840
|
// Service role integrations (legacy)
|
|
841
|
+
connectors: this.connectors
|
|
842
|
+
// Connectors module (requires service token)
|
|
780
843
|
// Note: auth not available in service role for security
|
|
781
844
|
};
|
|
782
845
|
return this._asServiceRole;
|
|
783
846
|
}
|
|
847
|
+
/**
|
|
848
|
+
* @deprecated Use service instead
|
|
849
|
+
*/
|
|
850
|
+
get asServiceRole() {
|
|
851
|
+
return this.service;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Lazy getter for connectors module
|
|
855
|
+
* Like Base44's connectors - provides access to external service tokens
|
|
856
|
+
*
|
|
857
|
+
* SECURITY: getAccessToken requires service token authentication.
|
|
858
|
+
* Only use in backend functions, not frontend code.
|
|
859
|
+
*
|
|
860
|
+
* @example
|
|
861
|
+
* ```typescript
|
|
862
|
+
* // In a backend function
|
|
863
|
+
* const { access_token } = await omnikit.connectors.getAccessToken('slack');
|
|
864
|
+
*
|
|
865
|
+
* // Make direct Slack API call
|
|
866
|
+
* const response = await fetch('https://slack.com/api/chat.postMessage', {
|
|
867
|
+
* method: 'POST',
|
|
868
|
+
* headers: { Authorization: `Bearer ${access_token}` },
|
|
869
|
+
* body: JSON.stringify({ channel: '#general', text: 'Hello!' })
|
|
870
|
+
* });
|
|
871
|
+
* ```
|
|
872
|
+
*/
|
|
873
|
+
get connectors() {
|
|
874
|
+
if (!this._connectors) {
|
|
875
|
+
this._connectors = createConnectorsModule(
|
|
876
|
+
this.makeRequest.bind(this),
|
|
877
|
+
this.appId,
|
|
878
|
+
this.baseUrl,
|
|
879
|
+
() => this._serviceToken
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
return this._connectors;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Resolve a return URL to an absolute URL.
|
|
886
|
+
* Handles relative paths like "/profile" by combining with current location.
|
|
887
|
+
* This fixes the OAuth redirect bug where relative URLs like "/profile" become
|
|
888
|
+
* "https://omnikit.ai/profile" instead of "https://omnikit.ai/app-builder/{id}/preview/profile"
|
|
889
|
+
*/
|
|
890
|
+
_resolveReturnUrl(returnUrl) {
|
|
891
|
+
if (typeof window === "undefined") return returnUrl || "/";
|
|
892
|
+
if (!returnUrl) return window.location.href;
|
|
893
|
+
if (returnUrl.startsWith("http://") || returnUrl.startsWith("https://")) {
|
|
894
|
+
return returnUrl;
|
|
895
|
+
}
|
|
896
|
+
if (returnUrl.startsWith("/")) {
|
|
897
|
+
const basePath = window.location.pathname.endsWith("/") ? window.location.pathname.slice(0, -1) : window.location.pathname;
|
|
898
|
+
return window.location.origin + basePath + returnUrl;
|
|
899
|
+
}
|
|
900
|
+
const base = window.location.origin + window.location.pathname;
|
|
901
|
+
return base.endsWith("/") ? base + returnUrl : base + "/" + returnUrl;
|
|
902
|
+
}
|
|
784
903
|
/**
|
|
785
904
|
* Create auth proxy that auto-initializes
|
|
786
905
|
*/
|
|
@@ -808,31 +927,42 @@ var APIClient = class {
|
|
|
808
927
|
client.emitUserChange(response);
|
|
809
928
|
return response;
|
|
810
929
|
},
|
|
811
|
-
login(returnUrl) {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
} else {
|
|
824
|
-
window.location.href = `/login?return_url=${encodedReturnUrl}`;
|
|
930
|
+
async login(returnUrl) {
|
|
931
|
+
if (typeof window === "undefined") return;
|
|
932
|
+
const fullReturnUrl = client._resolveReturnUrl(returnUrl);
|
|
933
|
+
const token = getAccessToken();
|
|
934
|
+
if (token) {
|
|
935
|
+
try {
|
|
936
|
+
const isAuth = await this.isAuthenticated();
|
|
937
|
+
if (isAuth && returnUrl) {
|
|
938
|
+
window.location.href = fullReturnUrl;
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
} catch {
|
|
825
942
|
}
|
|
826
943
|
}
|
|
944
|
+
if (window.__omnikit_openLoginModal) {
|
|
945
|
+
window.__omnikit_openLoginModal(fullReturnUrl);
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
const encodedReturnUrl = encodeURIComponent(fullReturnUrl);
|
|
949
|
+
const currentPath = window.location.pathname;
|
|
950
|
+
const apiSitesMatch = currentPath.match(/^\/api\/sites\/([^\/]+)/);
|
|
951
|
+
if (apiSitesMatch) {
|
|
952
|
+
window.location.href = `/api/sites/${client.appId}/login?return_url=${encodedReturnUrl}`;
|
|
953
|
+
} else {
|
|
954
|
+
window.location.href = `/login?return_url=${encodedReturnUrl}`;
|
|
955
|
+
}
|
|
827
956
|
},
|
|
828
957
|
/**
|
|
829
958
|
* Request a passwordless login code to email
|
|
830
959
|
*/
|
|
831
960
|
async requestLoginCode(email, returnUrl) {
|
|
961
|
+
const fullReturnUrl = returnUrl ? client._resolveReturnUrl(returnUrl) : void 0;
|
|
832
962
|
return await client.makeRequest(
|
|
833
963
|
`${client.baseUrl}/auth/email/request-code`,
|
|
834
964
|
"POST",
|
|
835
|
-
{ email, return_url:
|
|
965
|
+
{ email, return_url: fullReturnUrl }
|
|
836
966
|
);
|
|
837
967
|
},
|
|
838
968
|
/**
|
|
@@ -880,44 +1010,43 @@ var APIClient = class {
|
|
|
880
1010
|
* Redirects to the backend OAuth endpoint for the specified provider
|
|
881
1011
|
*/
|
|
882
1012
|
loginWithProvider(providerId, returnUrl) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1013
|
+
if (typeof window === "undefined") {
|
|
1014
|
+
throw new OmnikitError("loginWithProvider() can only be called in browser environment", 400, "NOT_BROWSER");
|
|
1015
|
+
}
|
|
1016
|
+
const fullReturnUrl = client._resolveReturnUrl(returnUrl);
|
|
1017
|
+
const redirectUrl = `${client.baseUrl}/auth/${providerId}?redirect_url=${encodeURIComponent(fullReturnUrl)}`;
|
|
1018
|
+
const inIframe = window.self !== window.top;
|
|
1019
|
+
if (inIframe) {
|
|
1020
|
+
const width = 600;
|
|
1021
|
+
const height = 700;
|
|
1022
|
+
const left = window.screen.width / 2 - width / 2;
|
|
1023
|
+
const top = window.screen.height / 2 - height / 2;
|
|
1024
|
+
const popup = window.open(
|
|
1025
|
+
redirectUrl,
|
|
1026
|
+
"oauth_popup",
|
|
1027
|
+
`width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes,status=yes`
|
|
1028
|
+
);
|
|
1029
|
+
if (popup) {
|
|
1030
|
+
const checkTimer = setInterval(() => {
|
|
1031
|
+
const token = getAccessToken();
|
|
1032
|
+
if (token) {
|
|
1033
|
+
clearInterval(checkTimer);
|
|
1034
|
+
popup.close();
|
|
1035
|
+
window.location.reload();
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
if (popup.closed) {
|
|
1039
|
+
clearInterval(checkTimer);
|
|
1040
|
+
const finalToken = getAccessToken();
|
|
1041
|
+
if (finalToken) {
|
|
903
1042
|
window.location.reload();
|
|
904
|
-
return;
|
|
905
1043
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
if (finalToken) {
|
|
910
|
-
window.location.reload();
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
}, 1e3);
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
1044
|
+
}
|
|
1045
|
+
}, 1e3);
|
|
1046
|
+
return;
|
|
916
1047
|
}
|
|
917
|
-
window.location.href = redirectUrl;
|
|
918
|
-
} else {
|
|
919
|
-
throw new OmnikitError("loginWithProvider() can only be called in browser environment", 400, "NOT_BROWSER");
|
|
920
1048
|
}
|
|
1049
|
+
window.location.href = redirectUrl;
|
|
921
1050
|
},
|
|
922
1051
|
/**
|
|
923
1052
|
* Initiate Google OAuth Login
|
|
@@ -1129,7 +1258,8 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
1129
1258
|
// Remove callback functions from request body
|
|
1130
1259
|
onToken: void 0,
|
|
1131
1260
|
onComplete: void 0,
|
|
1132
|
-
onError: void 0
|
|
1261
|
+
onError: void 0,
|
|
1262
|
+
onToolCall: void 0
|
|
1133
1263
|
};
|
|
1134
1264
|
Object.keys(requestBody).forEach((key) => {
|
|
1135
1265
|
if (requestBody[key] === void 0) {
|
|
@@ -1180,6 +1310,14 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
1180
1310
|
if (event.type === "token" && event.content) {
|
|
1181
1311
|
fullResponse += event.content;
|
|
1182
1312
|
params.onToken?.(event.content);
|
|
1313
|
+
} else if (event.type === "tool_call") {
|
|
1314
|
+
if (params.onToolCall && event.id && event.name) {
|
|
1315
|
+
params.onToolCall({
|
|
1316
|
+
id: event.id,
|
|
1317
|
+
name: event.name,
|
|
1318
|
+
arguments: event.arguments || {}
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1183
1321
|
} else if (event.type === "done") {
|
|
1184
1322
|
params.onComplete?.({
|
|
1185
1323
|
result: event.result || fullResponse,
|
|
@@ -1238,6 +1376,56 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
1238
1376
|
);
|
|
1239
1377
|
};
|
|
1240
1378
|
}
|
|
1379
|
+
if (normalizedName === "DownloadFile") {
|
|
1380
|
+
return async function(params) {
|
|
1381
|
+
await client.ensureInitialized();
|
|
1382
|
+
if (!params?.file_id) {
|
|
1383
|
+
throw new OmnikitError(
|
|
1384
|
+
"file_id is required for DownloadFile",
|
|
1385
|
+
400,
|
|
1386
|
+
"MISSING_FILE_ID"
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
const downloadUrl = new URL(`${client.baseUrl}/apps/${client.appId}/services/files/${params.file_id}/download`);
|
|
1390
|
+
if (params.download !== void 0) {
|
|
1391
|
+
downloadUrl.searchParams.set("download", String(params.download));
|
|
1392
|
+
}
|
|
1393
|
+
if (params.filename) {
|
|
1394
|
+
downloadUrl.searchParams.set("filename", params.filename);
|
|
1395
|
+
}
|
|
1396
|
+
const response = await fetch(downloadUrl.toString(), {
|
|
1397
|
+
method: "GET"
|
|
1398
|
+
});
|
|
1399
|
+
if (!response.ok) {
|
|
1400
|
+
const error = await response.json().catch(() => ({ detail: "Download failed" }));
|
|
1401
|
+
throw new OmnikitError(
|
|
1402
|
+
error.detail || "Download failed",
|
|
1403
|
+
response.status,
|
|
1404
|
+
"DOWNLOAD_FAILED"
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
const blob = await response.blob();
|
|
1408
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
1409
|
+
let filename = params.filename;
|
|
1410
|
+
if (!filename) {
|
|
1411
|
+
const contentDisposition = response.headers.get("Content-Disposition");
|
|
1412
|
+
if (contentDisposition) {
|
|
1413
|
+
const match = contentDisposition.match(/filename="?([^"]+)"?/);
|
|
1414
|
+
if (match) filename = match[1];
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
if (!filename) {
|
|
1418
|
+
filename = `file-${params.file_id}`;
|
|
1419
|
+
}
|
|
1420
|
+
const link = document.createElement("a");
|
|
1421
|
+
link.href = blobUrl;
|
|
1422
|
+
link.download = filename;
|
|
1423
|
+
document.body.appendChild(link);
|
|
1424
|
+
link.click();
|
|
1425
|
+
document.body.removeChild(link);
|
|
1426
|
+
URL.revokeObjectURL(blobUrl);
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1241
1429
|
if (normalizedName === "DownloadPrivateFile") {
|
|
1242
1430
|
return async function(params) {
|
|
1243
1431
|
await client.ensureInitialized();
|
|
@@ -1248,16 +1436,47 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
1248
1436
|
"MISSING_FILE_URI"
|
|
1249
1437
|
);
|
|
1250
1438
|
}
|
|
1251
|
-
const downloadUrl =
|
|
1252
|
-
downloadUrl.searchParams.set("file_uri", params.file_uri);
|
|
1253
|
-
if (params.filename) {
|
|
1254
|
-
downloadUrl.searchParams.set("filename", params.filename);
|
|
1255
|
-
}
|
|
1439
|
+
const downloadUrl = `${client.baseUrl}/apps/${client.appId}/services/files/private/download`;
|
|
1256
1440
|
const token = client.getAuthToken();
|
|
1257
|
-
|
|
1258
|
-
|
|
1441
|
+
const response = await fetch(downloadUrl, {
|
|
1442
|
+
method: "POST",
|
|
1443
|
+
headers: {
|
|
1444
|
+
"Content-Type": "application/json",
|
|
1445
|
+
...token ? { "Authorization": `Bearer ${token}` } : {}
|
|
1446
|
+
},
|
|
1447
|
+
body: JSON.stringify({ file_uri: params.file_uri })
|
|
1448
|
+
});
|
|
1449
|
+
if (!response.ok) {
|
|
1450
|
+
const error = await response.json().catch(() => ({ detail: "Download failed" }));
|
|
1451
|
+
throw new OmnikitError(
|
|
1452
|
+
error.detail || "Download failed",
|
|
1453
|
+
response.status,
|
|
1454
|
+
"DOWNLOAD_FAILED"
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
const blob = await response.blob();
|
|
1458
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
1459
|
+
let filename = params.filename;
|
|
1460
|
+
if (!filename) {
|
|
1461
|
+
const contentDisposition = response.headers.get("Content-Disposition");
|
|
1462
|
+
if (contentDisposition) {
|
|
1463
|
+
const match = contentDisposition.match(/filename="?([^"]+)"?/);
|
|
1464
|
+
if (match) filename = match[1];
|
|
1465
|
+
}
|
|
1259
1466
|
}
|
|
1260
|
-
|
|
1467
|
+
if (!filename) {
|
|
1468
|
+
const uriParts = params.file_uri.split("/");
|
|
1469
|
+
const lastPart = uriParts[uriParts.length - 1];
|
|
1470
|
+
const underscoreIdx = lastPart.indexOf("_");
|
|
1471
|
+
filename = underscoreIdx > 0 ? lastPart.slice(underscoreIdx + 1) : lastPart;
|
|
1472
|
+
}
|
|
1473
|
+
const link = document.createElement("a");
|
|
1474
|
+
link.href = blobUrl;
|
|
1475
|
+
link.download = filename;
|
|
1476
|
+
document.body.appendChild(link);
|
|
1477
|
+
link.click();
|
|
1478
|
+
document.body.removeChild(link);
|
|
1479
|
+
URL.revokeObjectURL(blobUrl);
|
|
1261
1480
|
};
|
|
1262
1481
|
}
|
|
1263
1482
|
return async function(params, asyncOptions) {
|
|
@@ -1276,7 +1495,7 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
1276
1495
|
response = await method(params, useServiceToken);
|
|
1277
1496
|
} else {
|
|
1278
1497
|
throw new OmnikitError(
|
|
1279
|
-
`Service '${serviceName}' not found. Known services: SendEmail, InvokeLLM, GenerateImage, GenerateSpeech, GenerateVideo, ExtractData, SendSMS, UploadFile, UploadPrivateFile, CreateFileSignedUrl (camelCase also supported)`,
|
|
1498
|
+
`Service '${serviceName}' not found. Known services: SendEmail, InvokeLLM, GenerateImage, GenerateSpeech, GenerateVideo, ExtractData, SendSMS, UploadFile, UploadPrivateFile, CreateFileSignedUrl, DownloadFile, DownloadPrivateFile (camelCase also supported)`,
|
|
1280
1499
|
404,
|
|
1281
1500
|
"SERVICE_NOT_FOUND"
|
|
1282
1501
|
);
|
|
@@ -1792,6 +2011,8 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
1792
2011
|
"files": "UploadFile",
|
|
1793
2012
|
"files/private": "UploadPrivateFile",
|
|
1794
2013
|
"files/signed-url": "CreateFileSignedUrl",
|
|
2014
|
+
"files/private/download": "DownloadPrivateFile",
|
|
2015
|
+
"files/download": "DownloadFile",
|
|
1795
2016
|
"images": "GenerateImage",
|
|
1796
2017
|
"speech": "GenerateSpeech",
|
|
1797
2018
|
"video": "GenerateVideo",
|
|
@@ -2234,7 +2455,289 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
|
|
|
2234
2455
|
function createClient(config) {
|
|
2235
2456
|
return new APIClient(config);
|
|
2236
2457
|
}
|
|
2458
|
+
function createServerClient(request) {
|
|
2459
|
+
const getHeader = (name) => {
|
|
2460
|
+
if (typeof request.headers.get === "function") {
|
|
2461
|
+
return request.headers.get(name);
|
|
2462
|
+
}
|
|
2463
|
+
return request.headers[name] || request.headers[name.toLowerCase()] || null;
|
|
2464
|
+
};
|
|
2465
|
+
const authHeader = getHeader("Authorization") || getHeader("authorization");
|
|
2466
|
+
const userToken = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
2467
|
+
const serviceToken = getHeader("X-Omnikit-Service-Authorization") || getHeader("x-omnikit-service-authorization");
|
|
2468
|
+
const appId = getHeader("X-Omnikit-App-Id") || getHeader("x-omnikit-app-id");
|
|
2469
|
+
const serverUrl = getHeader("X-Omnikit-Server-Url") || getHeader("x-omnikit-server-url") || "https://omnikit.ai/api";
|
|
2470
|
+
if (!appId) {
|
|
2471
|
+
throw new OmnikitError(
|
|
2472
|
+
"X-Omnikit-App-Id header is required. This function should be invoked through the Omnikit platform.",
|
|
2473
|
+
400,
|
|
2474
|
+
"MISSING_APP_ID"
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
return createClient({
|
|
2478
|
+
appId,
|
|
2479
|
+
serverUrl,
|
|
2480
|
+
token: userToken || void 0,
|
|
2481
|
+
serviceToken: serviceToken || void 0,
|
|
2482
|
+
autoInitAuth: false
|
|
2483
|
+
// Don't auto-detect from localStorage in backend
|
|
2484
|
+
});
|
|
2485
|
+
}
|
|
2486
|
+
var createClientFromRequest = createServerClient;
|
|
2487
|
+
|
|
2488
|
+
// src/analytics.ts
|
|
2489
|
+
var STORAGE_KEY = "omnikit_session";
|
|
2490
|
+
var SESSION_TIMEOUT = 30 * 60 * 1e3;
|
|
2491
|
+
var FLUSH_INTERVAL = 5e3;
|
|
2492
|
+
var MAX_RETRIES = 3;
|
|
2493
|
+
var Analytics = class {
|
|
2494
|
+
constructor(config) {
|
|
2495
|
+
this.eventQueue = [];
|
|
2496
|
+
this.config = config;
|
|
2497
|
+
this.enabled = config.enabled !== false;
|
|
2498
|
+
this.sessionId = config.sessionId || this.initSession();
|
|
2499
|
+
this.userId = config.userId;
|
|
2500
|
+
if (this.enabled && typeof window !== "undefined") {
|
|
2501
|
+
this.startFlushTimer();
|
|
2502
|
+
window.addEventListener("beforeunload", () => this.flush());
|
|
2503
|
+
window.addEventListener("pagehide", () => this.flush());
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
// ==========================================================================
|
|
2507
|
+
// Session Management
|
|
2508
|
+
// ==========================================================================
|
|
2509
|
+
initSession() {
|
|
2510
|
+
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
2511
|
+
return this.generateId();
|
|
2512
|
+
}
|
|
2513
|
+
try {
|
|
2514
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
2515
|
+
if (stored) {
|
|
2516
|
+
const { id, timestamp } = JSON.parse(stored);
|
|
2517
|
+
if (Date.now() - timestamp < SESSION_TIMEOUT) {
|
|
2518
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
2519
|
+
id,
|
|
2520
|
+
timestamp: Date.now()
|
|
2521
|
+
}));
|
|
2522
|
+
return id;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
} catch {
|
|
2526
|
+
}
|
|
2527
|
+
const newId = this.generateId();
|
|
2528
|
+
this.saveSession(newId);
|
|
2529
|
+
return newId;
|
|
2530
|
+
}
|
|
2531
|
+
generateId() {
|
|
2532
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
2533
|
+
return crypto.randomUUID();
|
|
2534
|
+
}
|
|
2535
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
2536
|
+
const r = Math.random() * 16 | 0;
|
|
2537
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
2538
|
+
return v.toString(16);
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
saveSession(id) {
|
|
2542
|
+
if (typeof localStorage === "undefined") return;
|
|
2543
|
+
try {
|
|
2544
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
2545
|
+
id,
|
|
2546
|
+
timestamp: Date.now()
|
|
2547
|
+
}));
|
|
2548
|
+
} catch {
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Get the current session ID
|
|
2553
|
+
*/
|
|
2554
|
+
getSessionId() {
|
|
2555
|
+
return this.sessionId;
|
|
2556
|
+
}
|
|
2557
|
+
/**
|
|
2558
|
+
* Start a new session (e.g., after logout)
|
|
2559
|
+
*/
|
|
2560
|
+
startNewSession() {
|
|
2561
|
+
this.sessionId = this.generateId();
|
|
2562
|
+
this.saveSession(this.sessionId);
|
|
2563
|
+
return this.sessionId;
|
|
2564
|
+
}
|
|
2565
|
+
// ==========================================================================
|
|
2566
|
+
// User Identification
|
|
2567
|
+
// ==========================================================================
|
|
2568
|
+
/**
|
|
2569
|
+
* Associate events with a user ID
|
|
2570
|
+
*/
|
|
2571
|
+
setUserId(userId) {
|
|
2572
|
+
this.userId = userId;
|
|
2573
|
+
}
|
|
2574
|
+
/**
|
|
2575
|
+
* Clear user association (e.g., on logout)
|
|
2576
|
+
*/
|
|
2577
|
+
clearUserId() {
|
|
2578
|
+
this.userId = void 0;
|
|
2579
|
+
}
|
|
2580
|
+
// ==========================================================================
|
|
2581
|
+
// Core Logging Methods
|
|
2582
|
+
// ==========================================================================
|
|
2583
|
+
/**
|
|
2584
|
+
* Log a custom event
|
|
2585
|
+
*/
|
|
2586
|
+
async logEvent(eventType, payload = {}) {
|
|
2587
|
+
if (!this.enabled) return;
|
|
2588
|
+
this.eventQueue.push({
|
|
2589
|
+
eventType,
|
|
2590
|
+
payload,
|
|
2591
|
+
timestamp: Date.now()
|
|
2592
|
+
});
|
|
2593
|
+
if (eventType === "error" || eventType === "api_error") {
|
|
2594
|
+
await this.flush();
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
/**
|
|
2598
|
+
* Log a page view event
|
|
2599
|
+
*/
|
|
2600
|
+
async logPageView(pageName, metadata) {
|
|
2601
|
+
if (!this.enabled) return;
|
|
2602
|
+
const url = typeof window !== "undefined" ? window.location.href : "";
|
|
2603
|
+
const referrer = typeof document !== "undefined" ? document.referrer : "";
|
|
2604
|
+
await this.logEvent("page_view", {
|
|
2605
|
+
page_name: pageName,
|
|
2606
|
+
metadata: {
|
|
2607
|
+
url,
|
|
2608
|
+
referrer,
|
|
2609
|
+
...metadata
|
|
2610
|
+
}
|
|
2611
|
+
});
|
|
2612
|
+
}
|
|
2613
|
+
/**
|
|
2614
|
+
* Log an error event
|
|
2615
|
+
*/
|
|
2616
|
+
async logError(error, componentStack) {
|
|
2617
|
+
if (!this.enabled) return;
|
|
2618
|
+
const url = typeof window !== "undefined" ? window.location.href : "";
|
|
2619
|
+
await this.logEvent("error", {
|
|
2620
|
+
error_message: error.message,
|
|
2621
|
+
error_stack: error.stack,
|
|
2622
|
+
metadata: {
|
|
2623
|
+
name: error.name,
|
|
2624
|
+
component_stack: componentStack,
|
|
2625
|
+
url
|
|
2626
|
+
}
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Log an API error event
|
|
2631
|
+
*/
|
|
2632
|
+
async logApiError(endpoint, statusCode, errorMessage, metadata) {
|
|
2633
|
+
if (!this.enabled) return;
|
|
2634
|
+
await this.logEvent("api_error", {
|
|
2635
|
+
error_message: errorMessage,
|
|
2636
|
+
metadata: {
|
|
2637
|
+
endpoint,
|
|
2638
|
+
status_code: statusCode,
|
|
2639
|
+
...metadata
|
|
2640
|
+
}
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
// ==========================================================================
|
|
2644
|
+
// Event Batching & Flushing
|
|
2645
|
+
// ==========================================================================
|
|
2646
|
+
startFlushTimer() {
|
|
2647
|
+
if (this.flushTimer) return;
|
|
2648
|
+
this.flushTimer = setInterval(() => {
|
|
2649
|
+
if (this.eventQueue.length > 0) {
|
|
2650
|
+
this.flush();
|
|
2651
|
+
}
|
|
2652
|
+
}, FLUSH_INTERVAL);
|
|
2653
|
+
}
|
|
2654
|
+
/**
|
|
2655
|
+
* Flush all queued events to the server
|
|
2656
|
+
*/
|
|
2657
|
+
async flush() {
|
|
2658
|
+
if (this.eventQueue.length === 0) return;
|
|
2659
|
+
const events = [...this.eventQueue];
|
|
2660
|
+
this.eventQueue = [];
|
|
2661
|
+
const sendPromises = events.map(
|
|
2662
|
+
({ eventType, payload }) => this.sendEvent(eventType, payload)
|
|
2663
|
+
);
|
|
2664
|
+
await Promise.allSettled(sendPromises);
|
|
2665
|
+
}
|
|
2666
|
+
async sendEvent(eventType, payload) {
|
|
2667
|
+
const pageName = payload.page_name || (typeof window !== "undefined" ? window.location.pathname : "/");
|
|
2668
|
+
const url = `${this.config.apiUrl}/api/app-logs/${this.config.appId}/log-event`;
|
|
2669
|
+
const body = {
|
|
2670
|
+
session_id: this.sessionId,
|
|
2671
|
+
user_id: this.userId,
|
|
2672
|
+
event_type: eventType,
|
|
2673
|
+
page_name: pageName,
|
|
2674
|
+
action: payload.action,
|
|
2675
|
+
inputs: payload.inputs,
|
|
2676
|
+
metadata: payload.metadata,
|
|
2677
|
+
is_error: eventType === "error" || eventType === "api_error",
|
|
2678
|
+
error_message: payload.error_message,
|
|
2679
|
+
error_stack: payload.error_stack
|
|
2680
|
+
};
|
|
2681
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
2682
|
+
try {
|
|
2683
|
+
const response = await fetch(url, {
|
|
2684
|
+
method: "POST",
|
|
2685
|
+
headers: { "Content-Type": "application/json" },
|
|
2686
|
+
body: JSON.stringify(body),
|
|
2687
|
+
keepalive: true
|
|
2688
|
+
// Ensures request completes even on page unload
|
|
2689
|
+
});
|
|
2690
|
+
if (response.ok) {
|
|
2691
|
+
return;
|
|
2692
|
+
}
|
|
2693
|
+
if (response.status >= 400 && response.status < 500) {
|
|
2694
|
+
console.warn(`[Omnikit Analytics] Event rejected: ${response.status}`);
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
} catch (err) {
|
|
2698
|
+
}
|
|
2699
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
2700
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3));
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
console.warn("[Omnikit Analytics] Failed to send event after retries");
|
|
2704
|
+
}
|
|
2705
|
+
// ==========================================================================
|
|
2706
|
+
// Lifecycle
|
|
2707
|
+
// ==========================================================================
|
|
2708
|
+
/**
|
|
2709
|
+
* Enable or disable analytics
|
|
2710
|
+
*/
|
|
2711
|
+
setEnabled(enabled) {
|
|
2712
|
+
this.enabled = enabled;
|
|
2713
|
+
if (enabled && typeof window !== "undefined") {
|
|
2714
|
+
this.startFlushTimer();
|
|
2715
|
+
} else if (this.flushTimer) {
|
|
2716
|
+
clearInterval(this.flushTimer);
|
|
2717
|
+
this.flushTimer = void 0;
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
/**
|
|
2721
|
+
* Check if analytics is enabled
|
|
2722
|
+
*/
|
|
2723
|
+
isEnabled() {
|
|
2724
|
+
return this.enabled;
|
|
2725
|
+
}
|
|
2726
|
+
/**
|
|
2727
|
+
* Clean up resources
|
|
2728
|
+
*/
|
|
2729
|
+
destroy() {
|
|
2730
|
+
if (this.flushTimer) {
|
|
2731
|
+
clearInterval(this.flushTimer);
|
|
2732
|
+
this.flushTimer = void 0;
|
|
2733
|
+
}
|
|
2734
|
+
this.flush();
|
|
2735
|
+
}
|
|
2736
|
+
};
|
|
2737
|
+
function createAnalytics(config) {
|
|
2738
|
+
return new Analytics(config);
|
|
2739
|
+
}
|
|
2237
2740
|
|
|
2238
|
-
export { APIClient, LiveVoiceSessionImpl, OmnikitError, cleanTokenFromUrl, createClient, getAccessToken, isTokenInUrl, removeAccessToken, saveAccessToken, setAccessToken };
|
|
2741
|
+
export { APIClient, Analytics, LiveVoiceSessionImpl, OmnikitError, cleanTokenFromUrl, createAnalytics, createClient, createClientFromRequest, createServerClient, getAccessToken, isTokenInUrl, removeAccessToken, saveAccessToken, setAccessToken };
|
|
2239
2742
|
//# sourceMappingURL=index.mjs.map
|
|
2240
2743
|
//# sourceMappingURL=index.mjs.map
|