@omnikit-ai/sdk 2.0.10 → 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.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
@@ -756,13 +803,13 @@ var APIClient = class {
756
803
  return this.createAuthProxy();
757
804
  }
758
805
  /**
759
- * Lazy getter for service role operations
760
- * Only available when serviceToken is provided
806
+ * Service-level operations (elevated privileges).
807
+ * Only available when serviceToken is provided (e.g., via createServerClient).
761
808
  */
762
- get asServiceRole() {
809
+ get service() {
763
810
  if (!this._serviceToken) {
764
811
  throw new OmnikitError(
765
- "Service token is required to use asServiceRole. Provide serviceToken in config.",
812
+ "Service token is required. Use createServerClient(req) in backend functions.",
766
813
  403,
767
814
  "SERVICE_TOKEN_REQUIRED"
768
815
  );
@@ -775,12 +822,51 @@ var APIClient = class {
775
822
  // Service role collections
776
823
  services: this.createServicesProxy(true),
777
824
  // Service role services (new flat structure)
778
- integrations: this.createIntegrationsProxy(true)
825
+ integrations: this.createIntegrationsProxy(true),
779
826
  // Service role integrations (legacy)
827
+ connectors: this.connectors
828
+ // Connectors module (requires service token)
780
829
  // Note: auth not available in service role for security
781
830
  };
782
831
  return this._asServiceRole;
783
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
+ }
784
870
  /**
785
871
  * Create auth proxy that auto-initializes
786
872
  */
@@ -2234,7 +2320,289 @@ Example: await ${collectionName}.list({ limit: 100, sort: '-created_at' })`,
2234
2320
  function createClient(config) {
2235
2321
  return new APIClient(config);
2236
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
+ }
2237
2605
 
2238
- 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 };
2239
2607
  //# sourceMappingURL=index.mjs.map
2240
2608
  //# sourceMappingURL=index.mjs.map