@chitmark/sdk 0.6.2 → 0.6.3

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.
@@ -1,435 +0,0 @@
1
- /**
2
- * Shared API types for Chitmark by Open Agent Ledger.
3
- * Aligns with openapi/openapi.yaml and SDK.md.
4
- */
5
- /** Routing decision from verify. When degraded, this is always "challenge". */
6
- type Decision = "allow" | "challenge" | "deny";
7
- /** Classified actor behind the inbound action. */
8
- type ActorType = "human" | "agent_principal" | "agent_abusive" | "unknown";
9
- /** Whether a returned verdict is meant to gate traffic or only be observed. */
10
- type EnforcementMode = "enforce" | "log_only";
11
- /** Known action surfaces; custom strings are also accepted. */
12
- type Action = "signup" | "trial_activation" | "api_key" | "demo_request" | "quote" | "ticket" | "custom" | (string & {});
13
- /** Outcomes reported via feedback: the data moat. Prefer fast labels first. */
14
- type Outcome = "credit_burn" | "multi_account_cluster" | "abuse_confirmed" | "converted" | "chargeback" | "churned" | "false_positive";
15
- /** Asymmetric-cost challenge methods (best → worst for anti-abuse). */
16
- type ChallengeMethod = "payment_preauth" | "proof_of_work" | "device_attestation" | "web_bot_auth_stepup" | "email_otp";
17
- /** Client-side PII minimization mode. Default is hashed. Raw is opt-in only. */
18
- type PiiMode = "raw" | "hashed" | "none";
19
- /** Environment target; selects default base URL. */
20
- type ChitmarkEnv = "production" | "staging" | "development";
21
- /** On timeout/error, client decision fallback. NEVER "allow". */
22
- type OnDegraded = "challenge";
23
- /**
24
- * Principal resolution: mostly populated for good signed agents;
25
- * sparse for farmers.
26
- */
27
- interface Principal {
28
- resolved: boolean;
29
- /** Bot maker from Web Bot Auth Signature-Agent (e.g. "openai"). */
30
- operator?: string;
31
- /** End-user principal ("on whose behalf"); often null at the wedge. */
32
- onBehalfOf?: string;
33
- identityBasis: string[];
34
- }
35
- /** Verdict object: single source of truth for a verify call. */
36
- interface Verdict {
37
- /** When degraded === true, this is ALWAYS "challenge", never "allow". */
38
- decision: Decision;
39
- actorType: ActorType;
40
- /** 0..1 */
41
- confidence: number;
42
- /** Human-readable; always populated for ops teams. */
43
- reasons: string[];
44
- principal: Principal;
45
- /** ES256 JWT decision receipt, bound to session. */
46
- verdictToken: string;
47
- /** Store on the account row: feedback join key. */
48
- eventId: string;
49
- /** true → served under timeout/error → decision forced to challenge. */
50
- degraded: boolean;
51
- /** log_only verdicts are for dashboards/observation, not partner-side blocking. */
52
- enforcementMode: EnforcementMode;
53
- /** true → this allow honors a challenge completed for the session (context.challengeId). */
54
- challengeCleared?: boolean;
55
- }
56
- /** Subject signals for verify. Prefer hashed fields over raw PII. */
57
- interface Subject {
58
- email?: string;
59
- emailSha256?: string;
60
- ip?: string;
61
- ipTrunc?: string;
62
- userAgent?: string;
63
- /** Includes Web Bot Auth headers when present. */
64
- headers?: Record<string, string | string[] | undefined>;
65
- formData?: Record<string, unknown>;
66
- formDataHashed?: Record<string, unknown>;
67
- }
68
- /**
69
- * Cost ratio that repositions the allow/challenge/deny boundaries for a
70
- * single verify. Higher `falseAllow` challenges earlier (abuse-averse);
71
- * higher `falseChallenge` lets more of the gray zone through; higher
72
- * `falseDeny` reserves deny for confirmed abuse. Defaults 1:1:3 keep the
73
- * fail-to-challenge semantics. Missing/non-positive fields fall back to
74
- * their default.
75
- */
76
- interface DecisionCosts {
77
- falseAllow?: number;
78
- falseChallenge?: number;
79
- falseDeny?: number;
80
- }
81
- /** Per-request policy flags for POST /v1/verify. */
82
- interface VerifyContext {
83
- /** Reference a challenge completed for this session; honored once. */
84
- challengeId?: string;
85
- /** "default" challenges the gray zone; "confirmed_tail_only" allows it in enforce mode. */
86
- challengePolicy?: "default" | "confirmed_tail_only";
87
- /** True → observation-only `log_only` verdict: nothing is blocked or challenged. */
88
- logOnly?: boolean;
89
- /** Reposition the allow/challenge/deny boundaries (defaults 1:1:3). */
90
- decisionCosts?: DecisionCosts;
91
- /** Partner-specific flags (e.g. plan, referrer), carried, not scored. */
92
- [key: string]: unknown;
93
- }
94
- /** Request body for POST /v1/verify. */
95
- interface VerifyRequest {
96
- idempotencyKey?: string;
97
- action: Action;
98
- /** Binds any resulting challenge + verdictToken to THIS session. */
99
- session?: string;
100
- surface?: string;
101
- subject: Subject;
102
- context?: VerifyContext;
103
- }
104
- /** Request body for POST /v1/feedback. */
105
- interface FeedbackRequest {
106
- eventId: string;
107
- outcome: Outcome;
108
- /** $ of infra/credit burned, or ARR: units in `unit`. */
109
- value?: number;
110
- unit?: string;
111
- observedAt?: string;
112
- /** Body form of Idempotency-Key; header takes precedence. */
113
- idempotencyKey?: string;
114
- }
115
- /** Response from POST /v1/feedback. */
116
- interface FeedbackResponse {
117
- ok: true;
118
- eventId: string;
119
- }
120
- /**
121
- * Scales the proof-of-work difficulty issued with a challenge so the
122
- * challenge's economic tax rises with risk. Absent → "default".
123
- */
124
- type ChallengeRiskTier = "default" | "elevated" | "severe";
125
- /** Request body for POST /v1/challenge: issue or complete. */
126
- interface ChallengeRequest {
127
- /** eventId from the verify verdict that routed to challenge. */
128
- eventId: string;
129
- /** Uniquely represents one action attempt. Required for issue and completion. */
130
- session: string;
131
- /** Ranked method preference, best → worst. Never defaults to email_otp. */
132
- prefer?: ChallengeMethod[];
133
- /** Completion mode: the challenge being solved. */
134
- challengeId?: string;
135
- /** Completion mode: server-verified proof bound to challengeId + session. */
136
- proof?: ChallengeProof;
137
- /**
138
- * Issue-mode context. `riskTier` scales the issued proof-of-work difficulty
139
- * so the challenge's economic tax rises with risk; completion is always
140
- * validated against the difficulty that was issued.
141
- */
142
- context?: {
143
- riskTier?: ChallengeRiskTier;
144
- };
145
- }
146
- /** Server-verified completion proof. */
147
- type ChallengeProof = {
148
- type: "proof_of_work";
149
- /** First nonce where sha256(`${challengeId}:${seed}:${nonce}`) hex starts with `difficulty` zero nibbles. */
150
- nonce: string;
151
- } | {
152
- type: "stripe_setup_intent";
153
- /** SetupIntent id from the issued instructions; status must be succeeded. */
154
- setupIntentId: string;
155
- };
156
- /** Response from POST /v1/challenge (issue mode). */
157
- interface ChallengeResponse {
158
- challengeId: string;
159
- method: ChallengeMethod;
160
- instructions: {
161
- type: "pow";
162
- /** Leading zero nibbles required in the sha256 hex digest. */
163
- difficulty: number;
164
- /** Combine as `${challengeId}:${seed}:${nonce}`. */
165
- seed: string;
166
- algorithm: "sha256-prefix";
167
- } | {
168
- type: "stripe_setup_intent";
169
- /** test = real Stripe test-mode; stub = deterministic local/CI id. */
170
- mode: "test" | "stub";
171
- clientSecret: string;
172
- publishableKey?: string;
173
- };
174
- /** Solving only clears THIS session (anti-replay). */
175
- boundTo: string;
176
- expiresAt: string;
177
- }
178
- /** Response from POST /v1/challenge (completion mode). */
179
- interface ChallengeCompletionResponse {
180
- ok: true;
181
- challengeId: string;
182
- /** Session that was cleared (single use, anti-replay). */
183
- boundTo: string;
184
- clearedAt: string;
185
- }
186
- /** Client constructor options. */
187
- interface ChitmarkOptions {
188
- /** API key (Bearer). Use process.env.CHITMARK_API_KEY. */
189
- apiKey: string;
190
- /**
191
- * Timeout/error behavior. Fixed to "challenge": never allow silent bypass.
192
- * @default "challenge"
193
- */
194
- onDegraded?: OnDegraded;
195
- /**
196
- * Client-side request budget in ms. Edge path is far faster.
197
- * @default 800
198
- */
199
- timeoutMs?: number;
200
- /**
201
- * Client-side PII minimization before send.
202
- * @default "hashed"
203
- */
204
- piiMode?: PiiMode;
205
- /**
206
- * Selects default base URL unless baseUrl or CHITMARK_BASE_URL is set.
207
- * @default "production"
208
- */
209
- env?: ChitmarkEnv;
210
- /**
211
- * Override API host (e.g. local edge). Precedence:
212
- * baseUrl > CHITMARK_BASE_URL env > env default.
213
- */
214
- baseUrl?: string;
215
- /** Custom fetch implementation (Workers, tests). */
216
- fetch?: typeof fetch;
217
- /** User-Agent / client identification sent as X-Chitmark-Client. */
218
- clientName?: string;
219
- }
220
- interface ChitmarkErrorBody {
221
- error: string;
222
- message?: string;
223
- code?: string;
224
- }
225
-
226
- /**
227
- * Base error for all Chitmark client failures.
228
- */
229
- declare class ChitmarkError extends Error {
230
- name: string;
231
- readonly status?: number;
232
- readonly code?: string;
233
- readonly body?: ChitmarkErrorBody | string;
234
- constructor(message: string, options?: {
235
- status?: number;
236
- code?: string;
237
- body?: ChitmarkErrorBody | string;
238
- });
239
- }
240
- /**
241
- * Raised when the API returns a non-2xx response.
242
- */
243
- declare class ChitmarkApiError extends ChitmarkError {
244
- name: string;
245
- constructor(status: number, body: ChitmarkErrorBody | string, message?: string);
246
- }
247
- /**
248
- * Build the degraded challenge verdict used on timeout / transport failure.
249
- * Golden rule: fail to challenge, never to allow.
250
- */
251
- declare function degradedChallengeVerdict(reason: string, session?: string): Verdict;
252
- /**
253
- * Ensure degraded responses never surface as allow (defense in depth client-side).
254
- */
255
- declare function enforceDegradedNeverAllow(verdict: Verdict): Verdict;
256
-
257
- /**
258
- * Client-side verdictToken verification.
259
- *
260
- * A verdictToken is an ES256 JWT decision receipt minted by the edge and bound
261
- * to session (`sub`), origin hint (`aud`), issuing tenant (`tid`), and `jti`
262
- * with a short `exp`. This module validates shape, signature (against the JWKS
263
- * served from GET /.well-known/jwks.json), expiry, session binding, and, when
264
- * expected values are supplied, tenant and origin binding. `aud` reflects
265
- * request headers and is attacker influenced: always verify `session` and
266
- * `tenantId`, never `aud` alone. Rejection reasons are surfaced as
267
- * `VerdictTokenError.code`.
268
- */
269
-
270
- interface VerdictTokenClaims {
271
- eventId: string;
272
- decision: Decision;
273
- actorType: ActorType;
274
- confidence: number;
275
- aud: string;
276
- sub: string;
277
- /** Issuing tenant, server-derived from the API key used at verify time. */
278
- tid: string;
279
- jti: string;
280
- iat: number;
281
- exp: number;
282
- degraded: boolean;
283
- }
284
- type VerdictTokenErrorCode = "malformed_token" | "wrong_algorithm" | "wrong_type" | "jwks_unavailable" | "unknown_kid" | "invalid_signature" | "expired" | "not_yet_valid" | "wrong_session" | "wrong_aud" | "wrong_tenant";
285
- declare class VerdictTokenError extends ChitmarkError {
286
- name: string;
287
- constructor(code: VerdictTokenErrorCode, message: string);
288
- }
289
- interface VerifyVerdictTokenOptions {
290
- /** Expected session: token `sub` must equal this or verification fails. */
291
- session?: string;
292
- /** Expected issuing tenant: token `tid` must equal this or verification fails. */
293
- tenantId?: string;
294
- /** Expected origin hint: token `aud` must equal this or verification fails. */
295
- aud?: string;
296
- /** JWKS URL; defaults to https://api.chitmark.com/.well-known/jwks.json. */
297
- jwksUrl?: string;
298
- /** Pre-fetched JWKS; skips the network fetch when provided. */
299
- jwks?: {
300
- keys: Array<Record<string, unknown>>;
301
- };
302
- /** Injectable fetch (Node 24+/browsers have a global). */
303
- fetch?: typeof fetch;
304
- /** Clock override for tests. */
305
- nowMs?: number;
306
- /** Clock skew tolerance in seconds; defaults to 30. */
307
- leewaySeconds?: number;
308
- }
309
- declare function verifyVerdictToken(token: string, options?: VerifyVerdictTokenOptions): Promise<VerdictTokenClaims>;
310
-
311
- /**
312
- * Official Chitmark client (Open Agent Ledger): three verbs:
313
- * verify, feedback, challenge. Trust decisions on agent-mediated actions,
314
- * tuned by business outcomes.
315
- *
316
- * @example
317
- * ```ts
318
- * const chitmark = new Chitmark({ apiKey: process.env.CHITMARK_API_KEY! });
319
- * const verdict = await chitmark.verify({
320
- * action: "signup",
321
- * subject: { email, ip, userAgent },
322
- * });
323
- * ```
324
- */
325
- declare class Chitmark {
326
- private readonly apiKey;
327
- private readonly baseUrl;
328
- private readonly timeoutMs;
329
- private readonly piiMode;
330
- private readonly onDegraded;
331
- private readonly fetchImpl;
332
- private readonly clientName;
333
- constructor(options: ChitmarkOptions);
334
- /**
335
- * Score + route an inbound action (signup / trial / …).
336
- * Hot path at the edge; client budget defaults to 800ms.
337
- * On timeout/transport error, or a malformed verdict shape from the API,
338
- * returns a degraded challenge verdict (never allow, never crashes).
339
- *
340
- * Persist `v.eventId` on the account row: feedback joins only on that id.
341
- */
342
- verify(request: VerifyRequest): Promise<Verdict>;
343
- /**
344
- * Report a downstream outcome joined on the stored eventId from verify.
345
- * This is the data moat: attribution is a schema contract, not a fuzzy match.
346
- * `idempotencyKey` is sent as both the Idempotency-Key header and body field
347
- * (header takes precedence server-side) so exact retries replay the original
348
- * acknowledgement.
349
- */
350
- feedback(request: FeedbackRequest): Promise<FeedbackResponse>;
351
- /**
352
- * Issue an asymmetric-cost challenge after decision === challenge | degraded.
353
- */
354
- challenge(request: ChallengeRequest): Promise<ChallengeResponse>;
355
- /**
356
- * Complete a challenge by submitting its solved proof. Clears only the bound
357
- * session, once. Re-verify with `context.challengeId` to have the next
358
- * verify honor the cleared session.
359
- */
360
- completeChallenge(request: {
361
- eventId: string;
362
- challengeId: string;
363
- session: string;
364
- proof: ChallengeProof;
365
- }): Promise<ChallengeCompletionResponse>;
366
- /**
367
- * Verify a verdictToken's signature against the API's JWKS and its session /
368
- * tenant binding. Rejects expired tokens, unknown kids, and
369
- * invalid signatures with `VerdictTokenError`. Pass `session` and `tenantId`
370
- * to enforce session and tenant binding (recommended); `aud` enforces the
371
- * origin hint only.
372
- */
373
- verifyVerdictToken(token: string, options?: Omit<VerifyVerdictTokenOptions, "jwksUrl" | "fetch">): Promise<VerdictTokenClaims>;
374
- /**
375
- * Low-level HTTP helper. Prefer verify / feedback / challenge.
376
- */
377
- request<T>(path: string, init: {
378
- method: string;
379
- body?: unknown;
380
- idempotencyKey?: string;
381
- }): Promise<T>;
382
- /** Public accessors for inspection / tests. */
383
- get config(): {
384
- baseUrl: string;
385
- timeoutMs: number;
386
- piiMode: PiiMode;
387
- onDegraded: OnDegraded;
388
- };
389
- }
390
-
391
- /**
392
- * Client-side PII minimization helpers.
393
- * Default SDK mode hashes email and truncates IP before leaving the customer process.
394
- */
395
- /**
396
- * SHA-256 hex digest of lowercased, trimmed email.
397
- * Uses Web Crypto (Node 18+, browsers, Workers).
398
- */
399
- declare function hashEmailSha256(email: string): Promise<string>;
400
- /**
401
- * Truncate IPv4 to /24 or IPv6 to /48 for coarse geo without host identity.
402
- */
403
- declare function truncateIp(ip: string): string;
404
- /**
405
- * Reduce form payload to non-PII keys (domain-style fields only for hashed mode).
406
- * Free-text is dropped; companyDomain-style keys are kept as-is when domain-like.
407
- */
408
- declare function minimizeFormData(formData: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
409
-
410
- declare const CHITMARK_HTTP_STATUS: {
411
- readonly ok: 200;
412
- readonly created: 201;
413
- readonly badRequest: 400;
414
- readonly unauthorized: 401;
415
- readonly forbidden: 403;
416
- readonly notFound: 404;
417
- readonly conflict: 409;
418
- readonly preconditionRequired: 428;
419
- readonly tooManyRequests: 429;
420
- };
421
- type ChitmarkHttpStatus = (typeof CHITMARK_HTTP_STATUS)[keyof typeof CHITMARK_HTTP_STATUS];
422
- declare const CHITMARK_HTTP_STATUS_MEANING: {
423
- readonly ok: "Request succeeded. For verify gates, continue only after an explicit non-degraded allow.";
424
- readonly created: "Resource was created after an explicit non-degraded allow.";
425
- readonly badRequest: "Required request fields are missing or malformed.";
426
- readonly unauthorized: "API key is missing or invalid.";
427
- readonly forbidden: "Verify returned deny; block the action.";
428
- readonly notFound: "Referenced Chitmark resource was not found.";
429
- readonly conflict: "Idempotency key was reused with a materially different payload.";
430
- readonly preconditionRequired: "Verify returned challenge or degraded; require friction before continuing.";
431
- readonly tooManyRequests: "Request was rate limited.";
432
- };
433
- declare function verdictToHttpStatus(verdict: Verdict): ChitmarkHttpStatus;
434
-
435
- export { type Action as A, enforceDegradedNeverAllow as B, Chitmark as C, type Decision as D, type EnforcementMode as E, type FeedbackRequest as F, hashEmailSha256 as G, minimizeFormData as H, truncateIp as I, verdictToHttpStatus as J, verifyVerdictToken as K, type OnDegraded as O, type PiiMode as P, type Subject as S, type VerifyContext as V, type VerifyRequest as a, type Verdict as b, type ActorType as c, CHITMARK_HTTP_STATUS as d, CHITMARK_HTTP_STATUS_MEANING as e, type ChallengeCompletionResponse as f, type ChallengeMethod as g, type ChallengeProof as h, type ChallengeRequest as i, type ChallengeResponse as j, type ChallengeRiskTier as k, ChitmarkApiError as l, type ChitmarkEnv as m, ChitmarkError as n, type ChitmarkErrorBody as o, type ChitmarkHttpStatus as p, type ChitmarkOptions as q, type DecisionCosts as r, type FeedbackResponse as s, type Outcome as t, type Principal as u, type VerdictTokenClaims as v, VerdictTokenError as w, type VerdictTokenErrorCode as x, type VerifyVerdictTokenOptions as y, degradedChallengeVerdict as z };