@truesift/express 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,567 @@
1
+ # TrueSift Express SDK
2
+
3
+ **TrueSift — Next-Gen Human Verification made in Germany**
4
+
5
+ Server-side TypeScript SDK client for the TrueSift human verification API.
6
+
7
+ This package is designed for Node.js and Express backend environments. It can also be used in other server-side Node.js runtimes, as long as secrets remain strictly backend-only.
8
+
9
+ > Status: internal work in progress
10
+ > Version: 0.1.0
11
+ > Runtime: Node.js 20+
12
+ > Module format: ESM
13
+ > Language: TypeScript
14
+
15
+ ---
16
+
17
+ ## Purpose
18
+
19
+ The SDK provides a small, typed, predictable service client for communicating with the TrueSift API.
20
+
21
+ It is intentionally thin.
22
+
23
+ The SDK should help backend projects:
24
+
25
+ - create verification challenges
26
+ - verify submitted challenges
27
+ - normalize TrueSift API responses
28
+ - work with typed decisions
29
+ - handle transport and API errors consistently
30
+ - keep secret credentials out of frontend code
31
+
32
+ ---
33
+
34
+ ## What this SDK is not
35
+
36
+ This SDK is not:
37
+
38
+ - a frontend SDK
39
+ - a React package
40
+ - a Next.js framework adapter
41
+ - a UI package
42
+ - an Express application
43
+ - an Express router
44
+ - a form library
45
+ - a CAPTCHA widget
46
+ - a database abstraction
47
+ - a policy engine
48
+ - an admin dashboard client
49
+
50
+ Project backends remain responsible for their own business logic, request handling, form validation, error responses, telemetry, fail-open/fail-closed behavior, and user-facing messages.
51
+
52
+ ---
53
+
54
+ ## Server-side only
55
+
56
+ This SDK must only be used in backend/server-side code.
57
+
58
+ Do not import this package in:
59
+
60
+ - React client components
61
+ - browser scripts
62
+ - frontend bundles
63
+ - public JavaScript
64
+ - code that exposes secrets through `NEXT_PUBLIC_*` variables
65
+
66
+ The SDK uses a `secretKey`, which must never leave the backend.
67
+
68
+ ---
69
+
70
+ ## Package name
71
+
72
+ Current package identity:
73
+
74
+ ```txt
75
+ @truesift/express
76
+ ```
77
+
78
+ The package is currently marked as private and is not published yet.
79
+
80
+ Possible future distribution options:
81
+
82
+ - public npm package
83
+ - private npm package
84
+ - GitHub Packages
85
+ - internal registry
86
+ - own package server
87
+ - local workspace package
88
+
89
+ The SDK architecture is intentionally independent from the final publishing strategy.
90
+
91
+ ---
92
+
93
+ ## Installation
94
+
95
+ The package is not published yet.
96
+
97
+ When published, installation will look like:
98
+
99
+ ```bash
100
+ pnpm add @truesift/express
101
+ ```
102
+
103
+ or:
104
+
105
+ ```bash
106
+ npm install @truesift/express
107
+ ```
108
+
109
+ For local development, use the package directly from the project directory or through a workspace setup.
110
+
111
+ ---
112
+
113
+ ## Requirements
114
+
115
+ ```txt
116
+ Node.js >= 20.0.0
117
+ TypeScript
118
+ ESM runtime
119
+ Server-side environment
120
+ ```
121
+
122
+ The SDK uses the native `fetch` available in modern Node.js versions.
123
+
124
+ No browser runtime is targeted.
125
+
126
+ ---
127
+
128
+ ## Planned public API
129
+
130
+ The first stable SDK API is planned to expose:
131
+
132
+ ```ts
133
+ createBotGuardClient(config)
134
+ BotGuardClient
135
+ client.createChallenge(input)
136
+ client.verifyChallenge(input)
137
+
138
+ isAllowed(result)
139
+ isReview(result)
140
+ isBlocked(result)
141
+
142
+ BotGuardError
143
+ BotGuardConfigError
144
+ BotGuardRequestError
145
+ BotGuardTimeoutError
146
+ BotGuardAuthError
147
+ BotGuardResponseError
148
+ BotGuardApiError
149
+ ```
150
+
151
+ The internal product name is now TrueSift, but the technical API may still use `BotGuard` naming in early versions where it reflects the original backend module and locked architecture.
152
+
153
+ ---
154
+
155
+ ## Configuration
156
+
157
+ Recommended project environment variables:
158
+
159
+ ```env
160
+ TRUESIFT_API_BASE_URL=https://your-truesift-api.example.com/api/v1/botguard
161
+ TRUESIFT_SITE_KEY=your_site_key
162
+ TRUESIFT_SECRET_KEY=your_secret_key
163
+ TRUESIFT_DEFAULT_ACTION=website_check
164
+ TRUESIFT_DEFAULT_ORIGIN=https://www.example.com
165
+ TRUESIFT_TIMEOUT_MS=2500
166
+ TRUESIFT_FAIL_OPEN=true
167
+ ```
168
+
169
+ The SDK itself does not automatically read `.env` files.
170
+
171
+ Backend projects should read and validate their own environment variables, then pass a configuration object to the SDK.
172
+
173
+ Example:
174
+
175
+ ```ts
176
+ import { createBotGuardClient } from '@truesift/express';
177
+
178
+ const trueSiftClient = createBotGuardClient({
179
+ apiBaseUrl: process.env.TRUESIFT_API_BASE_URL,
180
+ siteKey: process.env.TRUESIFT_SITE_KEY,
181
+ secretKey: process.env.TRUESIFT_SECRET_KEY,
182
+ defaultAction: 'website_check',
183
+ defaultOrigin: 'https://www.example.com',
184
+ timeoutMs: 2500
185
+ });
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Secret key rules
191
+
192
+ The `secretKey` is a backend-only credential.
193
+
194
+ Never:
195
+
196
+ - send it to the browser
197
+ - expose it through frontend environment variables
198
+ - log it
199
+ - include it in screenshots
200
+ - include it in client payloads
201
+ - store it in public repositories
202
+ - return it from API responses
203
+
204
+ The SDK must redact sensitive values from error context and debug context.
205
+
206
+ ---
207
+
208
+ ## Site key rules
209
+
210
+ The `siteKey` is a public identifier by design, but this SDK treats it as server-side configuration.
211
+
212
+ A backend project may decide whether the frontend ever needs to know a site key.
213
+
214
+ For backend-driven flows, the frontend does not need direct access to the site key.
215
+
216
+ ---
217
+
218
+ ## Challenge flow
219
+
220
+ The SDK does not decide where or when challenges are created.
221
+
222
+ A project may create challenges:
223
+
224
+ - when a page loads
225
+ - when a form opens
226
+ - immediately before submit
227
+ - through a server-side session flow
228
+ - through another project-specific flow
229
+
230
+ The SDK only provides the client operation.
231
+
232
+ Conceptual usage:
233
+
234
+ ```ts
235
+ const challenge = await trueSiftClient.createChallenge({
236
+ origin: 'https://www.example.com',
237
+ action: 'website_check',
238
+ path: '/website-check',
239
+ metadata: {
240
+ form: 'website-check'
241
+ }
242
+ });
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Verify flow
248
+
249
+ The SDK sends challenge data and client signals to the TrueSift API.
250
+
251
+ Conceptual usage:
252
+
253
+ ```ts
254
+ const result = await trueSiftClient.verifyChallenge({
255
+ challengeId: body.challengeId,
256
+ challengeToken: body.challengeToken,
257
+ origin: 'https://www.example.com',
258
+ action: 'website_check',
259
+ path: '/website-check',
260
+ clientSignals: {
261
+ elapsedMs: body.elapsedMs,
262
+ honeypotValue: body.companyWebsite
263
+ },
264
+ metadata: {
265
+ form: 'website-check'
266
+ }
267
+ });
268
+ ```
269
+
270
+ The SDK normalizes the response, but the project decides what to do next.
271
+
272
+ ---
273
+
274
+ ## Decision model
275
+
276
+ TrueSift decisions are normalized to:
277
+
278
+ ```txt
279
+ allow
280
+ review
281
+ block
282
+ ```
283
+
284
+ The SDK exposes helper functions:
285
+
286
+ ```ts
287
+ isAllowed(result)
288
+ isReview(result)
289
+ isBlocked(result)
290
+ ```
291
+
292
+ These helpers do not make business decisions.
293
+
294
+ They only make backend code easier to read.
295
+
296
+ ---
297
+
298
+ ## Fail-open and fail-closed
299
+
300
+ The SDK does not decide whether a request should continue when TrueSift is unavailable.
301
+
302
+ That decision belongs to the project backend.
303
+
304
+ Typical policies:
305
+
306
+ ```txt
307
+ fail-open:
308
+ if TrueSift is unavailable, continue the business flow
309
+
310
+ fail-closed:
311
+ if TrueSift is unavailable, reject the request
312
+ ```
313
+
314
+ For early observe-mode integrations, fail-open is usually safer because real users should not be blocked by a temporary verification outage.
315
+
316
+ ---
317
+
318
+ ## Observe mode
319
+
320
+ In observe mode, TrueSift can collect telemetry and return decisions without blocking real users.
321
+
322
+ The SDK should return normalized result data.
323
+
324
+ The project backend decides whether to ignore, store, review, or act on that result.
325
+
326
+ ---
327
+
328
+ ## Protect mode
329
+
330
+ In protect mode, TrueSift may return a block decision.
331
+
332
+ A block decision is a valid business result, not a transport error.
333
+
334
+ The SDK must not throw an exception just because the decision is `block`.
335
+
336
+ Transport errors are different and include:
337
+
338
+ - network failure
339
+ - timeout
340
+ - invalid JSON
341
+ - unexpected response shape
342
+ - HTTP 401
343
+ - HTTP 5xx
344
+ - malformed API response
345
+
346
+ ---
347
+
348
+ ## Error model
349
+
350
+ The SDK distinguishes between several error classes:
351
+
352
+ ```txt
353
+ BotGuardConfigError
354
+ BotGuardRequestError
355
+ BotGuardTimeoutError
356
+ BotGuardAuthError
357
+ BotGuardResponseError
358
+ BotGuardApiError
359
+ ```
360
+
361
+ Expected meaning:
362
+
363
+ ```txt
364
+ BotGuardConfigError:
365
+ missing or invalid SDK configuration
366
+
367
+ BotGuardRequestError:
368
+ network-level request failure
369
+
370
+ BotGuardTimeoutError:
371
+ request aborted after timeout
372
+
373
+ BotGuardAuthError:
374
+ API returned an authentication or authorization error
375
+
376
+ BotGuardResponseError:
377
+ API response was malformed or unexpected
378
+
379
+ BotGuardApiError:
380
+ API returned a structured error response
381
+ ```
382
+
383
+ ---
384
+
385
+ ## Timeout behavior
386
+
387
+ The SDK supports request timeouts.
388
+
389
+ Recommended default:
390
+
391
+ ```txt
392
+ 2500ms
393
+ ```
394
+
395
+ The timeout is implemented with `AbortController`.
396
+
397
+ The SDK must clean up timers correctly after each request.
398
+
399
+ ---
400
+
401
+ ## Retry behavior
402
+
403
+ The first SDK version does not retry requests by default.
404
+
405
+ Especially important:
406
+
407
+ ```txt
408
+ verifyChallenge() must not be retried automatically
409
+ ```
410
+
411
+ Challenge tokens may be single-use.
412
+
413
+ Retrying verification can produce incorrect behavior or falsely consume a token.
414
+
415
+ ---
416
+
417
+ ## Express usage concept
418
+
419
+ The SDK does not provide Express routes or automatic middleware in the first version.
420
+
421
+ A controller should remain project-specific.
422
+
423
+ Conceptual controller flow:
424
+
425
+ ```txt
426
+ 1. Receive form submit
427
+ 2. Normalize request body
428
+ 3. Extract challenge fields
429
+ 4. Extract client signals
430
+ 5. Call verifyChallenge()
431
+ 6. If TrueSift transport error and project policy is fail-open:
432
+ continue business flow and store telemetry if needed
433
+ 7. If result is blocked and project is in protect mode:
434
+ return project-specific rejection response
435
+ 8. Otherwise:
436
+ continue the normal business flow
437
+ ```
438
+
439
+ ---
440
+
441
+ ## Next.js backend usage concept
442
+
443
+ The same SDK may be used in Next.js route handlers, but this package must not import Next.js types.
444
+
445
+ Conceptual flow:
446
+
447
+ ```txt
448
+ app/api/some-form/route.ts
449
+
450
+ server-only environment config
451
+
452
+ createBotGuardClient()
453
+
454
+ verifyChallenge()
455
+
456
+ project-specific response handling
457
+ ```
458
+
459
+ Do not import this SDK into client components.
460
+
461
+ ---
462
+
463
+ ## Security principles
464
+
465
+ The SDK follows these principles:
466
+
467
+ - no default logging
468
+ - no secret logging
469
+ - no frontend usage
470
+ - no browser bundle usage
471
+ - no business policy decisions
472
+ - no automatic Express middleware in the first version
473
+ - no automatic retries for challenge verification
474
+ - runtime response validation
475
+ - strict TypeScript types
476
+ - minimal dependencies
477
+
478
+ ---
479
+
480
+ ## Development
481
+
482
+ Install dependencies:
483
+
484
+ ```bash
485
+ pnpm install
486
+ ```
487
+
488
+ Run typecheck:
489
+
490
+ ```bash
491
+ pnpm typecheck
492
+ ```
493
+
494
+ Build package:
495
+
496
+ ```bash
497
+ pnpm build
498
+ ```
499
+
500
+ Run tests:
501
+
502
+ ```bash
503
+ pnpm test
504
+ ```
505
+
506
+ Run all checks:
507
+
508
+ ```bash
509
+ pnpm check
510
+ ```
511
+
512
+ ---
513
+
514
+ ## Current build setup
515
+
516
+ The package currently uses:
517
+
518
+ ```txt
519
+ TypeScript 6
520
+ tsup
521
+ Vitest
522
+ Node.js 20 target
523
+ ESM output
524
+ DTS output
525
+ ```
526
+
527
+ The generated package output is written to:
528
+
529
+ ```txt
530
+ dist/
531
+ ```
532
+
533
+ ---
534
+
535
+ ## Repository status
536
+
537
+ This package directory may later become:
538
+
539
+ - a standalone Git repository
540
+ - part of a monorepo
541
+ - a private npm package source
542
+ - a public npm package source
543
+ - an internal TrueSift SDK workspace
544
+
545
+ The package is designed to remain reusable regardless of the final repository and publishing strategy.
546
+
547
+ ---
548
+
549
+ ## License
550
+
551
+ This package is currently proprietary and unpublished.
552
+
553
+ See:
554
+
555
+ ```txt
556
+ LICENSE
557
+ ```
558
+
559
+ ---
560
+
561
+ ## Product
562
+
563
+ ```txt
564
+ TrueSift — Next-Gen Human Verification made in Germany
565
+ ```
566
+
567
+ Developed by WebDigiTech.
@@ -0,0 +1 @@
1
+ export { B as BotGuardApiError, c as BotGuardAuthError, d as BotGuardConfigError, e as BotGuardError, j as BotGuardRequestError, k as BotGuardResponseError, l as BotGuardTimeoutError, B as TrueSiftApiError, c as TrueSiftAuthError, d as TrueSiftConfigError, e as TrueSiftError, j as TrueSiftRequestError, k as TrueSiftResponseError, l as TrueSiftTimeoutError } from '../index-DWCqfBfQ.js';
@@ -0,0 +1,158 @@
1
+ // src/errors/BotGuardError.ts
2
+ var BotGuardError = class extends Error {
3
+ code;
4
+ statusCode;
5
+ requestId;
6
+ context;
7
+ constructor(options) {
8
+ const errorOptions = options.cause === void 0 ? void 0 : { cause: options.cause };
9
+ super(options.message, errorOptions);
10
+ this.name = new.target.name;
11
+ this.code = options.code;
12
+ if (options.statusCode !== void 0) {
13
+ this.statusCode = options.statusCode;
14
+ }
15
+ if (options.requestId !== void 0) {
16
+ this.requestId = options.requestId;
17
+ }
18
+ if (options.context !== void 0) {
19
+ this.context = options.context;
20
+ }
21
+ Object.setPrototypeOf(this, new.target.prototype);
22
+ }
23
+ toJSON() {
24
+ return {
25
+ name: this.name,
26
+ code: this.code,
27
+ message: this.message,
28
+ ...this.statusCode !== void 0 ? { statusCode: this.statusCode } : {},
29
+ ...this.requestId !== void 0 ? { requestId: this.requestId } : {},
30
+ ...this.context !== void 0 ? { context: this.context } : {}
31
+ };
32
+ }
33
+ };
34
+
35
+ // src/errors/BotGuardConfigError.ts
36
+ var DEFAULT_CONFIG_ERROR_MESSAGE = "TrueSift SDK configuration is invalid.";
37
+ var BotGuardConfigError = class extends BotGuardError {
38
+ constructor(options = {}) {
39
+ const errorOptions = {
40
+ code: "TRUESIFT_CONFIG_ERROR",
41
+ message: options.message ?? DEFAULT_CONFIG_ERROR_MESSAGE,
42
+ ...options.context !== void 0 ? { context: options.context } : {},
43
+ ...options.cause !== void 0 ? { cause: options.cause } : {}
44
+ };
45
+ super(errorOptions);
46
+ }
47
+ };
48
+
49
+ // src/errors/BotGuardRequestError.ts
50
+ var DEFAULT_REQUEST_ERROR_MESSAGE = "TrueSift API request failed.";
51
+ var BotGuardRequestError = class extends BotGuardError {
52
+ constructor(options = {}) {
53
+ const errorOptions = {
54
+ code: "TRUESIFT_REQUEST_ERROR",
55
+ message: options.message ?? DEFAULT_REQUEST_ERROR_MESSAGE,
56
+ ...options.statusCode !== void 0 ? { statusCode: options.statusCode } : {},
57
+ ...options.requestId !== void 0 ? { requestId: options.requestId } : {},
58
+ ...options.context !== void 0 ? { context: options.context } : {},
59
+ ...options.cause !== void 0 ? { cause: options.cause } : {}
60
+ };
61
+ super(errorOptions);
62
+ }
63
+ };
64
+
65
+ // src/errors/BotGuardTimeoutError.ts
66
+ var DEFAULT_TIMEOUT_ERROR_MESSAGE = "TrueSift API request timed out.";
67
+ var BotGuardTimeoutError = class extends BotGuardError {
68
+ timeoutMs;
69
+ constructor(options = {}) {
70
+ const context = {
71
+ ...options.context ?? {},
72
+ ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
73
+ };
74
+ const errorOptions = {
75
+ code: "TRUESIFT_TIMEOUT_ERROR",
76
+ message: options.message ?? DEFAULT_TIMEOUT_ERROR_MESSAGE,
77
+ ...options.requestId !== void 0 ? { requestId: options.requestId } : {},
78
+ ...Object.keys(context).length > 0 ? { context } : {},
79
+ ...options.cause !== void 0 ? { cause: options.cause } : {}
80
+ };
81
+ super(errorOptions);
82
+ if (options.timeoutMs !== void 0) {
83
+ this.timeoutMs = options.timeoutMs;
84
+ }
85
+ }
86
+ toJSON() {
87
+ return {
88
+ ...super.toJSON(),
89
+ code: "TRUESIFT_TIMEOUT_ERROR",
90
+ ...this.timeoutMs !== void 0 ? { timeoutMs: this.timeoutMs } : {}
91
+ };
92
+ }
93
+ };
94
+
95
+ // src/errors/BotGuardAuthError.ts
96
+ var DEFAULT_AUTH_ERROR_MESSAGE = "TrueSift API authentication failed.";
97
+ var BotGuardAuthError = class extends BotGuardError {
98
+ constructor(options = {}) {
99
+ const errorOptions = {
100
+ code: "TRUESIFT_AUTH_ERROR",
101
+ message: options.message ?? DEFAULT_AUTH_ERROR_MESSAGE,
102
+ ...options.statusCode !== void 0 ? { statusCode: options.statusCode } : {},
103
+ ...options.requestId !== void 0 ? { requestId: options.requestId } : {},
104
+ ...options.context !== void 0 ? { context: options.context } : {},
105
+ ...options.cause !== void 0 ? { cause: options.cause } : {}
106
+ };
107
+ super(errorOptions);
108
+ }
109
+ };
110
+
111
+ // src/errors/BotGuardResponseError.ts
112
+ var DEFAULT_RESPONSE_ERROR_MESSAGE = "TrueSift API returned an invalid response.";
113
+ var BotGuardResponseError = class extends BotGuardError {
114
+ constructor(options = {}) {
115
+ const errorOptions = {
116
+ code: "TRUESIFT_RESPONSE_ERROR",
117
+ message: options.message ?? DEFAULT_RESPONSE_ERROR_MESSAGE,
118
+ ...options.statusCode !== void 0 ? { statusCode: options.statusCode } : {},
119
+ ...options.requestId !== void 0 ? { requestId: options.requestId } : {},
120
+ ...options.context !== void 0 ? { context: options.context } : {},
121
+ ...options.cause !== void 0 ? { cause: options.cause } : {}
122
+ };
123
+ super(errorOptions);
124
+ }
125
+ };
126
+
127
+ // src/errors/BotGuardApiError.ts
128
+ var DEFAULT_API_ERROR_MESSAGE = "TrueSift API returned an error response.";
129
+ var BotGuardApiError = class extends BotGuardError {
130
+ apiError;
131
+ constructor(options = {}) {
132
+ const context = {
133
+ ...options.context ?? {},
134
+ ...options.apiError !== void 0 ? { apiError: options.apiError } : {}
135
+ };
136
+ const errorOptions = {
137
+ code: "TRUESIFT_API_ERROR",
138
+ message: options.message ?? DEFAULT_API_ERROR_MESSAGE,
139
+ ...options.statusCode !== void 0 ? { statusCode: options.statusCode } : {},
140
+ ...options.requestId !== void 0 ? { requestId: options.requestId } : {},
141
+ ...Object.keys(context).length > 0 ? { context } : {},
142
+ ...options.cause !== void 0 ? { cause: options.cause } : {}
143
+ };
144
+ super(errorOptions);
145
+ if (options.apiError !== void 0) {
146
+ this.apiError = options.apiError;
147
+ }
148
+ }
149
+ toJSON() {
150
+ return {
151
+ ...super.toJSON(),
152
+ code: "TRUESIFT_API_ERROR",
153
+ ...this.apiError !== void 0 ? { apiError: this.apiError } : {}
154
+ };
155
+ }
156
+ };
157
+
158
+ export { BotGuardApiError, BotGuardAuthError, BotGuardConfigError, BotGuardError, BotGuardRequestError, BotGuardResponseError, BotGuardTimeoutError, BotGuardApiError as TrueSiftApiError, BotGuardAuthError as TrueSiftAuthError, BotGuardConfigError as TrueSiftConfigError, BotGuardError as TrueSiftError, BotGuardRequestError as TrueSiftRequestError, BotGuardResponseError as TrueSiftResponseError, BotGuardTimeoutError as TrueSiftTimeoutError };