@kreltix/liveness-sdk 0.1.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/README.md ADDED
@@ -0,0 +1,425 @@
1
+ # @kreltix/liveness-sdk
2
+
3
+ Liveness detection SDK for web and React Native applications. Verifies that a real person is present by guiding them through randomized face challenges (head turns, blinks, smiles) with an interactive camera overlay.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @kreltix/liveness-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { KreltixSDK } from "@kreltix/liveness-sdk";
15
+
16
+ const sdk = KreltixSDK.initialize("pk_live_your_public_key");
17
+
18
+ const result = await sdk.startLivenessCheck();
19
+
20
+ if (result.isLive) {
21
+ console.log("Verified!", result.confidence);
22
+ } else {
23
+ console.log("Failed:", result.recommendation);
24
+ }
25
+ ```
26
+
27
+ That's it. The SDK handles the entire flow: opens the camera, shows animated guides for each challenge, records video, submits to the server, and returns the result.
28
+
29
+ ## Getting Your Keys
30
+
31
+ 1. Log in to the [Kreltix Dashboard](https://kreltix.com)
32
+ 2. Go to **API Keys** > **Generate New Key**
33
+ 3. Select **SDK Key Pair**
34
+ 4. Copy both keys:
35
+ - `pk_live_...` (public key) — safe to use in frontend/mobile apps
36
+ - `sk_live_...` (secret key) — server-side only, never expose to clients
37
+
38
+ ## How It Works
39
+
40
+ ```
41
+ Your App SDK Kreltix API
42
+ ──────── ─── ───────────
43
+
44
+ startLivenessCheck()
45
+ → Create session ← Server picks challenges
46
+ (e.g. turn_right → turn_left)
47
+
48
+ → Open camera
49
+ → Show animated guide Step 1: "Turn right"
50
+ → Record 3-7s video
51
+ Step 2: "Turn left"
52
+ → Show animated guide
53
+ → Record 3-7s video
54
+
55
+ → Upload & verify ← Server analyzes frames:
56
+ Show processing animation challenge detection,
57
+ anti-spoof checks,
58
+ 3D depth estimation
59
+
60
+ → Show result animation ← { isLive, confidence }
61
+ ← result returned
62
+ ```
63
+
64
+ ## API Reference
65
+
66
+ ### `KreltixSDK.initialize(publicKey, options?)`
67
+
68
+ Creates a new SDK instance.
69
+
70
+ ```typescript
71
+ const sdk = KreltixSDK.initialize("pk_live_...", {
72
+ baseUrl: "https://api.kreltix.com", // default
73
+ timeout: 10000, // ms, default 10s
74
+ maxRetries: 2, // default 2
75
+ });
76
+ ```
77
+
78
+ | Parameter | Type | Description |
79
+ |---|---|---|
80
+ | `publicKey` | `string` | Your `pk_live_` public key (required) |
81
+ | `options.baseUrl` | `string` | API base URL. Override for self-hosted deployments |
82
+ | `options.timeout` | `number` | Request timeout in ms (default: 10000) |
83
+ | `options.maxRetries` | `number` | Retry count for failed requests (default: 2) |
84
+
85
+ ### `sdk.startLivenessCheck(options?)`
86
+
87
+ Runs the full liveness verification flow. Returns a promise that resolves with the result.
88
+
89
+ ```typescript
90
+ const result = await sdk.startLivenessCheck({
91
+ // Mount inside a specific element (default: fullscreen overlay)
92
+ container: document.getElementById("my-container"),
93
+
94
+ // Show built-in UI overlay (default: true)
95
+ showOverlay: true,
96
+
97
+ // Attach metadata to the session (passed through to webhooks)
98
+ metadata: { userId: "user_123", flow: "onboarding" },
99
+
100
+ // Callbacks
101
+ onSessionCreated: (session) => {
102
+ console.log("Challenges:", session.challenges);
103
+ },
104
+ onChallengeStarted: (challenge) => {
105
+ console.log("Now doing:", challenge);
106
+ },
107
+ onProgress: (event) => {
108
+ console.log(event.stage, event.message);
109
+ },
110
+ onError: (error) => {
111
+ console.error("SDK error:", error.message);
112
+ },
113
+ });
114
+ ```
115
+
116
+ #### Options
117
+
118
+ | Option | Type | Default | Description |
119
+ |---|---|---|---|
120
+ | `container` | `HTMLElement` | `document.body` | Element to mount the camera UI into |
121
+ | `showOverlay` | `boolean` | `true` | Show the built-in challenge overlay UI |
122
+ | `metadata` | `object` | — | Custom metadata attached to the session |
123
+ | `cameraAdapter` | `CameraAdapter` | — | Custom camera adapter (for React Native) |
124
+ | `onSessionCreated` | `function` | — | Called when the server creates the session |
125
+ | `onChallengeStarted` | `function` | — | Called when each challenge step begins |
126
+ | `onProgress` | `function` | — | Called with progress updates throughout the flow |
127
+ | `onError` | `function` | — | Called on any error |
128
+
129
+ #### Result: `LivenessResult`
130
+
131
+ ```typescript
132
+ {
133
+ sessionId: string; // Unique session identifier
134
+ isLive: boolean; // true if all checks passed
135
+ confidence: number; // 0-100 confidence score
136
+ allChallengesPassed: boolean;
137
+ challengeResults: [ // Per-step results
138
+ { challenge: "turn_right", completed: true, indicators: {...} },
139
+ { challenge: "turn_left", completed: true, indicators: {...} },
140
+ ];
141
+ recommendation: string; // Human-readable result message
142
+ error: string | null; // Error message if something failed
143
+ indicators: object | null; // Detailed analysis indicators
144
+ }
145
+ ```
146
+
147
+ #### Progress Stages
148
+
149
+ The `onProgress` callback receives events with these stages:
150
+
151
+ | Stage | When |
152
+ |---|---|
153
+ | `session_created` | Server session created, challenges assigned |
154
+ | `camera_ready` | Camera stream active |
155
+ | `recording` | Recording a challenge step |
156
+ | `uploading` | Submitting videos to server |
157
+ | `complete` | Result received |
158
+
159
+ ## Examples
160
+
161
+ ### Basic — Fullscreen Overlay
162
+
163
+ ```typescript
164
+ import { KreltixSDK } from "@kreltix/liveness-sdk";
165
+
166
+ const sdk = KreltixSDK.initialize("pk_live_...");
167
+
168
+ document.getElementById("verify-btn").addEventListener("click", async () => {
169
+ try {
170
+ const result = await sdk.startLivenessCheck();
171
+
172
+ if (result.isLive) {
173
+ showSuccess(`Verified with ${result.confidence}% confidence`);
174
+ } else {
175
+ showError(result.recommendation);
176
+ }
177
+ } catch (err) {
178
+ if (err.code === "CAMERA_ERROR") {
179
+ showError("Please allow camera access to continue.");
180
+ } else {
181
+ showError("Verification failed. Please try again.");
182
+ }
183
+ }
184
+ });
185
+ ```
186
+
187
+ ### Embedded in a Container
188
+
189
+ ```html
190
+ <div id="liveness-container" style="width: 400px; height: 600px;"></div>
191
+ ```
192
+
193
+ ```typescript
194
+ const result = await sdk.startLivenessCheck({
195
+ container: document.getElementById("liveness-container"),
196
+ });
197
+ ```
198
+
199
+ ### With Metadata for Webhooks
200
+
201
+ ```typescript
202
+ const result = await sdk.startLivenessCheck({
203
+ metadata: {
204
+ userId: "user_abc123",
205
+ flow: "kyc_onboarding",
206
+ tier: "premium",
207
+ },
208
+ });
209
+
210
+ // The metadata is included in webhook payloads sent to your server
211
+ ```
212
+
213
+ ### Full Progress Tracking
214
+
215
+ ```typescript
216
+ const result = await sdk.startLivenessCheck({
217
+ onSessionCreated: (session) => {
218
+ console.log("Session:", session.session_id);
219
+ console.log("Challenges:", session.challenges.join(" → "));
220
+ // e.g. ["turn_right", "turn_left"]
221
+ },
222
+
223
+ onChallengeStarted: (challenge) => {
224
+ analytics.track("liveness_challenge_started", { challenge });
225
+ },
226
+
227
+ onProgress: ({ stage, message }) => {
228
+ updateStatusBar(stage, message);
229
+ },
230
+
231
+ onError: (error) => {
232
+ errorReporting.capture(error);
233
+ },
234
+ });
235
+ ```
236
+
237
+ ### React Component
238
+
239
+ ```tsx
240
+ import { useState } from "react";
241
+ import { KreltixSDK, LivenessResult, KreltixError } from "@kreltix/liveness-sdk";
242
+
243
+ const sdk = KreltixSDK.initialize("pk_live_...");
244
+
245
+ function LivenessButton() {
246
+ const [status, setStatus] = useState<"idle" | "running" | "passed" | "failed">("idle");
247
+
248
+ const handleVerify = async () => {
249
+ setStatus("running");
250
+ try {
251
+ const result = await sdk.startLivenessCheck({
252
+ metadata: { component: "onboarding" },
253
+ });
254
+ setStatus(result.isLive ? "passed" : "failed");
255
+ } catch (err) {
256
+ setStatus("failed");
257
+ }
258
+ };
259
+
260
+ return (
261
+ <button onClick={handleVerify} disabled={status === "running"}>
262
+ {status === "running" ? "Verifying..." : "Verify Identity"}
263
+ </button>
264
+ );
265
+ }
266
+ ```
267
+
268
+ ### React Native
269
+
270
+ The SDK supports React Native via a custom camera adapter. You provide the camera implementation, the SDK handles the rest.
271
+
272
+ ```typescript
273
+ import { KreltixSDK, CameraAdapter } from "@kreltix/liveness-sdk";
274
+ import { Camera } from "expo-camera";
275
+
276
+ class ExpoCameraAdapter implements CameraAdapter {
277
+ private camera: Camera | null = null;
278
+ private videoElement: HTMLVideoElement;
279
+
280
+ constructor() {
281
+ this.videoElement = document.createElement("video");
282
+ }
283
+
284
+ async start(facingMode: "user" | "environment") {
285
+ const { status } = await Camera.requestCameraPermissionsAsync();
286
+ if (status !== "granted") throw new Error("Camera permission denied");
287
+
288
+ // Return the camera stream
289
+ const stream = await navigator.mediaDevices.getUserMedia({
290
+ video: { facingMode },
291
+ });
292
+ return stream;
293
+ }
294
+
295
+ stop() {
296
+ // Clean up camera resources
297
+ }
298
+
299
+ getVideoElement() {
300
+ return this.videoElement;
301
+ }
302
+ }
303
+
304
+ const sdk = KreltixSDK.initialize("pk_live_...");
305
+
306
+ const result = await sdk.startLivenessCheck({
307
+ cameraAdapter: new ExpoCameraAdapter(),
308
+ });
309
+ ```
310
+
311
+ ## Error Handling
312
+
313
+ All errors extend `KreltixError` with a `code` property and `isRetryable` flag.
314
+
315
+ ```typescript
316
+ import {
317
+ KreltixError,
318
+ KreltixCameraError,
319
+ KreltixAuthError,
320
+ KreltixInsufficientFundsError,
321
+ } from "@kreltix/liveness-sdk";
322
+
323
+ try {
324
+ const result = await sdk.startLivenessCheck();
325
+ } catch (err) {
326
+ if (err instanceof KreltixCameraError) {
327
+ // User denied camera permission or no camera available
328
+ showMessage("Camera access is required for verification.");
329
+ } else if (err instanceof KreltixAuthError) {
330
+ // Invalid or expired API key
331
+ showMessage("Configuration error. Contact support.");
332
+ } else if (err instanceof KreltixInsufficientFundsError) {
333
+ // Account balance too low
334
+ showMessage("Service temporarily unavailable.");
335
+ } else if (err instanceof KreltixError && err.isRetryable) {
336
+ // Network/server error — safe to retry
337
+ showMessage("Connection issue. Please try again.");
338
+ } else {
339
+ showMessage("Verification failed. Please try again.");
340
+ }
341
+ }
342
+ ```
343
+
344
+ ### Error Types
345
+
346
+ | Error | Code | Retryable | Cause |
347
+ |---|---|---|---|
348
+ | `KreltixCameraError` | `CAMERA_ERROR` | No | Camera permission denied or not available |
349
+ | `KreltixAuthError` | `AUTH_ERROR` | No | Invalid or expired public key |
350
+ | `KreltixInsufficientFundsError` | `INSUFFICIENT_FUNDS` | No | Account wallet balance too low |
351
+ | `KreltixSessionExpiredError` | `SESSION_EXPIRED` | No | Verification session timed out (5 min) |
352
+ | `KreltixValidationError` | `VALIDATION_ERROR` | No | Invalid request (e.g. session already used) |
353
+ | `KreltixNetworkError` | `NETWORK_ERROR` | Yes | Network failure or request timeout |
354
+ | `KreltixServerError` | `SERVER_ERROR` | Yes | Server-side error (5xx) |
355
+
356
+ ## Security Model
357
+
358
+ ### Public Key (`pk_live_`)
359
+
360
+ - Safe to embed in client-side apps (web, mobile)
361
+ - Can only create liveness sessions and submit verifications
362
+ - Cannot access account data, billing, verification history, or any other API
363
+ - Rate limited (30 requests/minute)
364
+
365
+ ### Secret Key (`sk_live_`)
366
+
367
+ - Server-side only — never expose in client code
368
+ - Full API access: read session results, verification history, account management
369
+ - Use for webhooks, backend integrations, and admin operations
370
+
371
+ ### How Challenges Work
372
+
373
+ 1. The **server** picks a random multi-step challenge sequence (e.g., "turn right" then "turn left")
374
+ 2. Challenges are **unpredictable** — the client cannot know them in advance
375
+ 3. Each session is **single-use** — a session token works exactly once
376
+ 4. Sessions **expire after 5 minutes**
377
+ 5. The server performs the actual liveness analysis (anti-spoof, depth estimation, texture analysis) — on-device detection is only for UX guidance
378
+
379
+ ## Browser Support
380
+
381
+ - Chrome 70+
382
+ - Firefox 65+
383
+ - Safari 14.1+
384
+ - Edge 79+
385
+
386
+ Requires `getUserMedia` and `MediaRecorder` APIs.
387
+
388
+ ## TypeScript
389
+
390
+ The SDK is written in TypeScript and ships with full type definitions. All types are exported:
391
+
392
+ ```typescript
393
+ import type {
394
+ LivenessResult,
395
+ LivenessOptions,
396
+ ProgressEvent,
397
+ ChallengeStepResult,
398
+ CameraAdapter,
399
+ } from "@kreltix/liveness-sdk";
400
+ ```
401
+
402
+ ## Webhooks
403
+
404
+ When a liveness check completes, Kreltix sends a webhook to your server (if configured in the dashboard) with the full result:
405
+
406
+ ```json
407
+ {
408
+ "event": "liveness_session.completed",
409
+ "session_id": "69c9ce0c...",
410
+ "status": "completed",
411
+ "challenges": ["turn_right", "turn_left"],
412
+ "is_live": true,
413
+ "confidence": 99.99,
414
+ "charge_amount": 90.0,
415
+ "metadata": { "userId": "user_123" },
416
+ "timestamp": "2026-03-30T06:12:44.000Z"
417
+ }
418
+ ```
419
+
420
+ Webhook payloads are signed with HMAC-SHA256. Verify the signature using your webhook secret from the dashboard.
421
+
422
+ ## Support
423
+
424
+ - Dashboard: [https://kreltix.com](https://kreltix.com)
425
+ - API Docs: [https://api.kreltix.com/docs](https://api.kreltix.com/docs)
@@ -0,0 +1,9 @@
1
+ import type { SDKOptions, LivenessOptions, LivenessResult } from "./api/types";
2
+ export declare class KreltixSDK {
3
+ private config;
4
+ private apiClient;
5
+ private sessionManager;
6
+ private constructor();
7
+ static initialize(publicKey: string, options?: SDKOptions): KreltixSDK;
8
+ startLivenessCheck(options?: LivenessOptions): Promise<LivenessResult>;
9
+ }
@@ -0,0 +1,8 @@
1
+ import type { SDKConfig, CreateSessionResponse, SubmitVerificationResponse } from "./types";
2
+ export declare class ApiClient {
3
+ private config;
4
+ constructor(config: SDKConfig);
5
+ private request;
6
+ createSession(metadata?: Record<string, unknown>): Promise<CreateSessionResponse>;
7
+ submitVerification(sessionId: string, sessionToken: string, videos: string[]): Promise<SubmitVerificationResponse>;
8
+ }
@@ -0,0 +1,71 @@
1
+ export interface SDKConfig {
2
+ publicKey: string;
3
+ baseUrl: string;
4
+ timeout: number;
5
+ maxRetries: number;
6
+ }
7
+ export interface SDKOptions {
8
+ baseUrl?: string;
9
+ timeout?: number;
10
+ maxRetries?: number;
11
+ }
12
+ export interface LivenessOptions {
13
+ /** Container element to mount the camera UI into. If not provided, creates a fullscreen overlay. */
14
+ container?: HTMLElement;
15
+ /** Whether to show the built-in challenge overlay UI. Default: true */
16
+ showOverlay?: boolean;
17
+ /** Custom metadata to attach to the session */
18
+ metadata?: Record<string, unknown>;
19
+ /** Camera adapter for React Native or custom implementations */
20
+ cameraAdapter?: CameraAdapter;
21
+ /** Called when the session is created */
22
+ onSessionCreated?: (session: CreateSessionResponse) => void;
23
+ /** Called when the challenge starts (camera open, recording begins) */
24
+ onChallengeStarted?: (challenge: string) => void;
25
+ /** Called with progress updates */
26
+ onProgress?: (event: ProgressEvent) => void;
27
+ /** Called on error */
28
+ onError?: (error: Error) => void;
29
+ }
30
+ export interface ProgressEvent {
31
+ stage: "session_created" | "camera_ready" | "recording" | "uploading" | "processing" | "complete";
32
+ message: string;
33
+ }
34
+ export interface CreateSessionResponse {
35
+ session_id: string;
36
+ session_token: string;
37
+ challenges: string[];
38
+ instructions: string[];
39
+ expires_at: string;
40
+ }
41
+ export interface ChallengeStepResult {
42
+ challenge: string;
43
+ completed: boolean;
44
+ indicators: Record<string, unknown> | null;
45
+ }
46
+ export interface SubmitVerificationResponse {
47
+ session_id: string;
48
+ is_live: boolean;
49
+ confidence: number;
50
+ challenges_completed: ChallengeStepResult[];
51
+ all_challenges_passed: boolean;
52
+ indicators: Record<string, unknown> | null;
53
+ recommendation: string | null;
54
+ error: string | null;
55
+ charge_amount: number | null;
56
+ }
57
+ export interface LivenessResult {
58
+ sessionId: string;
59
+ isLive: boolean;
60
+ confidence: number;
61
+ challengeResults: ChallengeStepResult[];
62
+ allChallengesPassed: boolean;
63
+ recommendation: string | null;
64
+ error: string | null;
65
+ indicators: Record<string, unknown> | null;
66
+ }
67
+ export interface CameraAdapter {
68
+ start(facingMode: "user" | "environment"): Promise<MediaStream>;
69
+ stop(): void;
70
+ getVideoElement(): HTMLVideoElement;
71
+ }
@@ -0,0 +1,19 @@
1
+ import type { CameraAdapter } from "../api/types";
2
+ /**
3
+ * Default web camera adapter using getUserMedia.
4
+ */
5
+ export declare class WebCameraAdapter implements CameraAdapter {
6
+ private stream;
7
+ private videoElement;
8
+ constructor();
9
+ start(facingMode?: "user" | "environment"): Promise<MediaStream>;
10
+ stop(): void;
11
+ getVideoElement(): HTMLVideoElement;
12
+ }
13
+ export declare class CameraManager {
14
+ private adapter;
15
+ constructor(adapter?: CameraAdapter);
16
+ start(): Promise<MediaStream>;
17
+ stop(): void;
18
+ getVideoElement(): HTMLVideoElement;
19
+ }
@@ -0,0 +1,34 @@
1
+ export interface RecordingOptions {
2
+ /** Minimum recording duration in ms. Default: 3000 */
3
+ minDurationMs?: number;
4
+ /** Maximum recording duration in ms. Default: 7000 */
5
+ maxDurationMs?: number;
6
+ /** Video bitrate in bps. Default: 1000000 (1 Mbps) */
7
+ videoBitsPerSecond?: number;
8
+ }
9
+ export declare class VideoRecorder {
10
+ private mediaRecorder;
11
+ private chunks;
12
+ private resolveRecording;
13
+ /**
14
+ * Get the best supported MIME type for video recording.
15
+ */
16
+ private getMimeType;
17
+ /**
18
+ * Start recording from a media stream.
19
+ */
20
+ start(stream: MediaStream, options?: RecordingOptions): void;
21
+ /**
22
+ * Stop recording and return the video as a base64 string.
23
+ */
24
+ stop(): Promise<string>;
25
+ /**
26
+ * Record for a duration, then stop and return base64.
27
+ * Can be stopped early via the returned controller.
28
+ */
29
+ record(stream: MediaStream, options?: RecordingOptions): {
30
+ promise: Promise<string>;
31
+ stopEarly: () => void;
32
+ };
33
+ private _pendingStopEarly;
34
+ }
@@ -0,0 +1,44 @@
1
+ export interface FaceLandmarks {
2
+ /** Left eye points [[x,y], ...] */
3
+ leftEye: [number, number][];
4
+ /** Right eye points [[x,y], ...] */
5
+ rightEye: [number, number][];
6
+ /** Nose tip [x, y] */
7
+ noseTip: [number, number];
8
+ /** Face bounding box { x, y, width, height } */
9
+ faceBounds: {
10
+ x: number;
11
+ y: number;
12
+ width: number;
13
+ height: number;
14
+ };
15
+ /** Upper lip points */
16
+ upperLip: [number, number][];
17
+ /** Lower lip points */
18
+ lowerLip: [number, number][];
19
+ }
20
+ export interface DetectionResult {
21
+ /** Whether the challenge appears completed */
22
+ completed: boolean;
23
+ /** 0-1 progress toward completion */
24
+ progress: number;
25
+ /** Human-readable feedback for the user */
26
+ feedback: string;
27
+ }
28
+ /**
29
+ * Lightweight on-device challenge detection for UX guidance.
30
+ * This is NOT a security layer -- the server is the sole authority on liveness.
31
+ */
32
+ export declare class ChallengeDetector {
33
+ private blinkDetector;
34
+ private headTurnDetector;
35
+ private smileDetector;
36
+ /**
37
+ * Process a frame's face landmarks and return detection result for the given challenge.
38
+ */
39
+ detect(challenge: string, landmarks: FaceLandmarks): DetectionResult;
40
+ /**
41
+ * Reset all detectors for a new session.
42
+ */
43
+ reset(): void;
44
+ }
@@ -0,0 +1,7 @@
1
+ import type { FaceLandmarks, DetectionResult } from "../ChallengeDetector";
2
+ export declare class BlinkDetector {
3
+ private earHistory;
4
+ private blinkDetected;
5
+ detect(landmarks: FaceLandmarks): DetectionResult;
6
+ reset(): void;
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { FaceLandmarks, DetectionResult } from "../ChallengeDetector";
2
+ export declare class HeadTurnDetector {
3
+ private noseOffsets;
4
+ private turnDetected;
5
+ detect(landmarks: FaceLandmarks, direction: "left" | "right"): DetectionResult;
6
+ reset(): void;
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { FaceLandmarks, DetectionResult } from "../ChallengeDetector";
2
+ export declare class SmileDetector {
3
+ private aspectHistory;
4
+ private smileDetected;
5
+ detect(landmarks: FaceLandmarks): DetectionResult;
6
+ reset(): void;
7
+ }
@@ -0,0 +1,26 @@
1
+ export declare class KreltixError extends Error {
2
+ code: string;
3
+ isRetryable: boolean;
4
+ constructor(message: string, code: string, isRetryable?: boolean);
5
+ }
6
+ export declare class KreltixNetworkError extends KreltixError {
7
+ constructor(message?: string);
8
+ }
9
+ export declare class KreltixAuthError extends KreltixError {
10
+ constructor(message?: string);
11
+ }
12
+ export declare class KreltixSessionExpiredError extends KreltixError {
13
+ constructor(message?: string);
14
+ }
15
+ export declare class KreltixCameraError extends KreltixError {
16
+ constructor(message?: string);
17
+ }
18
+ export declare class KreltixServerError extends KreltixError {
19
+ constructor(message?: string);
20
+ }
21
+ export declare class KreltixValidationError extends KreltixError {
22
+ constructor(message?: string);
23
+ }
24
+ export declare class KreltixInsufficientFundsError extends KreltixError {
25
+ constructor(message?: string);
26
+ }