@chitmark/sdk 0.5.2 → 0.6.1

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.
@@ -109,6 +109,8 @@ interface FeedbackRequest {
109
109
  value?: number;
110
110
  unit?: string;
111
111
  observedAt?: string;
112
+ /** Body form of Idempotency-Key; header takes precedence. */
113
+ idempotencyKey?: string;
112
114
  }
113
115
  /** Response from POST /v1/feedback. */
114
116
  interface FeedbackResponse {
@@ -124,8 +126,8 @@ type ChallengeRiskTier = "default" | "elevated" | "severe";
124
126
  interface ChallengeRequest {
125
127
  /** eventId from the verify verdict that routed to challenge. */
126
128
  eventId: string;
127
- /** Binds the challenge to this session; completion and re-verify must match. */
128
- session?: string;
129
+ /** Uniquely represents one action attempt. Required for issue and completion. */
130
+ session: string;
129
131
  /** Ranked method preference, best → worst. Never defaults to email_otp. */
130
132
  prefer?: ChallengeMethod[];
131
133
  /** Completion mode: the challenge being solved. */
@@ -256,10 +258,12 @@ declare function enforceDegradedNeverAllow(verdict: Verdict): Verdict;
256
258
  * Client-side verdictToken verification.
257
259
  *
258
260
  * A verdictToken is an ES256 JWT decision receipt minted by the edge and bound
259
- * to session (`sub`), origin (`aud`), and `jti` with a short `exp`. This module
260
- * validates shape, signature (against the JWKS served from
261
- * GET /.well-known/jwks.json), expiry, session binding, and, when an expected
262
- * audience is supplied, origin binding. Rejection reasons are surfaced as
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
263
267
  * `VerdictTokenError.code`.
264
268
  */
265
269
 
@@ -270,12 +274,14 @@ interface VerdictTokenClaims {
270
274
  confidence: number;
271
275
  aud: string;
272
276
  sub: string;
277
+ /** Issuing tenant, server-derived from the API key used at verify time. */
278
+ tid: string;
273
279
  jti: string;
274
280
  iat: number;
275
281
  exp: number;
276
282
  degraded: boolean;
277
283
  }
278
- type VerdictTokenErrorCode = "malformed_token" | "wrong_algorithm" | "jwks_unavailable" | "unknown_kid" | "invalid_signature" | "expired" | "not_yet_valid" | "wrong_session" | "wrong_aud";
284
+ type VerdictTokenErrorCode = "malformed_token" | "wrong_algorithm" | "jwks_unavailable" | "unknown_kid" | "invalid_signature" | "expired" | "not_yet_valid" | "wrong_session" | "wrong_aud" | "wrong_tenant";
279
285
  declare class VerdictTokenError extends ChitmarkError {
280
286
  name: string;
281
287
  constructor(code: VerdictTokenErrorCode, message: string);
@@ -283,7 +289,9 @@ declare class VerdictTokenError extends ChitmarkError {
283
289
  interface VerifyVerdictTokenOptions {
284
290
  /** Expected session: token `sub` must equal this or verification fails. */
285
291
  session?: string;
286
- /** Expected origin: token `aud` must equal this or verification fails. */
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. */
287
295
  aud?: string;
288
296
  /** JWKS URL; defaults to https://api.chitmark.com/.well-known/jwks.json. */
289
297
  jwksUrl?: string;
@@ -335,6 +343,9 @@ declare class Chitmark {
335
343
  /**
336
344
  * Report a downstream outcome joined on the stored eventId from verify.
337
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.
338
349
  */
339
350
  feedback(request: FeedbackRequest): Promise<FeedbackResponse>;
340
351
  /**
@@ -349,14 +360,15 @@ declare class Chitmark {
349
360
  completeChallenge(request: {
350
361
  eventId: string;
351
362
  challengeId: string;
352
- session?: string;
363
+ session: string;
353
364
  proof: ChallengeProof;
354
365
  }): Promise<ChallengeCompletionResponse>;
355
366
  /**
356
367
  * Verify a verdictToken's signature against the API's JWKS and its session /
357
- * origin binding. Rejects expired tokens, unknown kids, and
358
- * invalid signatures with `VerdictTokenError`. Pass `session` to enforce
359
- * session binding (recommended) and `aud` to enforce origin binding.
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.
360
372
  */
361
373
  verifyVerdictToken(token: string, options?: Omit<VerifyVerdictTokenOptions, "jwksUrl" | "fetch">): Promise<VerdictTokenClaims>;
362
374
  /**
@@ -109,6 +109,8 @@ interface FeedbackRequest {
109
109
  value?: number;
110
110
  unit?: string;
111
111
  observedAt?: string;
112
+ /** Body form of Idempotency-Key; header takes precedence. */
113
+ idempotencyKey?: string;
112
114
  }
113
115
  /** Response from POST /v1/feedback. */
114
116
  interface FeedbackResponse {
@@ -124,8 +126,8 @@ type ChallengeRiskTier = "default" | "elevated" | "severe";
124
126
  interface ChallengeRequest {
125
127
  /** eventId from the verify verdict that routed to challenge. */
126
128
  eventId: string;
127
- /** Binds the challenge to this session; completion and re-verify must match. */
128
- session?: string;
129
+ /** Uniquely represents one action attempt. Required for issue and completion. */
130
+ session: string;
129
131
  /** Ranked method preference, best → worst. Never defaults to email_otp. */
130
132
  prefer?: ChallengeMethod[];
131
133
  /** Completion mode: the challenge being solved. */
@@ -256,10 +258,12 @@ declare function enforceDegradedNeverAllow(verdict: Verdict): Verdict;
256
258
  * Client-side verdictToken verification.
257
259
  *
258
260
  * A verdictToken is an ES256 JWT decision receipt minted by the edge and bound
259
- * to session (`sub`), origin (`aud`), and `jti` with a short `exp`. This module
260
- * validates shape, signature (against the JWKS served from
261
- * GET /.well-known/jwks.json), expiry, session binding, and, when an expected
262
- * audience is supplied, origin binding. Rejection reasons are surfaced as
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
263
267
  * `VerdictTokenError.code`.
264
268
  */
265
269
 
@@ -270,12 +274,14 @@ interface VerdictTokenClaims {
270
274
  confidence: number;
271
275
  aud: string;
272
276
  sub: string;
277
+ /** Issuing tenant, server-derived from the API key used at verify time. */
278
+ tid: string;
273
279
  jti: string;
274
280
  iat: number;
275
281
  exp: number;
276
282
  degraded: boolean;
277
283
  }
278
- type VerdictTokenErrorCode = "malformed_token" | "wrong_algorithm" | "jwks_unavailable" | "unknown_kid" | "invalid_signature" | "expired" | "not_yet_valid" | "wrong_session" | "wrong_aud";
284
+ type VerdictTokenErrorCode = "malformed_token" | "wrong_algorithm" | "jwks_unavailable" | "unknown_kid" | "invalid_signature" | "expired" | "not_yet_valid" | "wrong_session" | "wrong_aud" | "wrong_tenant";
279
285
  declare class VerdictTokenError extends ChitmarkError {
280
286
  name: string;
281
287
  constructor(code: VerdictTokenErrorCode, message: string);
@@ -283,7 +289,9 @@ declare class VerdictTokenError extends ChitmarkError {
283
289
  interface VerifyVerdictTokenOptions {
284
290
  /** Expected session: token `sub` must equal this or verification fails. */
285
291
  session?: string;
286
- /** Expected origin: token `aud` must equal this or verification fails. */
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. */
287
295
  aud?: string;
288
296
  /** JWKS URL; defaults to https://api.chitmark.com/.well-known/jwks.json. */
289
297
  jwksUrl?: string;
@@ -335,6 +343,9 @@ declare class Chitmark {
335
343
  /**
336
344
  * Report a downstream outcome joined on the stored eventId from verify.
337
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.
338
349
  */
339
350
  feedback(request: FeedbackRequest): Promise<FeedbackResponse>;
340
351
  /**
@@ -349,14 +360,15 @@ declare class Chitmark {
349
360
  completeChallenge(request: {
350
361
  eventId: string;
351
362
  challengeId: string;
352
- session?: string;
363
+ session: string;
353
364
  proof: ChallengeProof;
354
365
  }): Promise<ChallengeCompletionResponse>;
355
366
  /**
356
367
  * Verify a verdictToken's signature against the API's JWKS and its session /
357
- * origin binding. Rejects expired tokens, unknown kids, and
358
- * invalid signatures with `VerdictTokenError`. Pass `session` to enforce
359
- * session binding (recommended) and `aud` to enforce origin binding.
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.
360
372
  */
361
373
  verifyVerdictToken(token: string, options?: Omit<VerifyVerdictTokenOptions, "jwksUrl" | "fetch">): Promise<VerdictTokenClaims>;
362
374
  /**
package/dist/index.cjs CHANGED
@@ -61,7 +61,7 @@ var DEFAULT_BASE_URLS = {
61
61
  development: "http://127.0.0.1:8787"
62
62
  };
63
63
  var DEFAULT_TIMEOUT_MS = 800;
64
- var SDK_VERSION = "0.5.1";
64
+ var SDK_VERSION = "0.6.0";
65
65
  function resolveBaseUrl(env = "production", baseUrl) {
66
66
  return (baseUrl ?? DEFAULT_BASE_URLS[env]).replace(/\/$/, "");
67
67
  }
@@ -236,6 +236,13 @@ async function verifyVerdictToken(token, options = {}) {
236
236
  "verdictToken was minted for a different session"
237
237
  );
238
238
  }
239
+ const expectedTenantId = options.tenantId;
240
+ if (expectedTenantId !== void 0 && payload["tid"] !== expectedTenantId) {
241
+ throw new VerdictTokenError(
242
+ "wrong_tenant",
243
+ "verdictToken was minted for a different tenant"
244
+ );
245
+ }
239
246
  const expectedAud = options.aud;
240
247
  if (expectedAud !== void 0 && payload["aud"] !== expectedAud) {
241
248
  throw new VerdictTokenError(
@@ -389,11 +396,15 @@ var Chitmark = class {
389
396
  /**
390
397
  * Report a downstream outcome joined on the stored eventId from verify.
391
398
  * This is the data moat: attribution is a schema contract, not a fuzzy match.
399
+ * `idempotencyKey` is sent as both the Idempotency-Key header and body field
400
+ * (header takes precedence server-side) so exact retries replay the original
401
+ * acknowledgement.
392
402
  */
393
403
  async feedback(request) {
394
404
  return this.request("/v1/feedback", {
395
405
  method: "POST",
396
- body: request
406
+ body: request,
407
+ idempotencyKey: request.idempotencyKey
397
408
  });
398
409
  }
399
410
  /**
@@ -418,9 +429,10 @@ var Chitmark = class {
418
429
  }
419
430
  /**
420
431
  * Verify a verdictToken's signature against the API's JWKS and its session /
421
- * origin binding. Rejects expired tokens, unknown kids, and
422
- * invalid signatures with `VerdictTokenError`. Pass `session` to enforce
423
- * session binding (recommended) and `aud` to enforce origin binding.
432
+ * tenant binding. Rejects expired tokens, unknown kids, and
433
+ * invalid signatures with `VerdictTokenError`. Pass `session` and `tenantId`
434
+ * to enforce session and tenant binding (recommended); `aud` enforces the
435
+ * origin hint only.
424
436
  */
425
437
  async verifyVerdictToken(token, options = {}) {
426
438
  return verifyVerdictToken(token, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/internal/constants.ts","../src/pii.ts","../src/internal/prepare.ts","../src/verify-token.ts","../src/client.ts","../src/http-status.ts","../src/middleware/express.ts","../src/middleware/next.ts"],"names":["out"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ChitmarkErrorBody, Decision, Verdict } from \"./types.js\";\n\n/**\n * Base error for all Chitmark client failures.\n */\nexport class ChitmarkError extends Error {\n override name = \"ChitmarkError\";\n readonly status?: number;\n readonly code?: string;\n readonly body?: ChitmarkErrorBody | string;\n\n constructor(\n message: string,\n options?: { status?: number; code?: string; body?: ChitmarkErrorBody | string },\n ) {\n super(message);\n this.status = options?.status;\n this.code = options?.code;\n this.body = options?.body;\n }\n}\n\n/**\n * Raised when the API returns a non-2xx response.\n */\nexport class ChitmarkApiError extends ChitmarkError {\n override name = \"ChitmarkApiError\";\n\n constructor(status: number, body: ChitmarkErrorBody | string, message?: string) {\n const msg =\n message ??\n (typeof body === \"string\"\n ? body\n : body.message || body.error || `Chitmark API error (${status})`);\n super(msg, {\n status,\n code: typeof body === \"object\" ? (body.code ?? body.error) : undefined,\n body,\n });\n }\n}\n\n/**\n * Build the degraded challenge verdict used on timeout / transport failure.\n * Golden rule: fail to challenge, never to allow.\n */\nexport function degradedChallengeVerdict(reason: string, session?: string): Verdict {\n return {\n decision: \"challenge\" satisfies Decision,\n actorType: \"unknown\",\n confidence: 0,\n reasons: [reason],\n principal: {\n resolved: false,\n identityBasis: [\"degraded\"],\n },\n verdictToken: \"\",\n eventId: `evt_degraded_${session ?? \"unknown\"}`,\n degraded: true,\n enforcementMode: \"enforce\",\n };\n}\n\n/**\n * Ensure degraded responses never surface as allow (defense in depth client-side).\n */\nexport function enforceDegradedNeverAllow(verdict: Verdict): Verdict {\n if (verdict.degraded && verdict.decision === \"allow\") {\n return {\n ...verdict,\n decision: \"challenge\",\n reasons: [\n ...verdict.reasons,\n \"Client enforced: degraded decision must not be allow\",\n ],\n };\n }\n return verdict;\n}\n","import type { ChitmarkEnv } from \"../types.js\";\n\nexport const DEFAULT_BASE_URLS: Record<ChitmarkEnv, string> = {\n production: \"https://api.chitmark.com\",\n staging: \"https://api.staging.chitmark.com\",\n development: \"http://127.0.0.1:8787\",\n};\n\nexport const DEFAULT_TIMEOUT_MS = 800;\n/** Keep in parity with the package version and the Python SDK. */\nexport const SDK_VERSION = \"0.5.1\";\n\nexport function resolveBaseUrl(\n env: ChitmarkEnv = \"production\",\n baseUrl?: string,\n): string {\n return (baseUrl ?? DEFAULT_BASE_URLS[env]).replace(/\\/$/, \"\");\n}\n\n/**\n * CHITMARK_BASE_URL environment override, when present (Node only, no-op on\n * Workers/browsers where `process` is undefined).\n */\nexport function envBaseUrl(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n const value = process.env?.CHITMARK_BASE_URL;\n return value ? value.trim() : undefined;\n}\n","/**\n * Client-side PII minimization helpers.\n * Default SDK mode hashes email and truncates IP before leaving the customer process.\n */\n\n/**\n * SHA-256 hex digest of lowercased, trimmed email.\n * Uses Web Crypto (Node 18+, browsers, Workers).\n */\nexport async function hashEmailSha256(email: string): Promise<string> {\n const normalized = email.trim().toLowerCase();\n const data = new TextEncoder().encode(normalized);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return bufferToHex(digest);\n}\n\n/**\n * Truncate IPv4 to /24 or IPv6 to /48 for coarse geo without host identity.\n */\nexport function truncateIp(ip: string): string {\n const trimmed = ip.trim();\n // IPv4 (optionally from x-forwarded-for first hop)\n const first = trimmed.split(\",\")[0]?.trim() ?? trimmed;\n if (first.includes(\".\") && !first.includes(\":\")) {\n const parts = first.split(\".\");\n if (parts.length === 4) {\n return `${parts[0]}.${parts[1]}.${parts[2]}.0/24`;\n }\n }\n // IPv6: keep first 3 hextets (~/48)\n if (first.includes(\":\")) {\n const hextets = first.split(\":\").filter(Boolean);\n const head = hextets.slice(0, 3).join(\":\");\n return `${head}::/48`;\n }\n return first;\n}\n\n/**\n * Reduce form payload to non-PII keys (domain-style fields only for hashed mode).\n * Free-text is dropped; companyDomain-style keys are kept as-is when domain-like.\n */\nexport function minimizeFormData(\n formData: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!formData) return undefined;\n const allowed = new Set([\n \"companyDomain\",\n \"company_domain\",\n \"domain\",\n \"plan\",\n \"referrer\",\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n ]);\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(formData)) {\n if (allowed.has(key) && value != null) {\n out[key] = value;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction bufferToHex(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let hex = \"\";\n for (const b of bytes) {\n hex += b.toString(16).padStart(2, \"0\");\n }\n return hex;\n}\n","import type { PiiMode, Subject } from \"../types.js\";\nimport { hashEmailSha256, minimizeFormData, truncateIp } from \"../pii.js\";\n\n/**\n * Apply client-side PII mode to a subject before the wire.\n */\nexport async function prepareSubject(\n subject: Subject,\n piiMode: PiiMode,\n): Promise<Subject> {\n if (piiMode === \"raw\") {\n return subject;\n }\n\n if (piiMode === \"none\") {\n return {\n userAgent: subject.userAgent,\n headers: pickWebBotAuthHeaders(subject.headers),\n };\n }\n\n // hashed (default)\n const prepared: Subject = {\n userAgent: subject.userAgent,\n headers: subject.headers,\n };\n\n if (subject.emailSha256) {\n prepared.emailSha256 = subject.emailSha256;\n } else if (subject.email) {\n prepared.emailSha256 = await hashEmailSha256(subject.email);\n }\n\n if (subject.ipTrunc) {\n prepared.ipTrunc = subject.ipTrunc;\n } else if (subject.ip) {\n prepared.ipTrunc = truncateIp(subject.ip);\n }\n\n const hashedForm = subject.formDataHashed ?? minimizeFormData(subject.formData);\n if (hashedForm) {\n prepared.formDataHashed = hashedForm;\n }\n\n return prepared;\n}\n\nfunction pickWebBotAuthHeaders(\n headers?: Record<string, string | string[] | undefined>,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n const keys = [\"signature-agent\", \"signature-input\", \"signature\"];\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(headers)) {\n const lower = k.toLowerCase();\n if (keys.includes(lower) && typeof v === \"string\") {\n out[lower] = v;\n } else if (keys.includes(lower) && Array.isArray(v) && v[0]) {\n out[lower] = v[0];\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Normalize header maps (Node / Fetch) to plain string records for JSON.\n */\nexport function flattenHeaders(\n headers?: Record<string, string | string[] | undefined> | Headers,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n if (headers instanceof Headers) {\n const out: Record<string, string> = {};\n headers.forEach((value, key) => {\n out[key.toLowerCase()] = value;\n });\n return out;\n }\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(headers)) {\n if (typeof v === \"string\") out[k.toLowerCase()] = v;\n else if (Array.isArray(v) && v[0]) out[k.toLowerCase()] = v[0];\n }\n return out;\n}\n","/**\n * Client-side verdictToken verification.\n *\n * A verdictToken is an ES256 JWT decision receipt minted by the edge and bound\n * to session (`sub`), origin (`aud`), and `jti` with a short `exp`. This module\n * validates shape, signature (against the JWKS served from\n * GET /.well-known/jwks.json), expiry, session binding, and, when an expected\n * audience is supplied, origin binding. Rejection reasons are surfaced as\n * `VerdictTokenError.code`.\n */\n\nimport { ChitmarkError } from \"./errors.js\";\nimport type { ActorType, Decision } from \"./types.js\";\n\nexport interface VerdictTokenClaims {\n eventId: string;\n decision: Decision;\n actorType: ActorType;\n confidence: number;\n aud: string;\n sub: string;\n jti: string;\n iat: number;\n exp: number;\n degraded: boolean;\n}\n\nexport type VerdictTokenErrorCode =\n | \"malformed_token\"\n | \"wrong_algorithm\"\n | \"jwks_unavailable\"\n | \"unknown_kid\"\n | \"invalid_signature\"\n | \"expired\"\n | \"not_yet_valid\"\n | \"wrong_session\"\n | \"wrong_aud\";\n\nexport class VerdictTokenError extends ChitmarkError {\n override name = \"VerdictTokenError\";\n\n constructor(code: VerdictTokenErrorCode, message: string) {\n super(message, { code });\n }\n}\n\nexport interface VerifyVerdictTokenOptions {\n /** Expected session: token `sub` must equal this or verification fails. */\n session?: string;\n /** Expected origin: token `aud` must equal this or verification fails. */\n aud?: string;\n /** JWKS URL; defaults to https://api.chitmark.com/.well-known/jwks.json. */\n jwksUrl?: string;\n /** Pre-fetched JWKS; skips the network fetch when provided. */\n jwks?: { keys: Array<Record<string, unknown>> };\n /** Injectable fetch (Node 24+/browsers have a global). */\n fetch?: typeof fetch;\n /** Clock override for tests. */\n nowMs?: number;\n /** Clock skew tolerance in seconds; defaults to 30. */\n leewaySeconds?: number;\n}\n\nconst DEFAULT_JWKS_URL = \"https://api.chitmark.com/.well-known/jwks.json\";\nconst DEFAULT_LEEWAY_SECONDS = 30;\n\nexport async function verifyVerdictToken(\n token: string,\n options: VerifyVerdictTokenOptions = {},\n): Promise<VerdictTokenClaims> {\n const nowMs = options.nowMs ?? Date.now();\n const leewaySeconds = options.leewaySeconds ?? DEFAULT_LEEWAY_SECONDS;\n\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n throw new VerdictTokenError(\"malformed_token\", \"verdictToken must be a JWT\");\n }\n const [headerB64, payloadB64, signatureB64] = parts as [string, string, string];\n\n let header: Record<string, unknown>;\n let payload: Record<string, unknown>;\n try {\n header = JSON.parse(decodeBase64Url(headerB64)) as Record<string, unknown>;\n payload = JSON.parse(decodeBase64Url(payloadB64)) as Record<string, unknown>;\n } catch {\n throw new VerdictTokenError(\"malformed_token\", \"verdictToken is not valid JWT JSON\");\n }\n\n if (header[\"alg\"] !== \"ES256\") {\n throw new VerdictTokenError(\n \"wrong_algorithm\",\n `verdictToken must use ES256, got ${String(header[\"alg\"])}`,\n );\n }\n const kid = typeof header[\"kid\"] === \"string\" ? header[\"kid\"] : \"\";\n if (!kid) {\n throw new VerdictTokenError(\"unknown_kid\", \"verdictToken is missing kid\");\n }\n\n const exp = typeof payload[\"exp\"] === \"number\" ? payload[\"exp\"] : NaN;\n const iat = typeof payload[\"iat\"] === \"number\" ? payload[\"iat\"] : NaN;\n const nowSeconds = Math.floor(nowMs / 1000);\n if (Number.isFinite(exp) && exp < nowSeconds - leewaySeconds) {\n throw new VerdictTokenError(\"expired\", \"verdictToken has expired\");\n }\n if (Number.isFinite(iat) && iat > nowSeconds + leewaySeconds) {\n throw new VerdictTokenError(\"not_yet_valid\", \"verdictToken iat is in the future\");\n }\n\n const expectedSession = options.session;\n if (expectedSession !== undefined && payload[\"sub\"] !== expectedSession) {\n throw new VerdictTokenError(\n \"wrong_session\",\n \"verdictToken was minted for a different session\",\n );\n }\n const expectedAud = options.aud;\n if (expectedAud !== undefined && payload[\"aud\"] !== expectedAud) {\n throw new VerdictTokenError(\n \"wrong_aud\",\n \"verdictToken was minted for a different origin\",\n );\n }\n\n const jwk = await findJwk(kid, options);\n if (!jwk) {\n throw new VerdictTokenError(\"unknown_kid\", `JWKS has no key for kid ${kid}`);\n }\n\n let publicKey: CryptoKey;\n try {\n publicKey = await crypto.subtle.importKey(\n \"jwk\",\n jwk as unknown as JsonWebKey,\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n false,\n [\"verify\"],\n );\n } catch {\n throw new VerdictTokenError(\n \"invalid_signature\",\n \"JWKS key is not a valid P-256 public key\",\n );\n }\n\n const signatureBytes = decodeBase64UrlBytes(signatureB64);\n const signatureBuffer = new ArrayBuffer(signatureBytes.byteLength);\n new Uint8Array(signatureBuffer).set(signatureBytes);\n\n const valid = await crypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n publicKey,\n signatureBuffer,\n new TextEncoder().encode(`${headerB64}.${payloadB64}`),\n );\n if (!valid) {\n throw new VerdictTokenError(\n \"invalid_signature\",\n \"verdictToken signature failed verification\",\n );\n }\n\n return payload as unknown as VerdictTokenClaims;\n}\n\nasync function findJwk(\n kid: string,\n options: VerifyVerdictTokenOptions,\n): Promise<Record<string, unknown> | undefined> {\n let jwks = options.jwks;\n if (!jwks) {\n const jwksUrl = options.jwksUrl ?? DEFAULT_JWKS_URL;\n try {\n const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n const res = await fetchImpl(jwksUrl);\n if (!res.ok) {\n throw new Error(`JWKS fetch failed with ${res.status}`);\n }\n jwks = (await res.json()) as { keys: Array<Record<string, unknown>> };\n } catch (err) {\n throw new VerdictTokenError(\n \"jwks_unavailable\",\n `Failed to load JWKS from ${jwksUrl}: ${\n err instanceof Error ? err.message : \"unknown error\"\n }`,\n );\n }\n }\n if (!Array.isArray(jwks.keys)) {\n throw new VerdictTokenError(\"jwks_unavailable\", \"JWKS response has no keys array\");\n }\n return jwks.keys.find((key) => key[\"kid\"] === kid);\n}\n\nfunction decodeBase64Url(value: string): string {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"=\".repeat((4 - (normalized.length % 4)) % 4);\n const binary = atob(padded);\n return new TextDecoder().decode(Uint8Array.from(binary, (ch) => ch.charCodeAt(0)));\n}\n\nfunction decodeBase64UrlBytes(value: string): Uint8Array {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"=\".repeat((4 - (normalized.length % 4)) % 4);\n const binary = atob(padded);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n}\n","import {\n ChitmarkApiError,\n ChitmarkError,\n degradedChallengeVerdict,\n enforceDegradedNeverAllow,\n} from \"./errors.js\";\nimport {\n DEFAULT_TIMEOUT_MS,\n SDK_VERSION,\n envBaseUrl,\n resolveBaseUrl,\n} from \"./internal/constants.js\";\nimport { flattenHeaders, prepareSubject } from \"./internal/prepare.js\";\nimport {\n verifyVerdictToken,\n type VerdictTokenClaims,\n type VerifyVerdictTokenOptions,\n} from \"./verify-token.js\";\nimport type {\n ChallengeRequest,\n ChallengeResponse,\n ChallengeCompletionResponse,\n ChallengeProof,\n ChitmarkOptions,\n FeedbackRequest,\n FeedbackResponse,\n OnDegraded,\n PiiMode,\n Verdict,\n VerifyRequest,\n} from \"./types.js\";\n\n/**\n * Official Chitmark client (Open Agent Ledger): three verbs:\n * verify, feedback, challenge. Trust decisions on agent-mediated actions,\n * tuned by business outcomes.\n *\n * @example\n * ```ts\n * const chitmark = new Chitmark({ apiKey: process.env.CHITMARK_API_KEY! });\n * const verdict = await chitmark.verify({\n * action: \"signup\",\n * subject: { email, ip, userAgent },\n * });\n * ```\n */\nexport class Chitmark {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly piiMode: PiiMode;\n private readonly onDegraded: OnDegraded;\n private readonly fetchImpl: typeof fetch;\n private readonly clientName: string;\n\n constructor(options: ChitmarkOptions) {\n if (!options.apiKey) {\n throw new ChitmarkError(\"Chitmark apiKey is required\");\n }\n if (options.onDegraded && options.onDegraded !== \"challenge\") {\n throw new ChitmarkError(\n 'onDegraded must be \"challenge\": fail to challenge, never to allow',\n );\n }\n this.apiKey = options.apiKey;\n this.baseUrl = resolveBaseUrl(options.env, options.baseUrl ?? envBaseUrl());\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.piiMode = options.piiMode ?? \"hashed\";\n this.onDegraded = \"challenge\";\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.clientName = options.clientName ?? `chitmark-node/${SDK_VERSION}`;\n }\n\n /**\n * Score + route an inbound action (signup / trial / …).\n * Hot path at the edge; client budget defaults to 800ms.\n * On timeout/transport error, or a malformed verdict shape from the API,\n * returns a degraded challenge verdict (never allow, never crashes).\n *\n * Persist `v.eventId` on the account row: feedback joins only on that id.\n */\n async verify(request: VerifyRequest): Promise<Verdict> {\n const subject = await prepareSubject(\n {\n ...request.subject,\n headers: flattenHeaders(request.subject.headers),\n },\n this.piiMode,\n );\n\n const body: VerifyRequest = {\n ...request,\n subject,\n };\n\n try {\n const verdict = await this.request<Verdict>(\"/v1/verify\", {\n method: \"POST\",\n body,\n idempotencyKey: request.idempotencyKey,\n });\n if (!isWellFormedVerdict(verdict)) {\n return degradedChallengeVerdict(\n \"Degraded: verify returned a malformed verdict shape\",\n request.session,\n );\n }\n return enforceDegradedNeverAllow(verdict);\n } catch (err) {\n if (err instanceof ChitmarkApiError) {\n throw err;\n }\n return degradedChallengeVerdict(\n err instanceof Error ? `Degraded: ${err.message}` : \"Degraded: verify failed\",\n request.session,\n );\n }\n }\n\n /**\n * Report a downstream outcome joined on the stored eventId from verify.\n * This is the data moat: attribution is a schema contract, not a fuzzy match.\n */\n async feedback(request: FeedbackRequest): Promise<FeedbackResponse> {\n return this.request<FeedbackResponse>(\"/v1/feedback\", {\n method: \"POST\",\n body: request,\n });\n }\n\n /**\n * Issue an asymmetric-cost challenge after decision === challenge | degraded.\n */\n async challenge(request: ChallengeRequest): Promise<ChallengeResponse> {\n return this.request<ChallengeResponse>(\"/v1/challenge\", {\n method: \"POST\",\n body: request,\n });\n }\n\n /**\n * Complete a challenge by submitting its solved proof. Clears only the bound\n * session, once. Re-verify with `context.challengeId` to have the next\n * verify honor the cleared session.\n */\n async completeChallenge(request: {\n eventId: string;\n challengeId: string;\n session?: string;\n proof: ChallengeProof;\n }): Promise<ChallengeCompletionResponse> {\n return this.request<ChallengeCompletionResponse>(\"/v1/challenge\", {\n method: \"POST\",\n body: request,\n });\n }\n\n /**\n * Verify a verdictToken's signature against the API's JWKS and its session /\n * origin binding. Rejects expired tokens, unknown kids, and\n * invalid signatures with `VerdictTokenError`. Pass `session` to enforce\n * session binding (recommended) and `aud` to enforce origin binding.\n */\n async verifyVerdictToken(\n token: string,\n options: Omit<VerifyVerdictTokenOptions, \"jwksUrl\" | \"fetch\"> = {},\n ): Promise<VerdictTokenClaims> {\n return verifyVerdictToken(token, {\n ...options,\n jwksUrl: `${this.baseUrl}/.well-known/jwks.json`,\n fetch: this.fetchImpl,\n });\n }\n\n /**\n * Low-level HTTP helper. Prefer verify / feedback / challenge.\n */\n async request<T>(\n path: string,\n init: {\n method: string;\n body?: unknown;\n idempotencyKey?: string;\n },\n ): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"User-Agent\": this.clientName,\n \"X-Chitmark-Client\": this.clientName,\n };\n if (init.idempotencyKey) {\n headers[\"Idempotency-Key\"] = init.idempotencyKey;\n }\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method: init.method,\n headers,\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n\n const text = await res.text();\n let parsed: unknown = undefined;\n if (text) {\n try {\n parsed = JSON.parse(text) as unknown;\n } catch {\n parsed = text;\n }\n }\n\n if (!res.ok) {\n const errBody =\n typeof parsed === \"object\" && parsed !== null\n ? (parsed as { error?: string; message?: string; code?: string })\n : text;\n const normalized =\n typeof errBody === \"string\"\n ? errBody\n : {\n error: errBody.error ?? `http_${res.status}`,\n message: errBody.message,\n code: errBody.code,\n };\n throw new ChitmarkApiError(res.status, normalized);\n }\n\n return parsed as T;\n } catch (err) {\n if (err instanceof ChitmarkApiError) throw err;\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new ChitmarkError(`Request timed out after ${this.timeoutMs}ms`, {\n code: \"timeout\",\n });\n }\n throw err instanceof Error\n ? new ChitmarkError(err.message, { code: \"transport\" })\n : new ChitmarkError(\"Unknown transport error\", { code: \"transport\" });\n } finally {\n clearTimeout(timer);\n }\n }\n\n /** Public accessors for inspection / tests. */\n get config(): {\n baseUrl: string;\n timeoutMs: number;\n piiMode: PiiMode;\n onDegraded: OnDegraded;\n } {\n return {\n baseUrl: this.baseUrl,\n timeoutMs: this.timeoutMs,\n piiMode: this.piiMode,\n onDegraded: this.onDegraded,\n };\n }\n}\n\nconst VERDICT_DECISIONS: ReadonlySet<string> = new Set([\"allow\", \"challenge\", \"deny\"]);\n\n/**\n * Minimal shape guard for a 200 verify response. A malformed verdict must\n * never be treated as allow: the gating fields are what gate correctness.\n */\nexport function isWellFormedVerdict(value: unknown): value is Verdict {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Partial<Verdict>;\n return (\n typeof v.decision === \"string\" &&\n VERDICT_DECISIONS.has(v.decision) &&\n typeof v.eventId === \"string\" &&\n v.eventId.length > 0 &&\n typeof v.degraded === \"boolean\"\n );\n}\n","import type { Verdict } from \"./types.js\";\n\nexport const CHITMARK_HTTP_STATUS = {\n ok: 200,\n created: 201,\n badRequest: 400,\n unauthorized: 401,\n forbidden: 403,\n notFound: 404,\n conflict: 409,\n preconditionRequired: 428,\n tooManyRequests: 429,\n} as const;\n\nexport type ChitmarkHttpStatus =\n (typeof CHITMARK_HTTP_STATUS)[keyof typeof CHITMARK_HTTP_STATUS];\n\nexport const CHITMARK_HTTP_STATUS_MEANING = {\n ok: \"Request succeeded. For verify gates, continue only after an explicit non-degraded allow.\",\n created: \"Resource was created after an explicit non-degraded allow.\",\n badRequest: \"Required request fields are missing or malformed.\",\n unauthorized: \"API key is missing or invalid.\",\n forbidden: \"Verify returned deny; block the action.\",\n notFound: \"Referenced Chitmark resource was not found.\",\n conflict: \"Idempotency key was reused with a materially different payload.\",\n preconditionRequired:\n \"Verify returned challenge or degraded; require friction before continuing.\",\n tooManyRequests: \"Request was rate limited.\",\n} as const satisfies Record<keyof typeof CHITMARK_HTTP_STATUS, string>;\n\nexport function verdictToHttpStatus(verdict: Verdict): ChitmarkHttpStatus {\n if (verdict.degraded || verdict.decision === \"challenge\") {\n return CHITMARK_HTTP_STATUS.preconditionRequired;\n }\n if (verdict.decision === \"deny\") return CHITMARK_HTTP_STATUS.forbidden;\n return CHITMARK_HTTP_STATUS.ok;\n}\n","import type { Chitmark } from \"../client.js\";\nimport { CHITMARK_HTTP_STATUS } from \"../http-status.js\";\nimport type { Action, Verdict } from \"../types.js\";\n\n/**\n * Minimal Express-compatible types (no express dependency).\n */\nexport interface ExpressLikeRequest {\n hostname?: string;\n path?: string;\n ip?: string;\n body?: {\n email?: string;\n [key: string]: unknown;\n };\n headers: Record<string, string | string[] | undefined>;\n}\n\nexport interface ExpressLikeResponse {\n status: (code: number) => ExpressLikeResponse;\n json: (body: unknown) => unknown;\n locals: Record<string, unknown>;\n}\n\nexport type ExpressNext = (err?: unknown) => void;\n\nexport interface GateOptions {\n /** Optional session binder. */\n session?: (req: ExpressLikeRequest) => string | undefined;\n /** Custom surface string. */\n surface?: (req: ExpressLikeRequest) => string;\n}\n\n/**\n * Express middleware factory: verify on the hot path, attach verdict to res.locals.\n *\n * - deny → 403\n * - challenge (incl. degraded) → 428\n * - allow → next()\n *\n * @example\n * ```ts\n * app.post(\"/signup\", chitmarkGate(chitmark, \"signup\"), signupHandler);\n * ```\n */\nexport function chitmarkGate(\n client: Chitmark,\n action: Action,\n options: GateOptions = {},\n): (\n req: ExpressLikeRequest,\n res: ExpressLikeResponse,\n next: ExpressNext,\n) => Promise<void> {\n return async (req, res, next) => {\n try {\n const surface = options.surface?.(req) ?? `${req.hostname ?? \"\"}${req.path ?? \"\"}`;\n const session = options.session?.(req);\n\n const v: Verdict = await client.verify({\n action,\n surface,\n session,\n subject: {\n email: req.body?.email,\n ip: req.ip,\n userAgent:\n (typeof req.headers[\"user-agent\"] === \"string\"\n ? req.headers[\"user-agent\"]\n : undefined) ?? \"\",\n headers: req.headers,\n formData: req.body,\n },\n });\n\n res.locals.chitmark = v;\n\n if (v.degraded || v.decision === \"challenge\") {\n res\n .status(CHITMARK_HTTP_STATUS.preconditionRequired)\n .json({ challenge: true, eventId: v.eventId });\n return;\n }\n if (v.decision === \"deny\") {\n res\n .status(CHITMARK_HTTP_STATUS.forbidden)\n .json({ error: \"blocked\", eventId: v.eventId });\n return;\n }\n next();\n } catch (err) {\n next(err);\n }\n };\n}\n","import type { Chitmark } from \"../client.js\";\nimport type { Action, Verdict } from \"../types.js\";\n\nexport interface NextVerifyOptions {\n action: Action;\n surface?: string;\n session?: string;\n body?: {\n email?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Helper for Next.js App Router route handlers.\n * Returns the verdict; caller maps decision → Response.\n *\n * @example\n * ```ts\n * const v = await verifyNextRequest(chitmark, req, { action: \"signup\", body });\n * const status = verdictToHttpStatus(v);\n * ```\n */\nexport async function verifyNextRequest(\n client: Chitmark,\n req: Request,\n options: NextVerifyOptions,\n): Promise<Verdict> {\n const url = new URL(req.url);\n return client.verify({\n action: options.action,\n surface: options.surface ?? `${url.host}${url.pathname}`,\n session: options.session,\n subject: {\n email: options.body?.email,\n ip: req.headers.get(\"x-forwarded-for\") ?? \"\",\n userAgent: req.headers.get(\"user-agent\") ?? \"\",\n headers: Object.fromEntries(req.headers),\n formData: options.body,\n },\n });\n}\n\nexport { verdictToHttpStatus } from \"../http-status.js\";\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/internal/constants.ts","../src/pii.ts","../src/internal/prepare.ts","../src/verify-token.ts","../src/client.ts","../src/http-status.ts","../src/middleware/express.ts","../src/middleware/next.ts"],"names":["out"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ChitmarkErrorBody, Decision, Verdict } from \"./types.js\";\n\n/**\n * Base error for all Chitmark client failures.\n */\nexport class ChitmarkError extends Error {\n override name = \"ChitmarkError\";\n readonly status?: number;\n readonly code?: string;\n readonly body?: ChitmarkErrorBody | string;\n\n constructor(\n message: string,\n options?: { status?: number; code?: string; body?: ChitmarkErrorBody | string },\n ) {\n super(message);\n this.status = options?.status;\n this.code = options?.code;\n this.body = options?.body;\n }\n}\n\n/**\n * Raised when the API returns a non-2xx response.\n */\nexport class ChitmarkApiError extends ChitmarkError {\n override name = \"ChitmarkApiError\";\n\n constructor(status: number, body: ChitmarkErrorBody | string, message?: string) {\n const msg =\n message ??\n (typeof body === \"string\"\n ? body\n : body.message || body.error || `Chitmark API error (${status})`);\n super(msg, {\n status,\n code: typeof body === \"object\" ? (body.code ?? body.error) : undefined,\n body,\n });\n }\n}\n\n/**\n * Build the degraded challenge verdict used on timeout / transport failure.\n * Golden rule: fail to challenge, never to allow.\n */\nexport function degradedChallengeVerdict(reason: string, session?: string): Verdict {\n return {\n decision: \"challenge\" satisfies Decision,\n actorType: \"unknown\",\n confidence: 0,\n reasons: [reason],\n principal: {\n resolved: false,\n identityBasis: [\"degraded\"],\n },\n verdictToken: \"\",\n eventId: `evt_degraded_${session ?? \"unknown\"}`,\n degraded: true,\n enforcementMode: \"enforce\",\n };\n}\n\n/**\n * Ensure degraded responses never surface as allow (defense in depth client-side).\n */\nexport function enforceDegradedNeverAllow(verdict: Verdict): Verdict {\n if (verdict.degraded && verdict.decision === \"allow\") {\n return {\n ...verdict,\n decision: \"challenge\",\n reasons: [\n ...verdict.reasons,\n \"Client enforced: degraded decision must not be allow\",\n ],\n };\n }\n return verdict;\n}\n","import type { ChitmarkEnv } from \"../types.js\";\n\nexport const DEFAULT_BASE_URLS: Record<ChitmarkEnv, string> = {\n production: \"https://api.chitmark.com\",\n staging: \"https://api.staging.chitmark.com\",\n development: \"http://127.0.0.1:8787\",\n};\n\nexport const DEFAULT_TIMEOUT_MS = 800;\n/** Keep in parity with the package version and the Python SDK. */\nexport const SDK_VERSION = \"0.6.0\";\n\nexport function resolveBaseUrl(\n env: ChitmarkEnv = \"production\",\n baseUrl?: string,\n): string {\n return (baseUrl ?? DEFAULT_BASE_URLS[env]).replace(/\\/$/, \"\");\n}\n\n/**\n * CHITMARK_BASE_URL environment override, when present (Node only, no-op on\n * Workers/browsers where `process` is undefined).\n */\nexport function envBaseUrl(): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n const value = process.env?.CHITMARK_BASE_URL;\n return value ? value.trim() : undefined;\n}\n","/**\n * Client-side PII minimization helpers.\n * Default SDK mode hashes email and truncates IP before leaving the customer process.\n */\n\n/**\n * SHA-256 hex digest of lowercased, trimmed email.\n * Uses Web Crypto (Node 18+, browsers, Workers).\n */\nexport async function hashEmailSha256(email: string): Promise<string> {\n const normalized = email.trim().toLowerCase();\n const data = new TextEncoder().encode(normalized);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return bufferToHex(digest);\n}\n\n/**\n * Truncate IPv4 to /24 or IPv6 to /48 for coarse geo without host identity.\n */\nexport function truncateIp(ip: string): string {\n const trimmed = ip.trim();\n // IPv4 (optionally from x-forwarded-for first hop)\n const first = trimmed.split(\",\")[0]?.trim() ?? trimmed;\n if (first.includes(\".\") && !first.includes(\":\")) {\n const parts = first.split(\".\");\n if (parts.length === 4) {\n return `${parts[0]}.${parts[1]}.${parts[2]}.0/24`;\n }\n }\n // IPv6: keep first 3 hextets (~/48)\n if (first.includes(\":\")) {\n const hextets = first.split(\":\").filter(Boolean);\n const head = hextets.slice(0, 3).join(\":\");\n return `${head}::/48`;\n }\n return first;\n}\n\n/**\n * Reduce form payload to non-PII keys (domain-style fields only for hashed mode).\n * Free-text is dropped; companyDomain-style keys are kept as-is when domain-like.\n */\nexport function minimizeFormData(\n formData: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!formData) return undefined;\n const allowed = new Set([\n \"companyDomain\",\n \"company_domain\",\n \"domain\",\n \"plan\",\n \"referrer\",\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n ]);\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(formData)) {\n if (allowed.has(key) && value != null) {\n out[key] = value;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction bufferToHex(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let hex = \"\";\n for (const b of bytes) {\n hex += b.toString(16).padStart(2, \"0\");\n }\n return hex;\n}\n","import type { PiiMode, Subject } from \"../types.js\";\nimport { hashEmailSha256, minimizeFormData, truncateIp } from \"../pii.js\";\n\n/**\n * Apply client-side PII mode to a subject before the wire.\n */\nexport async function prepareSubject(\n subject: Subject,\n piiMode: PiiMode,\n): Promise<Subject> {\n if (piiMode === \"raw\") {\n return subject;\n }\n\n if (piiMode === \"none\") {\n return {\n userAgent: subject.userAgent,\n headers: pickWebBotAuthHeaders(subject.headers),\n };\n }\n\n // hashed (default)\n const prepared: Subject = {\n userAgent: subject.userAgent,\n headers: subject.headers,\n };\n\n if (subject.emailSha256) {\n prepared.emailSha256 = subject.emailSha256;\n } else if (subject.email) {\n prepared.emailSha256 = await hashEmailSha256(subject.email);\n }\n\n if (subject.ipTrunc) {\n prepared.ipTrunc = subject.ipTrunc;\n } else if (subject.ip) {\n prepared.ipTrunc = truncateIp(subject.ip);\n }\n\n const hashedForm = subject.formDataHashed ?? minimizeFormData(subject.formData);\n if (hashedForm) {\n prepared.formDataHashed = hashedForm;\n }\n\n return prepared;\n}\n\nfunction pickWebBotAuthHeaders(\n headers?: Record<string, string | string[] | undefined>,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n const keys = [\"signature-agent\", \"signature-input\", \"signature\"];\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(headers)) {\n const lower = k.toLowerCase();\n if (keys.includes(lower) && typeof v === \"string\") {\n out[lower] = v;\n } else if (keys.includes(lower) && Array.isArray(v) && v[0]) {\n out[lower] = v[0];\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Normalize header maps (Node / Fetch) to plain string records for JSON.\n */\nexport function flattenHeaders(\n headers?: Record<string, string | string[] | undefined> | Headers,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n if (headers instanceof Headers) {\n const out: Record<string, string> = {};\n headers.forEach((value, key) => {\n out[key.toLowerCase()] = value;\n });\n return out;\n }\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(headers)) {\n if (typeof v === \"string\") out[k.toLowerCase()] = v;\n else if (Array.isArray(v) && v[0]) out[k.toLowerCase()] = v[0];\n }\n return out;\n}\n","/**\n * Client-side verdictToken verification.\n *\n * A verdictToken is an ES256 JWT decision receipt minted by the edge and bound\n * to session (`sub`), origin hint (`aud`), issuing tenant (`tid`), and `jti`\n * with a short `exp`. This module validates shape, signature (against the JWKS\n * served from GET /.well-known/jwks.json), expiry, session binding, and, when\n * expected values are supplied, tenant and origin binding. `aud` reflects\n * request headers and is attacker influenced: always verify `session` and\n * `tenantId`, never `aud` alone. Rejection reasons are surfaced as\n * `VerdictTokenError.code`.\n */\n\nimport { ChitmarkError } from \"./errors.js\";\nimport type { ActorType, Decision } from \"./types.js\";\n\nexport interface VerdictTokenClaims {\n eventId: string;\n decision: Decision;\n actorType: ActorType;\n confidence: number;\n aud: string;\n sub: string;\n /** Issuing tenant, server-derived from the API key used at verify time. */\n tid: string;\n jti: string;\n iat: number;\n exp: number;\n degraded: boolean;\n}\n\nexport type VerdictTokenErrorCode =\n | \"malformed_token\"\n | \"wrong_algorithm\"\n | \"jwks_unavailable\"\n | \"unknown_kid\"\n | \"invalid_signature\"\n | \"expired\"\n | \"not_yet_valid\"\n | \"wrong_session\"\n | \"wrong_aud\"\n | \"wrong_tenant\";\n\nexport class VerdictTokenError extends ChitmarkError {\n override name = \"VerdictTokenError\";\n\n constructor(code: VerdictTokenErrorCode, message: string) {\n super(message, { code });\n }\n}\n\nexport interface VerifyVerdictTokenOptions {\n /** Expected session: token `sub` must equal this or verification fails. */\n session?: string;\n /** Expected issuing tenant: token `tid` must equal this or verification fails. */\n tenantId?: string;\n /** Expected origin hint: token `aud` must equal this or verification fails. */\n aud?: string;\n /** JWKS URL; defaults to https://api.chitmark.com/.well-known/jwks.json. */\n jwksUrl?: string;\n /** Pre-fetched JWKS; skips the network fetch when provided. */\n jwks?: { keys: Array<Record<string, unknown>> };\n /** Injectable fetch (Node 24+/browsers have a global). */\n fetch?: typeof fetch;\n /** Clock override for tests. */\n nowMs?: number;\n /** Clock skew tolerance in seconds; defaults to 30. */\n leewaySeconds?: number;\n}\n\nconst DEFAULT_JWKS_URL = \"https://api.chitmark.com/.well-known/jwks.json\";\nconst DEFAULT_LEEWAY_SECONDS = 30;\n\nexport async function verifyVerdictToken(\n token: string,\n options: VerifyVerdictTokenOptions = {},\n): Promise<VerdictTokenClaims> {\n const nowMs = options.nowMs ?? Date.now();\n const leewaySeconds = options.leewaySeconds ?? DEFAULT_LEEWAY_SECONDS;\n\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n throw new VerdictTokenError(\"malformed_token\", \"verdictToken must be a JWT\");\n }\n const [headerB64, payloadB64, signatureB64] = parts as [string, string, string];\n\n let header: Record<string, unknown>;\n let payload: Record<string, unknown>;\n try {\n header = JSON.parse(decodeBase64Url(headerB64)) as Record<string, unknown>;\n payload = JSON.parse(decodeBase64Url(payloadB64)) as Record<string, unknown>;\n } catch {\n throw new VerdictTokenError(\"malformed_token\", \"verdictToken is not valid JWT JSON\");\n }\n\n if (header[\"alg\"] !== \"ES256\") {\n throw new VerdictTokenError(\n \"wrong_algorithm\",\n `verdictToken must use ES256, got ${String(header[\"alg\"])}`,\n );\n }\n const kid = typeof header[\"kid\"] === \"string\" ? header[\"kid\"] : \"\";\n if (!kid) {\n throw new VerdictTokenError(\"unknown_kid\", \"verdictToken is missing kid\");\n }\n\n const exp = typeof payload[\"exp\"] === \"number\" ? payload[\"exp\"] : NaN;\n const iat = typeof payload[\"iat\"] === \"number\" ? payload[\"iat\"] : NaN;\n const nowSeconds = Math.floor(nowMs / 1000);\n if (Number.isFinite(exp) && exp < nowSeconds - leewaySeconds) {\n throw new VerdictTokenError(\"expired\", \"verdictToken has expired\");\n }\n if (Number.isFinite(iat) && iat > nowSeconds + leewaySeconds) {\n throw new VerdictTokenError(\"not_yet_valid\", \"verdictToken iat is in the future\");\n }\n\n const expectedSession = options.session;\n if (expectedSession !== undefined && payload[\"sub\"] !== expectedSession) {\n throw new VerdictTokenError(\n \"wrong_session\",\n \"verdictToken was minted for a different session\",\n );\n }\n const expectedTenantId = options.tenantId;\n if (expectedTenantId !== undefined && payload[\"tid\"] !== expectedTenantId) {\n throw new VerdictTokenError(\n \"wrong_tenant\",\n \"verdictToken was minted for a different tenant\",\n );\n }\n const expectedAud = options.aud;\n if (expectedAud !== undefined && payload[\"aud\"] !== expectedAud) {\n throw new VerdictTokenError(\n \"wrong_aud\",\n \"verdictToken was minted for a different origin\",\n );\n }\n\n const jwk = await findJwk(kid, options);\n if (!jwk) {\n throw new VerdictTokenError(\"unknown_kid\", `JWKS has no key for kid ${kid}`);\n }\n\n let publicKey: CryptoKey;\n try {\n publicKey = await crypto.subtle.importKey(\n \"jwk\",\n jwk as unknown as JsonWebKey,\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n false,\n [\"verify\"],\n );\n } catch {\n throw new VerdictTokenError(\n \"invalid_signature\",\n \"JWKS key is not a valid P-256 public key\",\n );\n }\n\n const signatureBytes = decodeBase64UrlBytes(signatureB64);\n const signatureBuffer = new ArrayBuffer(signatureBytes.byteLength);\n new Uint8Array(signatureBuffer).set(signatureBytes);\n\n const valid = await crypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n publicKey,\n signatureBuffer,\n new TextEncoder().encode(`${headerB64}.${payloadB64}`),\n );\n if (!valid) {\n throw new VerdictTokenError(\n \"invalid_signature\",\n \"verdictToken signature failed verification\",\n );\n }\n\n return payload as unknown as VerdictTokenClaims;\n}\n\nasync function findJwk(\n kid: string,\n options: VerifyVerdictTokenOptions,\n): Promise<Record<string, unknown> | undefined> {\n let jwks = options.jwks;\n if (!jwks) {\n const jwksUrl = options.jwksUrl ?? DEFAULT_JWKS_URL;\n try {\n const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n const res = await fetchImpl(jwksUrl);\n if (!res.ok) {\n throw new Error(`JWKS fetch failed with ${res.status}`);\n }\n jwks = (await res.json()) as { keys: Array<Record<string, unknown>> };\n } catch (err) {\n throw new VerdictTokenError(\n \"jwks_unavailable\",\n `Failed to load JWKS from ${jwksUrl}: ${\n err instanceof Error ? err.message : \"unknown error\"\n }`,\n );\n }\n }\n if (!Array.isArray(jwks.keys)) {\n throw new VerdictTokenError(\"jwks_unavailable\", \"JWKS response has no keys array\");\n }\n return jwks.keys.find((key) => key[\"kid\"] === kid);\n}\n\nfunction decodeBase64Url(value: string): string {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"=\".repeat((4 - (normalized.length % 4)) % 4);\n const binary = atob(padded);\n return new TextDecoder().decode(Uint8Array.from(binary, (ch) => ch.charCodeAt(0)));\n}\n\nfunction decodeBase64UrlBytes(value: string): Uint8Array {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"=\".repeat((4 - (normalized.length % 4)) % 4);\n const binary = atob(padded);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n}\n","import {\n ChitmarkApiError,\n ChitmarkError,\n degradedChallengeVerdict,\n enforceDegradedNeverAllow,\n} from \"./errors.js\";\nimport {\n DEFAULT_TIMEOUT_MS,\n SDK_VERSION,\n envBaseUrl,\n resolveBaseUrl,\n} from \"./internal/constants.js\";\nimport { flattenHeaders, prepareSubject } from \"./internal/prepare.js\";\nimport {\n verifyVerdictToken,\n type VerdictTokenClaims,\n type VerifyVerdictTokenOptions,\n} from \"./verify-token.js\";\nimport type {\n ChallengeRequest,\n ChallengeResponse,\n ChallengeCompletionResponse,\n ChallengeProof,\n ChitmarkOptions,\n FeedbackRequest,\n FeedbackResponse,\n OnDegraded,\n PiiMode,\n Verdict,\n VerifyRequest,\n} from \"./types.js\";\n\n/**\n * Official Chitmark client (Open Agent Ledger): three verbs:\n * verify, feedback, challenge. Trust decisions on agent-mediated actions,\n * tuned by business outcomes.\n *\n * @example\n * ```ts\n * const chitmark = new Chitmark({ apiKey: process.env.CHITMARK_API_KEY! });\n * const verdict = await chitmark.verify({\n * action: \"signup\",\n * subject: { email, ip, userAgent },\n * });\n * ```\n */\nexport class Chitmark {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly piiMode: PiiMode;\n private readonly onDegraded: OnDegraded;\n private readonly fetchImpl: typeof fetch;\n private readonly clientName: string;\n\n constructor(options: ChitmarkOptions) {\n if (!options.apiKey) {\n throw new ChitmarkError(\"Chitmark apiKey is required\");\n }\n if (options.onDegraded && options.onDegraded !== \"challenge\") {\n throw new ChitmarkError(\n 'onDegraded must be \"challenge\": fail to challenge, never to allow',\n );\n }\n this.apiKey = options.apiKey;\n this.baseUrl = resolveBaseUrl(options.env, options.baseUrl ?? envBaseUrl());\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.piiMode = options.piiMode ?? \"hashed\";\n this.onDegraded = \"challenge\";\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.clientName = options.clientName ?? `chitmark-node/${SDK_VERSION}`;\n }\n\n /**\n * Score + route an inbound action (signup / trial / …).\n * Hot path at the edge; client budget defaults to 800ms.\n * On timeout/transport error, or a malformed verdict shape from the API,\n * returns a degraded challenge verdict (never allow, never crashes).\n *\n * Persist `v.eventId` on the account row: feedback joins only on that id.\n */\n async verify(request: VerifyRequest): Promise<Verdict> {\n const subject = await prepareSubject(\n {\n ...request.subject,\n headers: flattenHeaders(request.subject.headers),\n },\n this.piiMode,\n );\n\n const body: VerifyRequest = {\n ...request,\n subject,\n };\n\n try {\n const verdict = await this.request<Verdict>(\"/v1/verify\", {\n method: \"POST\",\n body,\n idempotencyKey: request.idempotencyKey,\n });\n if (!isWellFormedVerdict(verdict)) {\n return degradedChallengeVerdict(\n \"Degraded: verify returned a malformed verdict shape\",\n request.session,\n );\n }\n return enforceDegradedNeverAllow(verdict);\n } catch (err) {\n if (err instanceof ChitmarkApiError) {\n throw err;\n }\n return degradedChallengeVerdict(\n err instanceof Error ? `Degraded: ${err.message}` : \"Degraded: verify failed\",\n request.session,\n );\n }\n }\n\n /**\n * Report a downstream outcome joined on the stored eventId from verify.\n * This is the data moat: attribution is a schema contract, not a fuzzy match.\n * `idempotencyKey` is sent as both the Idempotency-Key header and body field\n * (header takes precedence server-side) so exact retries replay the original\n * acknowledgement.\n */\n async feedback(request: FeedbackRequest): Promise<FeedbackResponse> {\n return this.request<FeedbackResponse>(\"/v1/feedback\", {\n method: \"POST\",\n body: request,\n idempotencyKey: request.idempotencyKey,\n });\n }\n\n /**\n * Issue an asymmetric-cost challenge after decision === challenge | degraded.\n */\n async challenge(request: ChallengeRequest): Promise<ChallengeResponse> {\n return this.request<ChallengeResponse>(\"/v1/challenge\", {\n method: \"POST\",\n body: request,\n });\n }\n\n /**\n * Complete a challenge by submitting its solved proof. Clears only the bound\n * session, once. Re-verify with `context.challengeId` to have the next\n * verify honor the cleared session.\n */\n async completeChallenge(request: {\n eventId: string;\n challengeId: string;\n session: string;\n proof: ChallengeProof;\n }): Promise<ChallengeCompletionResponse> {\n return this.request<ChallengeCompletionResponse>(\"/v1/challenge\", {\n method: \"POST\",\n body: request,\n });\n }\n\n /**\n * Verify a verdictToken's signature against the API's JWKS and its session /\n * tenant binding. Rejects expired tokens, unknown kids, and\n * invalid signatures with `VerdictTokenError`. Pass `session` and `tenantId`\n * to enforce session and tenant binding (recommended); `aud` enforces the\n * origin hint only.\n */\n async verifyVerdictToken(\n token: string,\n options: Omit<VerifyVerdictTokenOptions, \"jwksUrl\" | \"fetch\"> = {},\n ): Promise<VerdictTokenClaims> {\n return verifyVerdictToken(token, {\n ...options,\n jwksUrl: `${this.baseUrl}/.well-known/jwks.json`,\n fetch: this.fetchImpl,\n });\n }\n\n /**\n * Low-level HTTP helper. Prefer verify / feedback / challenge.\n */\n async request<T>(\n path: string,\n init: {\n method: string;\n body?: unknown;\n idempotencyKey?: string;\n },\n ): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"User-Agent\": this.clientName,\n \"X-Chitmark-Client\": this.clientName,\n };\n if (init.idempotencyKey) {\n headers[\"Idempotency-Key\"] = init.idempotencyKey;\n }\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method: init.method,\n headers,\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n\n const text = await res.text();\n let parsed: unknown = undefined;\n if (text) {\n try {\n parsed = JSON.parse(text) as unknown;\n } catch {\n parsed = text;\n }\n }\n\n if (!res.ok) {\n const errBody =\n typeof parsed === \"object\" && parsed !== null\n ? (parsed as { error?: string; message?: string; code?: string })\n : text;\n const normalized =\n typeof errBody === \"string\"\n ? errBody\n : {\n error: errBody.error ?? `http_${res.status}`,\n message: errBody.message,\n code: errBody.code,\n };\n throw new ChitmarkApiError(res.status, normalized);\n }\n\n return parsed as T;\n } catch (err) {\n if (err instanceof ChitmarkApiError) throw err;\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new ChitmarkError(`Request timed out after ${this.timeoutMs}ms`, {\n code: \"timeout\",\n });\n }\n throw err instanceof Error\n ? new ChitmarkError(err.message, { code: \"transport\" })\n : new ChitmarkError(\"Unknown transport error\", { code: \"transport\" });\n } finally {\n clearTimeout(timer);\n }\n }\n\n /** Public accessors for inspection / tests. */\n get config(): {\n baseUrl: string;\n timeoutMs: number;\n piiMode: PiiMode;\n onDegraded: OnDegraded;\n } {\n return {\n baseUrl: this.baseUrl,\n timeoutMs: this.timeoutMs,\n piiMode: this.piiMode,\n onDegraded: this.onDegraded,\n };\n }\n}\n\nconst VERDICT_DECISIONS: ReadonlySet<string> = new Set([\"allow\", \"challenge\", \"deny\"]);\n\n/**\n * Minimal shape guard for a 200 verify response. A malformed verdict must\n * never be treated as allow: the gating fields are what gate correctness.\n */\nexport function isWellFormedVerdict(value: unknown): value is Verdict {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Partial<Verdict>;\n return (\n typeof v.decision === \"string\" &&\n VERDICT_DECISIONS.has(v.decision) &&\n typeof v.eventId === \"string\" &&\n v.eventId.length > 0 &&\n typeof v.degraded === \"boolean\"\n );\n}\n","import type { Verdict } from \"./types.js\";\n\nexport const CHITMARK_HTTP_STATUS = {\n ok: 200,\n created: 201,\n badRequest: 400,\n unauthorized: 401,\n forbidden: 403,\n notFound: 404,\n conflict: 409,\n preconditionRequired: 428,\n tooManyRequests: 429,\n} as const;\n\nexport type ChitmarkHttpStatus =\n (typeof CHITMARK_HTTP_STATUS)[keyof typeof CHITMARK_HTTP_STATUS];\n\nexport const CHITMARK_HTTP_STATUS_MEANING = {\n ok: \"Request succeeded. For verify gates, continue only after an explicit non-degraded allow.\",\n created: \"Resource was created after an explicit non-degraded allow.\",\n badRequest: \"Required request fields are missing or malformed.\",\n unauthorized: \"API key is missing or invalid.\",\n forbidden: \"Verify returned deny; block the action.\",\n notFound: \"Referenced Chitmark resource was not found.\",\n conflict: \"Idempotency key was reused with a materially different payload.\",\n preconditionRequired:\n \"Verify returned challenge or degraded; require friction before continuing.\",\n tooManyRequests: \"Request was rate limited.\",\n} as const satisfies Record<keyof typeof CHITMARK_HTTP_STATUS, string>;\n\nexport function verdictToHttpStatus(verdict: Verdict): ChitmarkHttpStatus {\n if (verdict.degraded || verdict.decision === \"challenge\") {\n return CHITMARK_HTTP_STATUS.preconditionRequired;\n }\n if (verdict.decision === \"deny\") return CHITMARK_HTTP_STATUS.forbidden;\n return CHITMARK_HTTP_STATUS.ok;\n}\n","import type { Chitmark } from \"../client.js\";\nimport { CHITMARK_HTTP_STATUS } from \"../http-status.js\";\nimport type { Action, Verdict } from \"../types.js\";\n\n/**\n * Minimal Express-compatible types (no express dependency).\n */\nexport interface ExpressLikeRequest {\n hostname?: string;\n path?: string;\n ip?: string;\n body?: {\n email?: string;\n [key: string]: unknown;\n };\n headers: Record<string, string | string[] | undefined>;\n}\n\nexport interface ExpressLikeResponse {\n status: (code: number) => ExpressLikeResponse;\n json: (body: unknown) => unknown;\n locals: Record<string, unknown>;\n}\n\nexport type ExpressNext = (err?: unknown) => void;\n\nexport interface GateOptions {\n /** Optional session binder. */\n session?: (req: ExpressLikeRequest) => string | undefined;\n /** Custom surface string. */\n surface?: (req: ExpressLikeRequest) => string;\n}\n\n/**\n * Express middleware factory: verify on the hot path, attach verdict to res.locals.\n *\n * - deny → 403\n * - challenge (incl. degraded) → 428\n * - allow → next()\n *\n * @example\n * ```ts\n * app.post(\"/signup\", chitmarkGate(chitmark, \"signup\"), signupHandler);\n * ```\n */\nexport function chitmarkGate(\n client: Chitmark,\n action: Action,\n options: GateOptions = {},\n): (\n req: ExpressLikeRequest,\n res: ExpressLikeResponse,\n next: ExpressNext,\n) => Promise<void> {\n return async (req, res, next) => {\n try {\n const surface = options.surface?.(req) ?? `${req.hostname ?? \"\"}${req.path ?? \"\"}`;\n const session = options.session?.(req);\n\n const v: Verdict = await client.verify({\n action,\n surface,\n session,\n subject: {\n email: req.body?.email,\n ip: req.ip,\n userAgent:\n (typeof req.headers[\"user-agent\"] === \"string\"\n ? req.headers[\"user-agent\"]\n : undefined) ?? \"\",\n headers: req.headers,\n formData: req.body,\n },\n });\n\n res.locals.chitmark = v;\n\n if (v.degraded || v.decision === \"challenge\") {\n res\n .status(CHITMARK_HTTP_STATUS.preconditionRequired)\n .json({ challenge: true, eventId: v.eventId });\n return;\n }\n if (v.decision === \"deny\") {\n res\n .status(CHITMARK_HTTP_STATUS.forbidden)\n .json({ error: \"blocked\", eventId: v.eventId });\n return;\n }\n next();\n } catch (err) {\n next(err);\n }\n };\n}\n","import type { Chitmark } from \"../client.js\";\nimport type { Action, Verdict } from \"../types.js\";\n\nexport interface NextVerifyOptions {\n action: Action;\n surface?: string;\n session?: string;\n body?: {\n email?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Helper for Next.js App Router route handlers.\n * Returns the verdict; caller maps decision → Response.\n *\n * @example\n * ```ts\n * const v = await verifyNextRequest(chitmark, req, { action: \"signup\", body });\n * const status = verdictToHttpStatus(v);\n * ```\n */\nexport async function verifyNextRequest(\n client: Chitmark,\n req: Request,\n options: NextVerifyOptions,\n): Promise<Verdict> {\n const url = new URL(req.url);\n return client.verify({\n action: options.action,\n surface: options.surface ?? `${url.host}${url.pathname}`,\n session: options.session,\n subject: {\n email: options.body?.email,\n ip: req.headers.get(\"x-forwarded-for\") ?? \"\",\n userAgent: req.headers.get(\"user-agent\") ?? \"\",\n headers: Object.fromEntries(req.headers),\n formData: options.body,\n },\n });\n}\n\nexport { verdictToHttpStatus } from \"../http-status.js\";\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Chitmark, A as Action, b as Verdict } from './http-status-VNdUBoY5.cjs';
2
- export { c as ActorType, d as CHITMARK_HTTP_STATUS, e as CHITMARK_HTTP_STATUS_MEANING, f as ChallengeCompletionResponse, g as ChallengeMethod, h as ChallengeProof, i as ChallengeRequest, j as ChallengeResponse, k as ChallengeRiskTier, l as ChitmarkApiError, m as ChitmarkEnv, n as ChitmarkError, o as ChitmarkErrorBody, p as ChitmarkHttpStatus, q as ChitmarkOptions, D as Decision, r as DecisionCosts, E as EnforcementMode, F as FeedbackRequest, s as FeedbackResponse, O as OnDegraded, t as Outcome, P as PiiMode, u as Principal, S as Subject, v as VerdictTokenClaims, w as VerdictTokenError, x as VerdictTokenErrorCode, V as VerifyContext, a as VerifyRequest, y as VerifyVerdictTokenOptions, z as degradedChallengeVerdict, B as enforceDegradedNeverAllow, G as hashEmailSha256, H as minimizeFormData, I as truncateIp, J as verdictToHttpStatus, K as verifyVerdictToken } from './http-status-VNdUBoY5.cjs';
1
+ import { C as Chitmark, A as Action, b as Verdict } from './http-status-CYKIa-SM.cjs';
2
+ export { c as ActorType, d as CHITMARK_HTTP_STATUS, e as CHITMARK_HTTP_STATUS_MEANING, f as ChallengeCompletionResponse, g as ChallengeMethod, h as ChallengeProof, i as ChallengeRequest, j as ChallengeResponse, k as ChallengeRiskTier, l as ChitmarkApiError, m as ChitmarkEnv, n as ChitmarkError, o as ChitmarkErrorBody, p as ChitmarkHttpStatus, q as ChitmarkOptions, D as Decision, r as DecisionCosts, E as EnforcementMode, F as FeedbackRequest, s as FeedbackResponse, O as OnDegraded, t as Outcome, P as PiiMode, u as Principal, S as Subject, v as VerdictTokenClaims, w as VerdictTokenError, x as VerdictTokenErrorCode, V as VerifyContext, a as VerifyRequest, y as VerifyVerdictTokenOptions, z as degradedChallengeVerdict, B as enforceDegradedNeverAllow, G as hashEmailSha256, H as minimizeFormData, I as truncateIp, J as verdictToHttpStatus, K as verifyVerdictToken } from './http-status-CYKIa-SM.cjs';
3
3
 
4
4
  /**
5
5
  * Minimal Express-compatible types (no express dependency).
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Chitmark, A as Action, b as Verdict } from './http-status-VNdUBoY5.js';
2
- export { c as ActorType, d as CHITMARK_HTTP_STATUS, e as CHITMARK_HTTP_STATUS_MEANING, f as ChallengeCompletionResponse, g as ChallengeMethod, h as ChallengeProof, i as ChallengeRequest, j as ChallengeResponse, k as ChallengeRiskTier, l as ChitmarkApiError, m as ChitmarkEnv, n as ChitmarkError, o as ChitmarkErrorBody, p as ChitmarkHttpStatus, q as ChitmarkOptions, D as Decision, r as DecisionCosts, E as EnforcementMode, F as FeedbackRequest, s as FeedbackResponse, O as OnDegraded, t as Outcome, P as PiiMode, u as Principal, S as Subject, v as VerdictTokenClaims, w as VerdictTokenError, x as VerdictTokenErrorCode, V as VerifyContext, a as VerifyRequest, y as VerifyVerdictTokenOptions, z as degradedChallengeVerdict, B as enforceDegradedNeverAllow, G as hashEmailSha256, H as minimizeFormData, I as truncateIp, J as verdictToHttpStatus, K as verifyVerdictToken } from './http-status-VNdUBoY5.js';
1
+ import { C as Chitmark, A as Action, b as Verdict } from './http-status-CYKIa-SM.js';
2
+ export { c as ActorType, d as CHITMARK_HTTP_STATUS, e as CHITMARK_HTTP_STATUS_MEANING, f as ChallengeCompletionResponse, g as ChallengeMethod, h as ChallengeProof, i as ChallengeRequest, j as ChallengeResponse, k as ChallengeRiskTier, l as ChitmarkApiError, m as ChitmarkEnv, n as ChitmarkError, o as ChitmarkErrorBody, p as ChitmarkHttpStatus, q as ChitmarkOptions, D as Decision, r as DecisionCosts, E as EnforcementMode, F as FeedbackRequest, s as FeedbackResponse, O as OnDegraded, t as Outcome, P as PiiMode, u as Principal, S as Subject, v as VerdictTokenClaims, w as VerdictTokenError, x as VerdictTokenErrorCode, V as VerifyContext, a as VerifyRequest, y as VerifyVerdictTokenOptions, z as degradedChallengeVerdict, B as enforceDegradedNeverAllow, G as hashEmailSha256, H as minimizeFormData, I as truncateIp, J as verdictToHttpStatus, K as verifyVerdictToken } from './http-status-CYKIa-SM.js';
3
3
 
4
4
  /**
5
5
  * Minimal Express-compatible types (no express dependency).
package/dist/index.js CHANGED
@@ -59,7 +59,7 @@ var DEFAULT_BASE_URLS = {
59
59
  development: "http://127.0.0.1:8787"
60
60
  };
61
61
  var DEFAULT_TIMEOUT_MS = 800;
62
- var SDK_VERSION = "0.5.1";
62
+ var SDK_VERSION = "0.6.0";
63
63
  function resolveBaseUrl(env = "production", baseUrl) {
64
64
  return (baseUrl ?? DEFAULT_BASE_URLS[env]).replace(/\/$/, "");
65
65
  }
@@ -234,6 +234,13 @@ async function verifyVerdictToken(token, options = {}) {
234
234
  "verdictToken was minted for a different session"
235
235
  );
236
236
  }
237
+ const expectedTenantId = options.tenantId;
238
+ if (expectedTenantId !== void 0 && payload["tid"] !== expectedTenantId) {
239
+ throw new VerdictTokenError(
240
+ "wrong_tenant",
241
+ "verdictToken was minted for a different tenant"
242
+ );
243
+ }
237
244
  const expectedAud = options.aud;
238
245
  if (expectedAud !== void 0 && payload["aud"] !== expectedAud) {
239
246
  throw new VerdictTokenError(
@@ -387,11 +394,15 @@ var Chitmark = class {
387
394
  /**
388
395
  * Report a downstream outcome joined on the stored eventId from verify.
389
396
  * This is the data moat: attribution is a schema contract, not a fuzzy match.
397
+ * `idempotencyKey` is sent as both the Idempotency-Key header and body field
398
+ * (header takes precedence server-side) so exact retries replay the original
399
+ * acknowledgement.
390
400
  */
391
401
  async feedback(request) {
392
402
  return this.request("/v1/feedback", {
393
403
  method: "POST",
394
- body: request
404
+ body: request,
405
+ idempotencyKey: request.idempotencyKey
395
406
  });
396
407
  }
397
408
  /**
@@ -416,9 +427,10 @@ var Chitmark = class {
416
427
  }
417
428
  /**
418
429
  * Verify a verdictToken's signature against the API's JWKS and its session /
419
- * origin binding. Rejects expired tokens, unknown kids, and
420
- * invalid signatures with `VerdictTokenError`. Pass `session` to enforce
421
- * session binding (recommended) and `aud` to enforce origin binding.
430
+ * tenant binding. Rejects expired tokens, unknown kids, and
431
+ * invalid signatures with `VerdictTokenError`. Pass `session` and `tenantId`
432
+ * to enforce session and tenant binding (recommended); `aud` enforces the
433
+ * origin hint only.
422
434
  */
423
435
  async verifyVerdictToken(token, options = {}) {
424
436
  return verifyVerdictToken(token, {