@surbee/cipher 0.1.0 → 0.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.
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Cipher SDK Types
3
+ *
4
+ * Core type definitions for the Cipher response validation system.
5
+ * Implementation details are hidden - the SDK communicates with Surbee's
6
+ * secure validation engine.
7
+ */
8
+ type CipherTier = 1 | 2 | 3 | 4 | 5;
9
+ type CheckId = 'rapid_completion' | 'uniform_timing' | 'low_interaction' | 'straight_line_answers' | 'impossibly_fast' | 'minimal_effort' | 'excessive_paste' | 'pointer_spikes' | 'webdriver_detected' | 'automation_detected' | 'no_plugins' | 'suspicious_user_agent' | 'device_fingerprint_mismatch' | 'screen_anomaly' | 'suspicious_pauses' | 'robotic_typing' | 'mouse_teleporting' | 'no_corrections' | 'excessive_tab_switching' | 'window_focus_loss' | 'ai_content_basic' | 'contradiction_basic' | 'hover_behavior' | 'scroll_patterns' | 'mouse_acceleration' | 'vpn_detection' | 'datacenter_ip' | 'plagiarism_basic' | 'quality_assessment' | 'semantic_analysis' | 'ai_content_full' | 'contradiction_full' | 'plagiarism_full' | 'fraud_ring_detection' | 'answer_sharing' | 'coordinated_timing' | 'device_sharing' | 'tor_detection' | 'proxy_detection' | 'timezone_validation' | 'baseline_deviation' | 'perplexity_analysis' | 'burstiness_analysis';
10
+ interface CheckResult {
11
+ /** The check that was run */
12
+ checkId: CheckId;
13
+ /** Whether the check passed */
14
+ passed: boolean;
15
+ /** Suspicion score (0-1, higher = more suspicious) */
16
+ score: number;
17
+ /** Human-readable details */
18
+ details?: string;
19
+ /** Structured diagnostic data behind the score (shape varies per check) */
20
+ data?: Record<string, unknown>;
21
+ }
22
+ interface ResponseInput {
23
+ /** The question text */
24
+ question: string;
25
+ /** The user's answer */
26
+ answer: string;
27
+ /** Question type for context */
28
+ questionType?: 'text' | 'multiple_choice' | 'rating' | 'scale' | 'boolean';
29
+ /** Time spent on this question in milliseconds */
30
+ responseTimeMs?: number;
31
+ /** Question index in the survey */
32
+ questionIndex?: number;
33
+ }
34
+ interface ValidationInput {
35
+ /** Array of question/answer pairs */
36
+ responses: ResponseInput[];
37
+ /** Behavioral metrics from client-side tracking */
38
+ behavioralMetrics?: BehavioralMetrics;
39
+ /** Device/browser information */
40
+ deviceInfo?: DeviceInfo;
41
+ /** Survey context */
42
+ context?: SurveyContext;
43
+ }
44
+ interface SurveyContext {
45
+ /** Survey ID for cross-respondent analysis */
46
+ surveyId?: string;
47
+ /** Expected completion time in seconds */
48
+ expectedDurationSeconds?: number;
49
+ /** Actual completion time in seconds */
50
+ actualDurationSeconds?: number;
51
+ /** Survey type for context-aware analysis */
52
+ surveyType?: 'nps' | 'csat' | 'research' | 'feedback' | 'quiz';
53
+ /** Total number of questions */
54
+ totalQuestions?: number;
55
+ }
56
+ interface BehavioralMetrics {
57
+ sessionId: string;
58
+ startedAt: number;
59
+ duration: number;
60
+ lastActiveAt: number;
61
+ mouseMovements: MouseMovement[];
62
+ mouseClicks: MouseClick[];
63
+ mouseMovementCount: number;
64
+ avgMouseVelocity: number;
65
+ keystrokeDynamics: KeystrokeEvent[];
66
+ keypressCount: number;
67
+ backspaceCount: number;
68
+ avgKeystrokeDwell: number;
69
+ keystrokeVariance: number;
70
+ scrollEvents: ScrollEvent[];
71
+ scrollEventCount: number;
72
+ focusEvents: FocusEvent[];
73
+ tabSwitchCount: number;
74
+ totalBlurDuration: number;
75
+ pasteEvents: number;
76
+ copyEvents: number;
77
+ hoverEvents: HoverEvent[];
78
+ responseTime: number[];
79
+ questionStartTimes: Record<string, number>;
80
+ }
81
+ interface MouseMovement {
82
+ x: number;
83
+ y: number;
84
+ t: number;
85
+ velocity: number;
86
+ }
87
+ interface MouseClick {
88
+ x: number;
89
+ y: number;
90
+ t: number;
91
+ hadHover: boolean;
92
+ }
93
+ interface KeystrokeEvent {
94
+ key: string;
95
+ downAt: number;
96
+ upAt: number;
97
+ dwell: number;
98
+ flightTime: number;
99
+ }
100
+ interface ScrollEvent {
101
+ y: number;
102
+ t: number;
103
+ velocity: number;
104
+ }
105
+ interface FocusEvent {
106
+ type: 'focus' | 'blur' | 'hidden' | 'visible';
107
+ t: number;
108
+ }
109
+ interface HoverEvent {
110
+ element: string;
111
+ duration: number;
112
+ t: number;
113
+ }
114
+ interface DeviceInfo {
115
+ userAgent: string;
116
+ platform: string;
117
+ language: string;
118
+ languages: string[];
119
+ timezone: string;
120
+ timezoneOffset: number;
121
+ screenWidth: number;
122
+ screenHeight: number;
123
+ screenAvailWidth: number;
124
+ screenAvailHeight: number;
125
+ colorDepth: number;
126
+ pixelRatio: number;
127
+ touchSupport: boolean;
128
+ maxTouchPoints: number;
129
+ hardwareConcurrency: number;
130
+ deviceMemory: number;
131
+ cookiesEnabled: boolean;
132
+ webDriver: boolean;
133
+ automationDetected: boolean;
134
+ canvasFingerprint: string | null;
135
+ webglVendor: string | null;
136
+ webglRenderer: string | null;
137
+ pluginCount: number;
138
+ collectedAt: number;
139
+ }
140
+ interface ValidationResult {
141
+ /** Overall quality score (0-1, higher = better quality) */
142
+ score: number;
143
+ /** Whether the response passed validation */
144
+ passed: boolean;
145
+ /** Recommendation for the response */
146
+ recommendation: 'keep' | 'review' | 'discard';
147
+ /** Confidence in the assessment (0-1) */
148
+ confidence: number;
149
+ /** Flags that were triggered */
150
+ flags: string[];
151
+ /** Human-readable summary analysis */
152
+ summary: ValidationSummary;
153
+ /** Detailed check results */
154
+ checks: CheckResult[];
155
+ /** Processing metadata */
156
+ meta: ValidationMeta;
157
+ }
158
+ interface ValidationSummary {
159
+ /** Short verdict (e.g., "Likely legitimate", "Suspected bot") */
160
+ verdict: string;
161
+ /** List of issues found */
162
+ issues: string[];
163
+ /** List of positive signals */
164
+ positives: string[];
165
+ /** Actionable suggestion for the user */
166
+ suggestion: string;
167
+ }
168
+ interface ValidationMeta {
169
+ /** Tier used for validation */
170
+ tier: CipherTier;
171
+ /** Processing time in milliseconds */
172
+ processingTimeMs: number;
173
+ /** Number of checks run */
174
+ checksRun: number;
175
+ /** Number of checks passed */
176
+ checksPassed: number;
177
+ /** Request ID for support */
178
+ requestId: string;
179
+ /** Timestamp */
180
+ timestamp: number;
181
+ }
182
+ interface CipherConfig {
183
+ /**
184
+ * API key from Surbee dashboard (Settings > API Keys)
185
+ * Format: cipher_sk_...
186
+ *
187
+ * Optional only when `offline: true` — tier 1–2 checks run locally with no
188
+ * key. Online validation (tiers 3–5 / `validate()`) always requires a key.
189
+ */
190
+ apiKey?: string;
191
+ /**
192
+ * Validation tier (1-5)
193
+ * - Tier 1-2: Basic checks (~free)
194
+ * - Tier 3: Enhanced analysis
195
+ * - Tier 4: Advanced validation
196
+ * - Tier 5: Maximum accuracy
197
+ */
198
+ tier?: CipherTier;
199
+ /** Custom thresholds */
200
+ thresholds?: {
201
+ /** Score below this = fail (default: 0.4) */
202
+ fail?: number;
203
+ /** Score below this = review (default: 0.7) */
204
+ review?: number;
205
+ };
206
+ /** Enable debug logging */
207
+ debug?: boolean;
208
+ /**
209
+ * Run validation entirely on-device with no API calls. Only the offline
210
+ * checks for the selected tier are evaluated (AI-powered checks are skipped).
211
+ * Recommended for tiers 1–2, which are fully offline.
212
+ */
213
+ offline?: boolean;
214
+ /** Custom API endpoint (for enterprise/self-hosted) */
215
+ endpoint?: string;
216
+ }
217
+ interface BatchValidationInput {
218
+ submissions: ValidationInput[];
219
+ /** Enable cross-submission fraud detection (tier 5) */
220
+ crossAnalysis?: boolean;
221
+ }
222
+ interface BatchValidationResult {
223
+ results: ValidationResult[];
224
+ summary: {
225
+ total: number;
226
+ passed: number;
227
+ review: number;
228
+ failed: number;
229
+ avgScore: number;
230
+ };
231
+ /** Cross-submission fraud indicators (tier 5 only) */
232
+ fraudIndicators?: FraudIndicators;
233
+ }
234
+ interface FraudIndicators {
235
+ /** Response IDs with duplicate answers */
236
+ duplicateAnswers: string[];
237
+ /** Whether coordinated timing was detected */
238
+ coordinatedTiming: boolean;
239
+ /** Whether device sharing was detected */
240
+ deviceSharing: boolean;
241
+ /** Fraud ring score (0-1) */
242
+ fraudRingScore: number;
243
+ }
244
+ interface CipherError {
245
+ code: CipherErrorCode;
246
+ message: string;
247
+ details?: Record<string, unknown>;
248
+ }
249
+ type CipherErrorCode = 'INVALID_API_KEY' | 'RATE_LIMITED' | 'INSUFFICIENT_CREDITS' | 'INVALID_INPUT' | 'TIER_NOT_AVAILABLE' | 'SERVER_ERROR' | 'NETWORK_ERROR';
250
+
251
+ export type { BatchValidationInput as B, CipherConfig as C, DeviceInfo as D, FraudIndicators as F, HoverEvent as H, KeystrokeEvent as K, MouseMovement as M, ResponseInput as R, SurveyContext as S, ValidationInput as V, ValidationResult as a, BatchValidationResult as b, CipherTier as c, CheckId as d, BehavioralMetrics as e, ValidationSummary as f, ValidationMeta as g, CheckResult as h, CipherError as i, CipherErrorCode as j, MouseClick as k, ScrollEvent as l, FocusEvent as m };
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Cipher SDK Types
3
+ *
4
+ * Core type definitions for the Cipher response validation system.
5
+ * Implementation details are hidden - the SDK communicates with Surbee's
6
+ * secure validation engine.
7
+ */
8
+ type CipherTier = 1 | 2 | 3 | 4 | 5;
9
+ type CheckId = 'rapid_completion' | 'uniform_timing' | 'low_interaction' | 'straight_line_answers' | 'impossibly_fast' | 'minimal_effort' | 'excessive_paste' | 'pointer_spikes' | 'webdriver_detected' | 'automation_detected' | 'no_plugins' | 'suspicious_user_agent' | 'device_fingerprint_mismatch' | 'screen_anomaly' | 'suspicious_pauses' | 'robotic_typing' | 'mouse_teleporting' | 'no_corrections' | 'excessive_tab_switching' | 'window_focus_loss' | 'ai_content_basic' | 'contradiction_basic' | 'hover_behavior' | 'scroll_patterns' | 'mouse_acceleration' | 'vpn_detection' | 'datacenter_ip' | 'plagiarism_basic' | 'quality_assessment' | 'semantic_analysis' | 'ai_content_full' | 'contradiction_full' | 'plagiarism_full' | 'fraud_ring_detection' | 'answer_sharing' | 'coordinated_timing' | 'device_sharing' | 'tor_detection' | 'proxy_detection' | 'timezone_validation' | 'baseline_deviation' | 'perplexity_analysis' | 'burstiness_analysis';
10
+ interface CheckResult {
11
+ /** The check that was run */
12
+ checkId: CheckId;
13
+ /** Whether the check passed */
14
+ passed: boolean;
15
+ /** Suspicion score (0-1, higher = more suspicious) */
16
+ score: number;
17
+ /** Human-readable details */
18
+ details?: string;
19
+ /** Structured diagnostic data behind the score (shape varies per check) */
20
+ data?: Record<string, unknown>;
21
+ }
22
+ interface ResponseInput {
23
+ /** The question text */
24
+ question: string;
25
+ /** The user's answer */
26
+ answer: string;
27
+ /** Question type for context */
28
+ questionType?: 'text' | 'multiple_choice' | 'rating' | 'scale' | 'boolean';
29
+ /** Time spent on this question in milliseconds */
30
+ responseTimeMs?: number;
31
+ /** Question index in the survey */
32
+ questionIndex?: number;
33
+ }
34
+ interface ValidationInput {
35
+ /** Array of question/answer pairs */
36
+ responses: ResponseInput[];
37
+ /** Behavioral metrics from client-side tracking */
38
+ behavioralMetrics?: BehavioralMetrics;
39
+ /** Device/browser information */
40
+ deviceInfo?: DeviceInfo;
41
+ /** Survey context */
42
+ context?: SurveyContext;
43
+ }
44
+ interface SurveyContext {
45
+ /** Survey ID for cross-respondent analysis */
46
+ surveyId?: string;
47
+ /** Expected completion time in seconds */
48
+ expectedDurationSeconds?: number;
49
+ /** Actual completion time in seconds */
50
+ actualDurationSeconds?: number;
51
+ /** Survey type for context-aware analysis */
52
+ surveyType?: 'nps' | 'csat' | 'research' | 'feedback' | 'quiz';
53
+ /** Total number of questions */
54
+ totalQuestions?: number;
55
+ }
56
+ interface BehavioralMetrics {
57
+ sessionId: string;
58
+ startedAt: number;
59
+ duration: number;
60
+ lastActiveAt: number;
61
+ mouseMovements: MouseMovement[];
62
+ mouseClicks: MouseClick[];
63
+ mouseMovementCount: number;
64
+ avgMouseVelocity: number;
65
+ keystrokeDynamics: KeystrokeEvent[];
66
+ keypressCount: number;
67
+ backspaceCount: number;
68
+ avgKeystrokeDwell: number;
69
+ keystrokeVariance: number;
70
+ scrollEvents: ScrollEvent[];
71
+ scrollEventCount: number;
72
+ focusEvents: FocusEvent[];
73
+ tabSwitchCount: number;
74
+ totalBlurDuration: number;
75
+ pasteEvents: number;
76
+ copyEvents: number;
77
+ hoverEvents: HoverEvent[];
78
+ responseTime: number[];
79
+ questionStartTimes: Record<string, number>;
80
+ }
81
+ interface MouseMovement {
82
+ x: number;
83
+ y: number;
84
+ t: number;
85
+ velocity: number;
86
+ }
87
+ interface MouseClick {
88
+ x: number;
89
+ y: number;
90
+ t: number;
91
+ hadHover: boolean;
92
+ }
93
+ interface KeystrokeEvent {
94
+ key: string;
95
+ downAt: number;
96
+ upAt: number;
97
+ dwell: number;
98
+ flightTime: number;
99
+ }
100
+ interface ScrollEvent {
101
+ y: number;
102
+ t: number;
103
+ velocity: number;
104
+ }
105
+ interface FocusEvent {
106
+ type: 'focus' | 'blur' | 'hidden' | 'visible';
107
+ t: number;
108
+ }
109
+ interface HoverEvent {
110
+ element: string;
111
+ duration: number;
112
+ t: number;
113
+ }
114
+ interface DeviceInfo {
115
+ userAgent: string;
116
+ platform: string;
117
+ language: string;
118
+ languages: string[];
119
+ timezone: string;
120
+ timezoneOffset: number;
121
+ screenWidth: number;
122
+ screenHeight: number;
123
+ screenAvailWidth: number;
124
+ screenAvailHeight: number;
125
+ colorDepth: number;
126
+ pixelRatio: number;
127
+ touchSupport: boolean;
128
+ maxTouchPoints: number;
129
+ hardwareConcurrency: number;
130
+ deviceMemory: number;
131
+ cookiesEnabled: boolean;
132
+ webDriver: boolean;
133
+ automationDetected: boolean;
134
+ canvasFingerprint: string | null;
135
+ webglVendor: string | null;
136
+ webglRenderer: string | null;
137
+ pluginCount: number;
138
+ collectedAt: number;
139
+ }
140
+ interface ValidationResult {
141
+ /** Overall quality score (0-1, higher = better quality) */
142
+ score: number;
143
+ /** Whether the response passed validation */
144
+ passed: boolean;
145
+ /** Recommendation for the response */
146
+ recommendation: 'keep' | 'review' | 'discard';
147
+ /** Confidence in the assessment (0-1) */
148
+ confidence: number;
149
+ /** Flags that were triggered */
150
+ flags: string[];
151
+ /** Human-readable summary analysis */
152
+ summary: ValidationSummary;
153
+ /** Detailed check results */
154
+ checks: CheckResult[];
155
+ /** Processing metadata */
156
+ meta: ValidationMeta;
157
+ }
158
+ interface ValidationSummary {
159
+ /** Short verdict (e.g., "Likely legitimate", "Suspected bot") */
160
+ verdict: string;
161
+ /** List of issues found */
162
+ issues: string[];
163
+ /** List of positive signals */
164
+ positives: string[];
165
+ /** Actionable suggestion for the user */
166
+ suggestion: string;
167
+ }
168
+ interface ValidationMeta {
169
+ /** Tier used for validation */
170
+ tier: CipherTier;
171
+ /** Processing time in milliseconds */
172
+ processingTimeMs: number;
173
+ /** Number of checks run */
174
+ checksRun: number;
175
+ /** Number of checks passed */
176
+ checksPassed: number;
177
+ /** Request ID for support */
178
+ requestId: string;
179
+ /** Timestamp */
180
+ timestamp: number;
181
+ }
182
+ interface CipherConfig {
183
+ /**
184
+ * API key from Surbee dashboard (Settings > API Keys)
185
+ * Format: cipher_sk_...
186
+ *
187
+ * Optional only when `offline: true` — tier 1–2 checks run locally with no
188
+ * key. Online validation (tiers 3–5 / `validate()`) always requires a key.
189
+ */
190
+ apiKey?: string;
191
+ /**
192
+ * Validation tier (1-5)
193
+ * - Tier 1-2: Basic checks (~free)
194
+ * - Tier 3: Enhanced analysis
195
+ * - Tier 4: Advanced validation
196
+ * - Tier 5: Maximum accuracy
197
+ */
198
+ tier?: CipherTier;
199
+ /** Custom thresholds */
200
+ thresholds?: {
201
+ /** Score below this = fail (default: 0.4) */
202
+ fail?: number;
203
+ /** Score below this = review (default: 0.7) */
204
+ review?: number;
205
+ };
206
+ /** Enable debug logging */
207
+ debug?: boolean;
208
+ /**
209
+ * Run validation entirely on-device with no API calls. Only the offline
210
+ * checks for the selected tier are evaluated (AI-powered checks are skipped).
211
+ * Recommended for tiers 1–2, which are fully offline.
212
+ */
213
+ offline?: boolean;
214
+ /** Custom API endpoint (for enterprise/self-hosted) */
215
+ endpoint?: string;
216
+ }
217
+ interface BatchValidationInput {
218
+ submissions: ValidationInput[];
219
+ /** Enable cross-submission fraud detection (tier 5) */
220
+ crossAnalysis?: boolean;
221
+ }
222
+ interface BatchValidationResult {
223
+ results: ValidationResult[];
224
+ summary: {
225
+ total: number;
226
+ passed: number;
227
+ review: number;
228
+ failed: number;
229
+ avgScore: number;
230
+ };
231
+ /** Cross-submission fraud indicators (tier 5 only) */
232
+ fraudIndicators?: FraudIndicators;
233
+ }
234
+ interface FraudIndicators {
235
+ /** Response IDs with duplicate answers */
236
+ duplicateAnswers: string[];
237
+ /** Whether coordinated timing was detected */
238
+ coordinatedTiming: boolean;
239
+ /** Whether device sharing was detected */
240
+ deviceSharing: boolean;
241
+ /** Fraud ring score (0-1) */
242
+ fraudRingScore: number;
243
+ }
244
+ interface CipherError {
245
+ code: CipherErrorCode;
246
+ message: string;
247
+ details?: Record<string, unknown>;
248
+ }
249
+ type CipherErrorCode = 'INVALID_API_KEY' | 'RATE_LIMITED' | 'INSUFFICIENT_CREDITS' | 'INVALID_INPUT' | 'TIER_NOT_AVAILABLE' | 'SERVER_ERROR' | 'NETWORK_ERROR';
250
+
251
+ export type { BatchValidationInput as B, CipherConfig as C, DeviceInfo as D, FraudIndicators as F, HoverEvent as H, KeystrokeEvent as K, MouseMovement as M, ResponseInput as R, SurveyContext as S, ValidationInput as V, ValidationResult as a, BatchValidationResult as b, CipherTier as c, CheckId as d, BehavioralMetrics as e, ValidationSummary as f, ValidationMeta as g, CheckResult as h, CipherError as i, CipherErrorCode as j, MouseClick as k, ScrollEvent as l, FocusEvent as m };
package/package.json CHANGED
@@ -1,22 +1,33 @@
1
1
  {
2
2
  "name": "@surbee/cipher",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "AI-powered survey response validation - detect fraud, bots, and low-quality responses",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "sideEffects": false,
8
12
  "exports": {
9
13
  ".": {
10
14
  "types": "./dist/index.d.ts",
11
15
  "import": "./dist/index.mjs",
12
16
  "require": "./dist/index.js"
17
+ },
18
+ "./checks": {
19
+ "types": "./dist/checks/index.d.ts",
20
+ "import": "./dist/checks/index.mjs",
21
+ "require": "./dist/checks/index.js"
13
22
  }
14
23
  },
15
24
  "scripts": {
16
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
17
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
25
+ "build": "tsup src/index.ts src/checks/index.ts --format cjs,esm --dts --clean",
26
+ "dev": "tsup src/index.ts src/checks/index.ts --format cjs,esm --dts --watch",
18
27
  "lint": "eslint src/",
19
- "typecheck": "tsc --noEmit"
28
+ "typecheck": "tsc --noEmit",
29
+ "test": "tsx --test test/*.test.ts",
30
+ "prepublishOnly": "npm run build"
20
31
  },
21
32
  "keywords": [
22
33
  "survey",
@@ -37,6 +48,7 @@
37
48
  "devDependencies": {
38
49
  "@types/node": "^20.0.0",
39
50
  "tsup": "^8.0.0",
51
+ "tsx": "^4.21.0",
40
52
  "typescript": "^5.0.0"
41
53
  },
42
54
  "engines": {