@fin-integrity/node 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -394,6 +394,28 @@ var FinIntegrityClient = class {
394
394
  if (this.timer) clearInterval(this.timer);
395
395
  await this.flush();
396
396
  }
397
+ /** Record a deploy marker so reconciliation can attribute a discrepancy spike
398
+ * to the release that caused it. Infrequent; sent directly (not batched).
399
+ * Fail-open — never throws into your deploy pipeline. */
400
+ async recordDeploy(release, opts = {}) {
401
+ try {
402
+ const clean = cleanReleaseLabel(release);
403
+ if (!clean) return;
404
+ const body = { release: clean, source: "sdk" };
405
+ if (opts.environment != null) body.environment = opts.environment;
406
+ if (opts.deployedAt != null) {
407
+ body.deployed_at = opts.deployedAt instanceof Date ? opts.deployedAt.toISOString() : String(opts.deployedAt);
408
+ }
409
+ const res = await fetch(this.endpoint.replace(/\/+$/, "") + "/v1/deploys", {
410
+ method: "POST",
411
+ headers: { "content-type": "application/json", authorization: `Bearer ${this.apiKey}` },
412
+ body: JSON.stringify(body)
413
+ });
414
+ if (!res.ok) throw new Error(`fin-integrity: recordDeploy got ${res.status}`);
415
+ } catch (err) {
416
+ this.onError(err);
417
+ }
418
+ }
397
419
  /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */
398
420
  inspect() {
399
421
  return this.memory ? [...this.memory.sent, ...this.queue] : [...this.queue];
@@ -410,6 +432,12 @@ function toIso(v) {
410
432
  if (!v) return (/* @__PURE__ */ new Date()).toISOString();
411
433
  return v instanceof Date ? v.toISOString() : v;
412
434
  }
435
+ function cleanReleaseLabel(raw) {
436
+ if (typeof raw !== "string") return void 0;
437
+ const v = raw.trim();
438
+ if (!v || v.length > 200 || /[\n\t]/.test(v)) return void 0;
439
+ return v;
440
+ }
413
441
 
414
442
  // src/stripe.ts
415
443
  function instrumentStripe(stripe, fi) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/errors.ts","../src/idempotency.ts","../src/transport.ts","../src/client.ts","../src/stripe.ts"],"sourcesContent":["import { FinIntegrityClient } from \"./client.js\";\nimport type { FinIntegrityConfig } from \"./types.js\";\n\nexport { FinIntegrityClient } from \"./client.js\";\nexport { instrumentStripe } from \"./stripe.js\";\nexport { FinIntegrityError, ConfigError } from \"./errors.js\";\n// Reaches onError whenever a 2xx carries per-event rejections — callers can't\n// branch on an error they have no way to import. Python exports it; parity.\nexport { RejectedEventsError, type RejectedEvent } from \"./transport.js\";\nexport type {\n FinIntegrityConfig,\n RecordInput,\n PayoutInput,\n SubscriptionInput,\n EventEnvelope,\n Money,\n Side,\n EventType,\n WireEventType,\n Direction,\n Transport,\n} from \"./types.js\";\n\nlet current: FinIntegrityClient | undefined;\n\n/** Create and configure the client. Returns it (also stored as the module singleton). */\nexport function init(config?: FinIntegrityConfig): FinIntegrityClient {\n current = new FinIntegrityClient(config);\n return current;\n}\n\n/** The client from the most recent init() — convenient in scripts. */\nexport function getClient(): FinIntegrityClient {\n if (!current) throw new Error(\"fin-integrity: call init() before getClient()\");\n return current;\n}\n","// Sentry-style environment tags, validated the same way the ingest server does\n// (kept in sync by hand — the SDK has no shared dependency on the backend):\n// - trimmed; empty is treated as \"not provided\"\n// - max 64 chars\n// - no whitespace (incl. newlines) or forward slashes\n// - not the literal \"none\" (case-insensitive)\n// Case is otherwise preserved (environments are case-sensitive).\n\nconst MAX_LEN = 64;\nconst INVALID = /[\\s/]/;\n\n/** Returns the cleaned environment, or undefined if absent/invalid (the caller\n * falls back to its default, and ultimately the server defaults to \"production\"). */\nexport function cleanEnvironment(raw: unknown): string | undefined {\n if (typeof raw !== \"string\") return undefined;\n const v = raw.trim();\n if (!v || v.length > MAX_LEN || INVALID.test(v) || v.toLowerCase() === \"none\") return undefined;\n return v;\n}\n","export class FinIntegrityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FinIntegrityError\";\n }\n}\n\n/** Thrown at init() for invalid configuration (fail fast). Runtime capture never throws. */\nexport class ConfigError extends FinIntegrityError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\";\nimport type { EventEnvelope } from \"./types.js\";\n\ntype KeyBasis = Pick<EventEnvelope, \"source\" | \"side\" | \"external_id\" | \"event_type\"> &\n Partial<Pick<EventEnvelope, \"status\" | \"current_period_end\" | \"arrival_at\" | \"environment\">> & {\n amount?: { minor: string };\n };\n\n/**\n * Deterministic content-hash key so a client crash/retry of the *same* underlying\n * fact collapses to one row.\n *\n * The basis is identity + observed state. Identity alone is not enough: the\n * server dedupes on this key and drops the event before it can update anything,\n * so any field that legitimately changes over an entity's life must be in here\n * or the update is silently lost. That bites the states that matter most — a\n * dispute going needs_response -> lost (only `lost` is money out), a\n * subscription renewing into its next period, a payout going pending -> paid.\n *\n * Retry safety is preserved: same fact in the same state = same key = collapsed.\n * A real change produces a new key, reaches the server, and upserts the row.\n */\nexport function deterministicKey(e: KeyBasis): string {\n const basis = [\n e.source,\n e.side,\n e.external_id,\n e.event_type,\n // Environment is part of identity: the same external_id in staging vs\n // production are distinct facts that must not collapse to one row.\n e.environment ?? \"\",\n // Mutable state. Absent fields collapse to \"\" so unused ones cost nothing.\n e.status ?? \"\",\n e.amount?.minor ?? \"\",\n e.current_period_end ?? \"\",\n e.arrival_at ?? \"\",\n ].join(\":\");\n return \"fi_\" + createHash(\"sha256\").update(basis).digest(\"hex\").slice(0, 40);\n}\n\nexport function uuidKey(): string {\n return \"fi_\" + randomUUID();\n}\n","import { FinIntegrityError } from \"./errors.js\";\nimport type { EventEnvelope, Transport } from \"./types.js\";\n\nexport interface HttpTransportOptions {\n endpoint: string;\n apiKey: string;\n retries: number;\n debug: boolean;\n}\n\n/** Batched HTTP transport. Retries 5xx/429/network with backoff; honors Retry-After. */\nexport class HttpTransport implements Transport {\n constructor(private readonly opts: HttpTransportOptions) {}\n\n async send(batch: EventEnvelope[], meta: { dropped: number }): Promise<void> {\n const url = this.opts.endpoint.replace(/\\/+$/, \"\") + \"/v1/events\";\n const body = JSON.stringify({ sent_at: new Date().toISOString(), dropped: meta.dropped, events: batch });\n\n for (let attempt = 0; ; attempt++) {\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${this.opts.apiKey}`,\n \"idempotency-key\": batch[0]?.idempotency_key ?? \"\",\n },\n body,\n });\n } catch (netErr) {\n if (attempt >= this.opts.retries) throw netErr;\n await sleep(backoff(attempt));\n continue;\n }\n\n if (res.ok) {\n // A 200 means the batch was received, NOT that every event was stored:\n // ingest validates per event and reports rejects in the body. Treating\n // 200 as total success hides dropped money events behind a success log.\n const rejected = await rejectedFrom(res);\n if (rejected.length > 0) {\n throw new RejectedEventsError(rejected, batch.length);\n }\n if (this.opts.debug) console.log(`[fin-integrity] delivered ${batch.length} event(s)`);\n return;\n }\n if (res.status === 429 || res.status >= 500) {\n if (attempt >= this.opts.retries) throw new Error(`fin-integrity ingest ${res.status}`);\n const ra = Number(res.headers.get(\"retry-after\"));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n // 4xx — terminal, do not retry\n throw new Error(`fin-integrity ingest ${res.status}: ${await safeText(res)}`);\n }\n }\n}\n\n/** In-memory transport for dryRun and tests. */\nexport class MemoryTransport implements Transport {\n sent: EventEnvelope[] = [];\n async send(batch: EventEnvelope[]): Promise<void> {\n this.sent.push(...batch);\n }\n}\n\nfunction backoff(n: number): number {\n return Math.min(1000 * 2 ** n, 15000) + Math.random() * 250;\n}\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n/** Per-event rejections inside an HTTP 200. Surfaced via onError, never thrown to the caller. */\nexport class RejectedEventsError extends FinIntegrityError {\n constructor(\n readonly rejected: RejectedEvent[],\n readonly batchSize: number,\n ) {\n const detail = rejected.map((r) => `${r.event_id}: ${r.error}`).join(\"; \");\n super(`fin-integrity: ingest rejected ${rejected.length}/${batchSize} event(s) — ${detail}`);\n this.name = \"RejectedEventsError\";\n }\n}\n\nexport interface RejectedEvent {\n event_id: string;\n error: string;\n}\n\n/** Rejected entries from a 200 body. An unparseable body means nothing to report. */\nasync function rejectedFrom(res: Response): Promise<RejectedEvent[]> {\n try {\n const body = (await res.clone().json()) as {\n results?: Array<{ event_id?: string; status?: string; error?: string }>;\n };\n if (!Array.isArray(body?.results)) return [];\n return body.results\n .filter((r) => r?.status === \"rejected\")\n .map((r) => ({ event_id: r.event_id ?? \"unknown\", error: r.error ?? \"unknown error\" }));\n } catch {\n return [];\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text();\n } catch {\n return \"\";\n }\n}\n","import { cleanEnvironment } from \"./environment.js\";\nimport { ConfigError, FinIntegrityError } from \"./errors.js\";\nimport { deterministicKey, uuidKey } from \"./idempotency.js\";\nimport { HttpTransport, MemoryTransport } from \"./transport.js\";\nimport type { EventEnvelope, FinIntegrityConfig, PayoutInput, RecordInput, Side, SubscriptionInput, Transport } from \"./types.js\";\n\nconst DEFAULT_ENDPOINT = \"https://ingest.fin-integrity.com\";\n\nexport class FinIntegrityClient {\n private readonly apiKey: string;\n private readonly endpoint: string;\n private readonly idempotencyMode: \"deterministic\" | \"uuid\";\n private readonly maxSize: number;\n private readonly flushMs: number;\n private readonly maxQueueSize: number;\n private readonly sampleRate: number;\n private readonly environment?: string;\n private readonly beforeSend?: FinIntegrityConfig[\"beforeSend\"];\n private readonly debug: boolean;\n private readonly onError: (err: unknown) => void;\n private readonly transport: Transport;\n private readonly memory?: MemoryTransport;\n\n private queue: EventEnvelope[] = [];\n private dropped = 0;\n private timer?: ReturnType<typeof setInterval>;\n\n /** Capture money-movement observed from a payment processor (Stripe, Adyen, bank, …). */\n readonly processor: {\n record: (input: RecordInput) => void;\n recordPayout: (input: PayoutInput) => void;\n recordSubscription: (input: SubscriptionInput) => void;\n };\n /** Capture entries from your own internal ledger / books. */\n readonly ledger: { record: (input: RecordInput) => void };\n\n constructor(config: FinIntegrityConfig = {}) {\n const dryRun = config.dryRun ?? false;\n const apiKey = config.apiKey ?? process.env.FIN_INTEGRITY_KEY;\n if (!apiKey && !dryRun && !config.transport) {\n throw new ConfigError(\n \"fin-integrity: apiKey is required (pass config.apiKey or set FIN_INTEGRITY_KEY). Use { dryRun: true } to test without a key.\",\n );\n }\n this.apiKey = apiKey ?? \"dry-run\";\n this.endpoint = config.endpoint ?? process.env.FIN_INTEGRITY_ENDPOINT ?? DEFAULT_ENDPOINT;\n this.idempotencyMode = config.idempotency ?? \"deterministic\";\n this.maxSize = config.batch?.maxSize ?? 50;\n this.flushMs = config.batch?.flushMs ?? 2000;\n this.maxQueueSize = config.maxQueueSize ?? 1000;\n this.sampleRate = config.sampleRate ?? 1.0;\n this.environment = cleanEnvironment(config.environment ?? process.env.NODE_ENV);\n this.beforeSend = config.beforeSend;\n this.debug = config.debug ?? false;\n this.onError = config.onError ?? ((e) => { if (this.debug) console.warn(\"[fin-integrity]\", e); });\n\n if (config.transport) {\n this.transport = config.transport;\n } else if (dryRun) {\n this.memory = new MemoryTransport();\n this.transport = this.memory;\n } else {\n this.transport = new HttpTransport({\n endpoint: this.endpoint,\n apiKey: this.apiKey,\n retries: config.retries ?? 3,\n debug: this.debug,\n });\n }\n\n this.processor = {\n record: (input) => this.record(\"processor\", input),\n recordPayout: (input) => this.recordPayout(input),\n recordSubscription: (input) => this.recordSubscription(input),\n };\n this.ledger = { record: (input) => this.record(\"ledger\", input) };\n\n this.timer = setInterval(() => void this.flush(), this.flushMs);\n if (typeof this.timer.unref === \"function\") this.timer.unref();\n\n process.once(\"beforeExit\", () => void this.flush());\n process.once(\"SIGTERM\", () => this.onSigterm());\n }\n\n /**\n * Drain on SIGTERM, then hand the process back its normal fate.\n *\n * Node disables its default terminate-on-SIGTERM as soon as ANY listener is\n * registered, so simply attaching one made this library silently decide that\n * SIGTERM no longer kills the host process — a bare script would ignore\n * `docker stop` and hang until SIGKILL, which is also when the queued events\n * we were trying to protect get dropped anyway.\n *\n * So: flush, then exit ourselves — but only if nothing else is listening. If\n * the app registered its own handler it owns the shutdown sequence, and a\n * library must not exit out from under it. `once` has already removed our own\n * listener by the time this runs, so any remaining count is the app's.\n */\n private onSigterm(): void {\n const appHandlesIt = process.listenerCount(\"SIGTERM\") > 0;\n void this.flush().finally(() => {\n if (!appHandlesIt) process.exit(143); // 128 + SIGTERM(15), the conventional code\n });\n }\n\n /** Low-level escape hatch: capture a fully-specified event (both adapters use this). */\n capture(input: RecordInput & { side: Side }): void {\n this.record(input.side, input);\n }\n\n private record(side: Side, input: RecordInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side,\n source: input.source ?? (side === \"ledger\" ? \"ledger.internal\" : \"custom\"),\n event_type: input.type,\n reference: input.reference,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.fee != null\n ? { fee: { minor: toMinorString(input.fee.minor), currency: input.fee.currency.toLowerCase() } }\n : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.payoutId != null ? { payout_id: input.payoutId } : {}),\n ...(input.subscriptionId != null ? { subscription_id: input.subscriptionId } : {}),\n ...(input.parentExternalId != null ? { parent_external_id: input.parentExternalId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...(input.direction != null ? { direction: input.direction } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open — never throw into the caller\n }\n }\n\n /**\n * Capture a recurring billing container. Not money movement — this is what a\n * charge is expected to arrive in, which is what lets reconciliation catch a\n * billing period that produced no charge at all.\n *\n * Send it whenever the subscription changes (created, renewed, status change)\n * so `currentPeriodEnd` stays current.\n */\n private recordSubscription(input: SubscriptionInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"subscription\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n status: input.status,\n ...(input.interval != null ? { interval: input.interval } : {}),\n ...(input.currentPeriodStart != null ? { current_period_start: toIso(input.currentPeriodStart) } : {}),\n ...(input.currentPeriodEnd != null ? { current_period_end: toIso(input.currentPeriodEnd) } : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Capture a processor payout (processor → bank). Stored separately; links to\n * transactions via their payoutId. */\n private recordPayout(input: PayoutInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"payout\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.arrivalAt != null ? { arrival_at: toIso(input.arrivalAt) } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Per-event override wins over the client default; an invalid value falls back\n * to the default (and, if that's absent too, the server defaults to production). */\n private envFields(perEvent?: string): { environment?: string } {\n const environment = cleanEnvironment(perEvent) ?? this.environment;\n return environment != null ? { environment } : {};\n }\n\n private enqueue(env: EventEnvelope): void {\n if (this.sampleRate < 1 && Math.random() > this.sampleRate) return;\n let out: EventEnvelope | null | undefined = env;\n if (this.beforeSend) out = this.beforeSend(env);\n if (!out) return;\n if (this.queue.length >= this.maxQueueSize) {\n this.queue.shift(); // drop-oldest\n this.dropped++;\n }\n this.queue.push(out);\n if (this.queue.length >= this.maxSize) void this.flush();\n }\n\n /** Send all queued events now. Safe to await (e.g. in a serverless `finally`). */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n const batch = this.queue.splice(0, this.queue.length);\n const dropped = this.dropped;\n this.dropped = 0;\n try {\n await this.transport.send(batch, { dropped });\n } catch (err) {\n this.onError(err); // fail-open: batch is lost, SDK stays alive\n }\n }\n\n /** Drain and stop the client (call before a long-lived process exits). */\n async shutdown(): Promise<void> {\n if (this.timer) clearInterval(this.timer);\n await this.flush();\n }\n\n /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */\n inspect(): EventEnvelope[] {\n return this.memory ? [...this.memory.sent, ...this.queue] : [...this.queue];\n }\n}\n\nfunction toMinorString(m: number | bigint): string {\n if (typeof m === \"bigint\") return m.toString();\n if (!Number.isInteger(m)) {\n throw new FinIntegrityError(`amount.minor must be an integer in minor units, got ${m}`);\n }\n return String(m);\n}\nfunction toIso(v?: string | Date): string {\n if (!v) return new Date().toISOString();\n return v instanceof Date ? v.toISOString() : v;\n}\n","import type { FinIntegrityClient } from \"./client.js\";\nimport type { EventType } from \"./types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Wrap the Stripe client you pass in so `charges.create`, `paymentIntents.create`,\n * and `refunds.create` are captured automatically as fin-integrity processor events.\n *\n * We wrap the exact instance you hand us — no global monkey-patching — so it's\n * predictable and ESM/bundler-safe. Capture runs off the hot path and never blocks\n * or alters your Stripe call. Returns the same (now instrumented) client.\n */\nexport function instrumentStripe<T>(stripe: T, fi: FinIntegrityClient): T {\n const s = stripe as any;\n wrap(s?.charges, \"create\", fi, \"payment\");\n wrap(s?.paymentIntents, \"create\", fi, \"payment\");\n wrap(s?.refunds, \"create\", fi, \"refund\");\n return stripe;\n}\n\nfunction wrap(resource: any, method: string, fi: FinIntegrityClient, type: EventType): void {\n if (!resource || typeof resource[method] !== \"function\") return;\n const original = resource[method];\n if (original.__fiWrapped) return; // idempotent — never double-wrap\n\n const wrapped = async function (this: any, ...args: any[]) {\n const result = await original.apply(this, args); // never block/alter the real call\n queueMicrotask(() => {\n try {\n captureStripe(fi, type, result);\n } catch {\n /* swallowed — must never break the Stripe call path */\n }\n });\n return result;\n };\n wrapped.__fiWrapped = true;\n resource[method] = wrapped;\n}\n\nfunction captureStripe(fi: FinIntegrityClient, type: EventType, obj: any): void {\n if (!obj || typeof obj !== \"object\" || typeof obj.id !== \"string\") return;\n const amount = type === \"refund\" ? obj.amount : obj.amount_received ?? obj.amount;\n const reference =\n obj.metadata?.reference ??\n obj.metadata?.order_id ??\n obj.metadata?.reconciliation_id ??\n (type === \"refund\" ? obj.charge ?? obj.payment_intent ?? obj.id : obj.id);\n\n fi.capture({\n side: \"processor\",\n type,\n source: \"stripe\",\n reference: String(reference),\n external_id: obj.id,\n amount: { minor: typeof amount === \"number\" ? amount : 0, currency: String(obj.currency ?? \"\") },\n ...(obj.status ? { status: String(obj.status) } : {}),\n ...(typeof obj.created === \"number\" ? { occurred_at: new Date(obj.created * 1000) } : {}),\n metadata: { stripe_object: obj.object },\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/errors.ts","../src/idempotency.ts","../src/transport.ts","../src/client.ts","../src/stripe.ts"],"sourcesContent":["import { FinIntegrityClient } from \"./client.js\";\nimport type { FinIntegrityConfig } from \"./types.js\";\n\nexport { FinIntegrityClient } from \"./client.js\";\nexport { instrumentStripe } from \"./stripe.js\";\nexport { FinIntegrityError, ConfigError } from \"./errors.js\";\n// Reaches onError whenever a 2xx carries per-event rejections — callers can't\n// branch on an error they have no way to import. Python exports it; parity.\nexport { RejectedEventsError, type RejectedEvent } from \"./transport.js\";\nexport type {\n FinIntegrityConfig,\n RecordInput,\n PayoutInput,\n SubscriptionInput,\n EventEnvelope,\n Money,\n Side,\n EventType,\n WireEventType,\n Direction,\n Transport,\n} from \"./types.js\";\n\nlet current: FinIntegrityClient | undefined;\n\n/** Create and configure the client. Returns it (also stored as the module singleton). */\nexport function init(config?: FinIntegrityConfig): FinIntegrityClient {\n current = new FinIntegrityClient(config);\n return current;\n}\n\n/** The client from the most recent init() — convenient in scripts. */\nexport function getClient(): FinIntegrityClient {\n if (!current) throw new Error(\"fin-integrity: call init() before getClient()\");\n return current;\n}\n","// Sentry-style environment tags, validated the same way the ingest server does\n// (kept in sync by hand — the SDK has no shared dependency on the backend):\n// - trimmed; empty is treated as \"not provided\"\n// - max 64 chars\n// - no whitespace (incl. newlines) or forward slashes\n// - not the literal \"none\" (case-insensitive)\n// Case is otherwise preserved (environments are case-sensitive).\n\nconst MAX_LEN = 64;\nconst INVALID = /[\\s/]/;\n\n/** Returns the cleaned environment, or undefined if absent/invalid (the caller\n * falls back to its default, and ultimately the server defaults to \"production\"). */\nexport function cleanEnvironment(raw: unknown): string | undefined {\n if (typeof raw !== \"string\") return undefined;\n const v = raw.trim();\n if (!v || v.length > MAX_LEN || INVALID.test(v) || v.toLowerCase() === \"none\") return undefined;\n return v;\n}\n","export class FinIntegrityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FinIntegrityError\";\n }\n}\n\n/** Thrown at init() for invalid configuration (fail fast). Runtime capture never throws. */\nexport class ConfigError extends FinIntegrityError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\";\nimport type { EventEnvelope } from \"./types.js\";\n\ntype KeyBasis = Pick<EventEnvelope, \"source\" | \"side\" | \"external_id\" | \"event_type\"> &\n Partial<Pick<EventEnvelope, \"status\" | \"current_period_end\" | \"arrival_at\" | \"environment\">> & {\n amount?: { minor: string };\n };\n\n/**\n * Deterministic content-hash key so a client crash/retry of the *same* underlying\n * fact collapses to one row.\n *\n * The basis is identity + observed state. Identity alone is not enough: the\n * server dedupes on this key and drops the event before it can update anything,\n * so any field that legitimately changes over an entity's life must be in here\n * or the update is silently lost. That bites the states that matter most — a\n * dispute going needs_response -> lost (only `lost` is money out), a\n * subscription renewing into its next period, a payout going pending -> paid.\n *\n * Retry safety is preserved: same fact in the same state = same key = collapsed.\n * A real change produces a new key, reaches the server, and upserts the row.\n */\nexport function deterministicKey(e: KeyBasis): string {\n const basis = [\n e.source,\n e.side,\n e.external_id,\n e.event_type,\n // Environment is part of identity: the same external_id in staging vs\n // production are distinct facts that must not collapse to one row.\n e.environment ?? \"\",\n // Mutable state. Absent fields collapse to \"\" so unused ones cost nothing.\n e.status ?? \"\",\n e.amount?.minor ?? \"\",\n e.current_period_end ?? \"\",\n e.arrival_at ?? \"\",\n ].join(\":\");\n return \"fi_\" + createHash(\"sha256\").update(basis).digest(\"hex\").slice(0, 40);\n}\n\nexport function uuidKey(): string {\n return \"fi_\" + randomUUID();\n}\n","import { FinIntegrityError } from \"./errors.js\";\nimport type { EventEnvelope, Transport } from \"./types.js\";\n\nexport interface HttpTransportOptions {\n endpoint: string;\n apiKey: string;\n retries: number;\n debug: boolean;\n}\n\n/** Batched HTTP transport. Retries 5xx/429/network with backoff; honors Retry-After. */\nexport class HttpTransport implements Transport {\n constructor(private readonly opts: HttpTransportOptions) {}\n\n async send(batch: EventEnvelope[], meta: { dropped: number }): Promise<void> {\n const url = this.opts.endpoint.replace(/\\/+$/, \"\") + \"/v1/events\";\n const body = JSON.stringify({ sent_at: new Date().toISOString(), dropped: meta.dropped, events: batch });\n\n for (let attempt = 0; ; attempt++) {\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${this.opts.apiKey}`,\n \"idempotency-key\": batch[0]?.idempotency_key ?? \"\",\n },\n body,\n });\n } catch (netErr) {\n if (attempt >= this.opts.retries) throw netErr;\n await sleep(backoff(attempt));\n continue;\n }\n\n if (res.ok) {\n // A 200 means the batch was received, NOT that every event was stored:\n // ingest validates per event and reports rejects in the body. Treating\n // 200 as total success hides dropped money events behind a success log.\n const rejected = await rejectedFrom(res);\n if (rejected.length > 0) {\n throw new RejectedEventsError(rejected, batch.length);\n }\n if (this.opts.debug) console.log(`[fin-integrity] delivered ${batch.length} event(s)`);\n return;\n }\n if (res.status === 429 || res.status >= 500) {\n if (attempt >= this.opts.retries) throw new Error(`fin-integrity ingest ${res.status}`);\n const ra = Number(res.headers.get(\"retry-after\"));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n // 4xx — terminal, do not retry\n throw new Error(`fin-integrity ingest ${res.status}: ${await safeText(res)}`);\n }\n }\n}\n\n/** In-memory transport for dryRun and tests. */\nexport class MemoryTransport implements Transport {\n sent: EventEnvelope[] = [];\n async send(batch: EventEnvelope[]): Promise<void> {\n this.sent.push(...batch);\n }\n}\n\nfunction backoff(n: number): number {\n return Math.min(1000 * 2 ** n, 15000) + Math.random() * 250;\n}\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n/** Per-event rejections inside an HTTP 200. Surfaced via onError, never thrown to the caller. */\nexport class RejectedEventsError extends FinIntegrityError {\n constructor(\n readonly rejected: RejectedEvent[],\n readonly batchSize: number,\n ) {\n const detail = rejected.map((r) => `${r.event_id}: ${r.error}`).join(\"; \");\n super(`fin-integrity: ingest rejected ${rejected.length}/${batchSize} event(s) — ${detail}`);\n this.name = \"RejectedEventsError\";\n }\n}\n\nexport interface RejectedEvent {\n event_id: string;\n error: string;\n}\n\n/** Rejected entries from a 200 body. An unparseable body means nothing to report. */\nasync function rejectedFrom(res: Response): Promise<RejectedEvent[]> {\n try {\n const body = (await res.clone().json()) as {\n results?: Array<{ event_id?: string; status?: string; error?: string }>;\n };\n if (!Array.isArray(body?.results)) return [];\n return body.results\n .filter((r) => r?.status === \"rejected\")\n .map((r) => ({ event_id: r.event_id ?? \"unknown\", error: r.error ?? \"unknown error\" }));\n } catch {\n return [];\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text();\n } catch {\n return \"\";\n }\n}\n","import { cleanEnvironment } from \"./environment.js\";\nimport { ConfigError, FinIntegrityError } from \"./errors.js\";\nimport { deterministicKey, uuidKey } from \"./idempotency.js\";\nimport { HttpTransport, MemoryTransport } from \"./transport.js\";\nimport type { EventEnvelope, FinIntegrityConfig, PayoutInput, RecordInput, Side, SubscriptionInput, Transport } from \"./types.js\";\n\nconst DEFAULT_ENDPOINT = \"https://ingest.fin-integrity.com\";\n\nexport class FinIntegrityClient {\n private readonly apiKey: string;\n private readonly endpoint: string;\n private readonly idempotencyMode: \"deterministic\" | \"uuid\";\n private readonly maxSize: number;\n private readonly flushMs: number;\n private readonly maxQueueSize: number;\n private readonly sampleRate: number;\n private readonly environment?: string;\n private readonly beforeSend?: FinIntegrityConfig[\"beforeSend\"];\n private readonly debug: boolean;\n private readonly onError: (err: unknown) => void;\n private readonly transport: Transport;\n private readonly memory?: MemoryTransport;\n\n private queue: EventEnvelope[] = [];\n private dropped = 0;\n private timer?: ReturnType<typeof setInterval>;\n\n /** Capture money-movement observed from a payment processor (Stripe, Adyen, bank, …). */\n readonly processor: {\n record: (input: RecordInput) => void;\n recordPayout: (input: PayoutInput) => void;\n recordSubscription: (input: SubscriptionInput) => void;\n };\n /** Capture entries from your own internal ledger / books. */\n readonly ledger: { record: (input: RecordInput) => void };\n\n constructor(config: FinIntegrityConfig = {}) {\n const dryRun = config.dryRun ?? false;\n const apiKey = config.apiKey ?? process.env.FIN_INTEGRITY_KEY;\n if (!apiKey && !dryRun && !config.transport) {\n throw new ConfigError(\n \"fin-integrity: apiKey is required (pass config.apiKey or set FIN_INTEGRITY_KEY). Use { dryRun: true } to test without a key.\",\n );\n }\n this.apiKey = apiKey ?? \"dry-run\";\n this.endpoint = config.endpoint ?? process.env.FIN_INTEGRITY_ENDPOINT ?? DEFAULT_ENDPOINT;\n this.idempotencyMode = config.idempotency ?? \"deterministic\";\n this.maxSize = config.batch?.maxSize ?? 50;\n this.flushMs = config.batch?.flushMs ?? 2000;\n this.maxQueueSize = config.maxQueueSize ?? 1000;\n this.sampleRate = config.sampleRate ?? 1.0;\n this.environment = cleanEnvironment(config.environment ?? process.env.NODE_ENV);\n this.beforeSend = config.beforeSend;\n this.debug = config.debug ?? false;\n this.onError = config.onError ?? ((e) => { if (this.debug) console.warn(\"[fin-integrity]\", e); });\n\n if (config.transport) {\n this.transport = config.transport;\n } else if (dryRun) {\n this.memory = new MemoryTransport();\n this.transport = this.memory;\n } else {\n this.transport = new HttpTransport({\n endpoint: this.endpoint,\n apiKey: this.apiKey,\n retries: config.retries ?? 3,\n debug: this.debug,\n });\n }\n\n this.processor = {\n record: (input) => this.record(\"processor\", input),\n recordPayout: (input) => this.recordPayout(input),\n recordSubscription: (input) => this.recordSubscription(input),\n };\n this.ledger = { record: (input) => this.record(\"ledger\", input) };\n\n this.timer = setInterval(() => void this.flush(), this.flushMs);\n if (typeof this.timer.unref === \"function\") this.timer.unref();\n\n process.once(\"beforeExit\", () => void this.flush());\n process.once(\"SIGTERM\", () => this.onSigterm());\n }\n\n /**\n * Drain on SIGTERM, then hand the process back its normal fate.\n *\n * Node disables its default terminate-on-SIGTERM as soon as ANY listener is\n * registered, so simply attaching one made this library silently decide that\n * SIGTERM no longer kills the host process — a bare script would ignore\n * `docker stop` and hang until SIGKILL, which is also when the queued events\n * we were trying to protect get dropped anyway.\n *\n * So: flush, then exit ourselves — but only if nothing else is listening. If\n * the app registered its own handler it owns the shutdown sequence, and a\n * library must not exit out from under it. `once` has already removed our own\n * listener by the time this runs, so any remaining count is the app's.\n */\n private onSigterm(): void {\n const appHandlesIt = process.listenerCount(\"SIGTERM\") > 0;\n void this.flush().finally(() => {\n if (!appHandlesIt) process.exit(143); // 128 + SIGTERM(15), the conventional code\n });\n }\n\n /** Low-level escape hatch: capture a fully-specified event (both adapters use this). */\n capture(input: RecordInput & { side: Side }): void {\n this.record(input.side, input);\n }\n\n private record(side: Side, input: RecordInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side,\n source: input.source ?? (side === \"ledger\" ? \"ledger.internal\" : \"custom\"),\n event_type: input.type,\n reference: input.reference,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.fee != null\n ? { fee: { minor: toMinorString(input.fee.minor), currency: input.fee.currency.toLowerCase() } }\n : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.payoutId != null ? { payout_id: input.payoutId } : {}),\n ...(input.subscriptionId != null ? { subscription_id: input.subscriptionId } : {}),\n ...(input.parentExternalId != null ? { parent_external_id: input.parentExternalId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...(input.direction != null ? { direction: input.direction } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open — never throw into the caller\n }\n }\n\n /**\n * Capture a recurring billing container. Not money movement — this is what a\n * charge is expected to arrive in, which is what lets reconciliation catch a\n * billing period that produced no charge at all.\n *\n * Send it whenever the subscription changes (created, renewed, status change)\n * so `currentPeriodEnd` stays current.\n */\n private recordSubscription(input: SubscriptionInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"subscription\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n status: input.status,\n ...(input.interval != null ? { interval: input.interval } : {}),\n ...(input.currentPeriodStart != null ? { current_period_start: toIso(input.currentPeriodStart) } : {}),\n ...(input.currentPeriodEnd != null ? { current_period_end: toIso(input.currentPeriodEnd) } : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Capture a processor payout (processor → bank). Stored separately; links to\n * transactions via their payoutId. */\n private recordPayout(input: PayoutInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"payout\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.arrivalAt != null ? { arrival_at: toIso(input.arrivalAt) } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Per-event override wins over the client default; an invalid value falls back\n * to the default (and, if that's absent too, the server defaults to production). */\n private envFields(perEvent?: string): { environment?: string } {\n const environment = cleanEnvironment(perEvent) ?? this.environment;\n return environment != null ? { environment } : {};\n }\n\n private enqueue(env: EventEnvelope): void {\n if (this.sampleRate < 1 && Math.random() > this.sampleRate) return;\n let out: EventEnvelope | null | undefined = env;\n if (this.beforeSend) out = this.beforeSend(env);\n if (!out) return;\n if (this.queue.length >= this.maxQueueSize) {\n this.queue.shift(); // drop-oldest\n this.dropped++;\n }\n this.queue.push(out);\n if (this.queue.length >= this.maxSize) void this.flush();\n }\n\n /** Send all queued events now. Safe to await (e.g. in a serverless `finally`). */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n const batch = this.queue.splice(0, this.queue.length);\n const dropped = this.dropped;\n this.dropped = 0;\n try {\n await this.transport.send(batch, { dropped });\n } catch (err) {\n this.onError(err); // fail-open: batch is lost, SDK stays alive\n }\n }\n\n /** Drain and stop the client (call before a long-lived process exits). */\n async shutdown(): Promise<void> {\n if (this.timer) clearInterval(this.timer);\n await this.flush();\n }\n\n /** Record a deploy marker so reconciliation can attribute a discrepancy spike\n * to the release that caused it. Infrequent; sent directly (not batched).\n * Fail-open — never throws into your deploy pipeline. */\n async recordDeploy(\n release: string,\n opts: { environment?: string; deployedAt?: string | Date } = {},\n ): Promise<void> {\n try {\n const clean = cleanReleaseLabel(release);\n if (!clean) return;\n const body: Record<string, unknown> = { release: clean, source: \"sdk\" };\n if (opts.environment != null) body.environment = opts.environment;\n if (opts.deployedAt != null) {\n body.deployed_at = opts.deployedAt instanceof Date ? opts.deployedAt.toISOString() : String(opts.deployedAt);\n }\n const res = await fetch(this.endpoint.replace(/\\/+$/, \"\") + \"/v1/deploys\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${this.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw new Error(`fin-integrity: recordDeploy got ${res.status}`);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */\n inspect(): EventEnvelope[] {\n return this.memory ? [...this.memory.sent, ...this.queue] : [...this.queue];\n }\n}\n\nfunction toMinorString(m: number | bigint): string {\n if (typeof m === \"bigint\") return m.toString();\n if (!Number.isInteger(m)) {\n throw new FinIntegrityError(`amount.minor must be an integer in minor units, got ${m}`);\n }\n return String(m);\n}\nfunction toIso(v?: string | Date): string {\n if (!v) return new Date().toISOString();\n return v instanceof Date ? v.toISOString() : v;\n}\nfunction cleanReleaseLabel(raw: unknown): string | undefined {\n if (typeof raw !== \"string\") return undefined;\n const v = raw.trim();\n if (!v || v.length > 200 || /[\\n\\t]/.test(v)) return undefined;\n return v;\n}\n","import type { FinIntegrityClient } from \"./client.js\";\nimport type { EventType } from \"./types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Wrap the Stripe client you pass in so `charges.create`, `paymentIntents.create`,\n * and `refunds.create` are captured automatically as fin-integrity processor events.\n *\n * We wrap the exact instance you hand us — no global monkey-patching — so it's\n * predictable and ESM/bundler-safe. Capture runs off the hot path and never blocks\n * or alters your Stripe call. Returns the same (now instrumented) client.\n */\nexport function instrumentStripe<T>(stripe: T, fi: FinIntegrityClient): T {\n const s = stripe as any;\n wrap(s?.charges, \"create\", fi, \"payment\");\n wrap(s?.paymentIntents, \"create\", fi, \"payment\");\n wrap(s?.refunds, \"create\", fi, \"refund\");\n return stripe;\n}\n\nfunction wrap(resource: any, method: string, fi: FinIntegrityClient, type: EventType): void {\n if (!resource || typeof resource[method] !== \"function\") return;\n const original = resource[method];\n if (original.__fiWrapped) return; // idempotent — never double-wrap\n\n const wrapped = async function (this: any, ...args: any[]) {\n const result = await original.apply(this, args); // never block/alter the real call\n queueMicrotask(() => {\n try {\n captureStripe(fi, type, result);\n } catch {\n /* swallowed — must never break the Stripe call path */\n }\n });\n return result;\n };\n wrapped.__fiWrapped = true;\n resource[method] = wrapped;\n}\n\nfunction captureStripe(fi: FinIntegrityClient, type: EventType, obj: any): void {\n if (!obj || typeof obj !== \"object\" || typeof obj.id !== \"string\") return;\n const amount = type === \"refund\" ? obj.amount : obj.amount_received ?? obj.amount;\n const reference =\n obj.metadata?.reference ??\n obj.metadata?.order_id ??\n obj.metadata?.reconciliation_id ??\n (type === \"refund\" ? obj.charge ?? obj.payment_intent ?? obj.id : obj.id);\n\n fi.capture({\n side: \"processor\",\n type,\n source: \"stripe\",\n reference: String(reference),\n external_id: obj.id,\n amount: { minor: typeof amount === \"number\" ? amount : 0, currency: String(obj.currency ?? \"\") },\n ...(obj.status ? { status: String(obj.status) } : {}),\n ...(typeof obj.created === \"number\" ? { occurred_at: new Date(obj.created * 1000) } : {}),\n metadata: { stripe_object: obj.object },\n });\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -228,6 +228,13 @@ declare class FinIntegrityClient {
228
228
  flush(): Promise<void>;
229
229
  /** Drain and stop the client (call before a long-lived process exits). */
230
230
  shutdown(): Promise<void>;
231
+ /** Record a deploy marker so reconciliation can attribute a discrepancy spike
232
+ * to the release that caused it. Infrequent; sent directly (not batched).
233
+ * Fail-open — never throws into your deploy pipeline. */
234
+ recordDeploy(release: string, opts?: {
235
+ environment?: string;
236
+ deployedAt?: string | Date;
237
+ }): Promise<void>;
231
238
  /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */
232
239
  inspect(): EventEnvelope[];
233
240
  }
package/dist/index.d.ts CHANGED
@@ -228,6 +228,13 @@ declare class FinIntegrityClient {
228
228
  flush(): Promise<void>;
229
229
  /** Drain and stop the client (call before a long-lived process exits). */
230
230
  shutdown(): Promise<void>;
231
+ /** Record a deploy marker so reconciliation can attribute a discrepancy spike
232
+ * to the release that caused it. Infrequent; sent directly (not batched).
233
+ * Fail-open — never throws into your deploy pipeline. */
234
+ recordDeploy(release: string, opts?: {
235
+ environment?: string;
236
+ deployedAt?: string | Date;
237
+ }): Promise<void>;
231
238
  /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */
232
239
  inspect(): EventEnvelope[];
233
240
  }
package/dist/index.js CHANGED
@@ -362,6 +362,28 @@ var FinIntegrityClient = class {
362
362
  if (this.timer) clearInterval(this.timer);
363
363
  await this.flush();
364
364
  }
365
+ /** Record a deploy marker so reconciliation can attribute a discrepancy spike
366
+ * to the release that caused it. Infrequent; sent directly (not batched).
367
+ * Fail-open — never throws into your deploy pipeline. */
368
+ async recordDeploy(release, opts = {}) {
369
+ try {
370
+ const clean = cleanReleaseLabel(release);
371
+ if (!clean) return;
372
+ const body = { release: clean, source: "sdk" };
373
+ if (opts.environment != null) body.environment = opts.environment;
374
+ if (opts.deployedAt != null) {
375
+ body.deployed_at = opts.deployedAt instanceof Date ? opts.deployedAt.toISOString() : String(opts.deployedAt);
376
+ }
377
+ const res = await fetch(this.endpoint.replace(/\/+$/, "") + "/v1/deploys", {
378
+ method: "POST",
379
+ headers: { "content-type": "application/json", authorization: `Bearer ${this.apiKey}` },
380
+ body: JSON.stringify(body)
381
+ });
382
+ if (!res.ok) throw new Error(`fin-integrity: recordDeploy got ${res.status}`);
383
+ } catch (err) {
384
+ this.onError(err);
385
+ }
386
+ }
365
387
  /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */
366
388
  inspect() {
367
389
  return this.memory ? [...this.memory.sent, ...this.queue] : [...this.queue];
@@ -378,6 +400,12 @@ function toIso(v) {
378
400
  if (!v) return (/* @__PURE__ */ new Date()).toISOString();
379
401
  return v instanceof Date ? v.toISOString() : v;
380
402
  }
403
+ function cleanReleaseLabel(raw) {
404
+ if (typeof raw !== "string") return void 0;
405
+ const v = raw.trim();
406
+ if (!v || v.length > 200 || /[\n\t]/.test(v)) return void 0;
407
+ return v;
408
+ }
381
409
 
382
410
  // src/stripe.ts
383
411
  function instrumentStripe(stripe, fi) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/environment.ts","../src/errors.ts","../src/idempotency.ts","../src/transport.ts","../src/client.ts","../src/stripe.ts","../src/index.ts"],"sourcesContent":["// Sentry-style environment tags, validated the same way the ingest server does\n// (kept in sync by hand — the SDK has no shared dependency on the backend):\n// - trimmed; empty is treated as \"not provided\"\n// - max 64 chars\n// - no whitespace (incl. newlines) or forward slashes\n// - not the literal \"none\" (case-insensitive)\n// Case is otherwise preserved (environments are case-sensitive).\n\nconst MAX_LEN = 64;\nconst INVALID = /[\\s/]/;\n\n/** Returns the cleaned environment, or undefined if absent/invalid (the caller\n * falls back to its default, and ultimately the server defaults to \"production\"). */\nexport function cleanEnvironment(raw: unknown): string | undefined {\n if (typeof raw !== \"string\") return undefined;\n const v = raw.trim();\n if (!v || v.length > MAX_LEN || INVALID.test(v) || v.toLowerCase() === \"none\") return undefined;\n return v;\n}\n","export class FinIntegrityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FinIntegrityError\";\n }\n}\n\n/** Thrown at init() for invalid configuration (fail fast). Runtime capture never throws. */\nexport class ConfigError extends FinIntegrityError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\";\nimport type { EventEnvelope } from \"./types.js\";\n\ntype KeyBasis = Pick<EventEnvelope, \"source\" | \"side\" | \"external_id\" | \"event_type\"> &\n Partial<Pick<EventEnvelope, \"status\" | \"current_period_end\" | \"arrival_at\" | \"environment\">> & {\n amount?: { minor: string };\n };\n\n/**\n * Deterministic content-hash key so a client crash/retry of the *same* underlying\n * fact collapses to one row.\n *\n * The basis is identity + observed state. Identity alone is not enough: the\n * server dedupes on this key and drops the event before it can update anything,\n * so any field that legitimately changes over an entity's life must be in here\n * or the update is silently lost. That bites the states that matter most — a\n * dispute going needs_response -> lost (only `lost` is money out), a\n * subscription renewing into its next period, a payout going pending -> paid.\n *\n * Retry safety is preserved: same fact in the same state = same key = collapsed.\n * A real change produces a new key, reaches the server, and upserts the row.\n */\nexport function deterministicKey(e: KeyBasis): string {\n const basis = [\n e.source,\n e.side,\n e.external_id,\n e.event_type,\n // Environment is part of identity: the same external_id in staging vs\n // production are distinct facts that must not collapse to one row.\n e.environment ?? \"\",\n // Mutable state. Absent fields collapse to \"\" so unused ones cost nothing.\n e.status ?? \"\",\n e.amount?.minor ?? \"\",\n e.current_period_end ?? \"\",\n e.arrival_at ?? \"\",\n ].join(\":\");\n return \"fi_\" + createHash(\"sha256\").update(basis).digest(\"hex\").slice(0, 40);\n}\n\nexport function uuidKey(): string {\n return \"fi_\" + randomUUID();\n}\n","import { FinIntegrityError } from \"./errors.js\";\nimport type { EventEnvelope, Transport } from \"./types.js\";\n\nexport interface HttpTransportOptions {\n endpoint: string;\n apiKey: string;\n retries: number;\n debug: boolean;\n}\n\n/** Batched HTTP transport. Retries 5xx/429/network with backoff; honors Retry-After. */\nexport class HttpTransport implements Transport {\n constructor(private readonly opts: HttpTransportOptions) {}\n\n async send(batch: EventEnvelope[], meta: { dropped: number }): Promise<void> {\n const url = this.opts.endpoint.replace(/\\/+$/, \"\") + \"/v1/events\";\n const body = JSON.stringify({ sent_at: new Date().toISOString(), dropped: meta.dropped, events: batch });\n\n for (let attempt = 0; ; attempt++) {\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${this.opts.apiKey}`,\n \"idempotency-key\": batch[0]?.idempotency_key ?? \"\",\n },\n body,\n });\n } catch (netErr) {\n if (attempt >= this.opts.retries) throw netErr;\n await sleep(backoff(attempt));\n continue;\n }\n\n if (res.ok) {\n // A 200 means the batch was received, NOT that every event was stored:\n // ingest validates per event and reports rejects in the body. Treating\n // 200 as total success hides dropped money events behind a success log.\n const rejected = await rejectedFrom(res);\n if (rejected.length > 0) {\n throw new RejectedEventsError(rejected, batch.length);\n }\n if (this.opts.debug) console.log(`[fin-integrity] delivered ${batch.length} event(s)`);\n return;\n }\n if (res.status === 429 || res.status >= 500) {\n if (attempt >= this.opts.retries) throw new Error(`fin-integrity ingest ${res.status}`);\n const ra = Number(res.headers.get(\"retry-after\"));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n // 4xx — terminal, do not retry\n throw new Error(`fin-integrity ingest ${res.status}: ${await safeText(res)}`);\n }\n }\n}\n\n/** In-memory transport for dryRun and tests. */\nexport class MemoryTransport implements Transport {\n sent: EventEnvelope[] = [];\n async send(batch: EventEnvelope[]): Promise<void> {\n this.sent.push(...batch);\n }\n}\n\nfunction backoff(n: number): number {\n return Math.min(1000 * 2 ** n, 15000) + Math.random() * 250;\n}\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n/** Per-event rejections inside an HTTP 200. Surfaced via onError, never thrown to the caller. */\nexport class RejectedEventsError extends FinIntegrityError {\n constructor(\n readonly rejected: RejectedEvent[],\n readonly batchSize: number,\n ) {\n const detail = rejected.map((r) => `${r.event_id}: ${r.error}`).join(\"; \");\n super(`fin-integrity: ingest rejected ${rejected.length}/${batchSize} event(s) — ${detail}`);\n this.name = \"RejectedEventsError\";\n }\n}\n\nexport interface RejectedEvent {\n event_id: string;\n error: string;\n}\n\n/** Rejected entries from a 200 body. An unparseable body means nothing to report. */\nasync function rejectedFrom(res: Response): Promise<RejectedEvent[]> {\n try {\n const body = (await res.clone().json()) as {\n results?: Array<{ event_id?: string; status?: string; error?: string }>;\n };\n if (!Array.isArray(body?.results)) return [];\n return body.results\n .filter((r) => r?.status === \"rejected\")\n .map((r) => ({ event_id: r.event_id ?? \"unknown\", error: r.error ?? \"unknown error\" }));\n } catch {\n return [];\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text();\n } catch {\n return \"\";\n }\n}\n","import { cleanEnvironment } from \"./environment.js\";\nimport { ConfigError, FinIntegrityError } from \"./errors.js\";\nimport { deterministicKey, uuidKey } from \"./idempotency.js\";\nimport { HttpTransport, MemoryTransport } from \"./transport.js\";\nimport type { EventEnvelope, FinIntegrityConfig, PayoutInput, RecordInput, Side, SubscriptionInput, Transport } from \"./types.js\";\n\nconst DEFAULT_ENDPOINT = \"https://ingest.fin-integrity.com\";\n\nexport class FinIntegrityClient {\n private readonly apiKey: string;\n private readonly endpoint: string;\n private readonly idempotencyMode: \"deterministic\" | \"uuid\";\n private readonly maxSize: number;\n private readonly flushMs: number;\n private readonly maxQueueSize: number;\n private readonly sampleRate: number;\n private readonly environment?: string;\n private readonly beforeSend?: FinIntegrityConfig[\"beforeSend\"];\n private readonly debug: boolean;\n private readonly onError: (err: unknown) => void;\n private readonly transport: Transport;\n private readonly memory?: MemoryTransport;\n\n private queue: EventEnvelope[] = [];\n private dropped = 0;\n private timer?: ReturnType<typeof setInterval>;\n\n /** Capture money-movement observed from a payment processor (Stripe, Adyen, bank, …). */\n readonly processor: {\n record: (input: RecordInput) => void;\n recordPayout: (input: PayoutInput) => void;\n recordSubscription: (input: SubscriptionInput) => void;\n };\n /** Capture entries from your own internal ledger / books. */\n readonly ledger: { record: (input: RecordInput) => void };\n\n constructor(config: FinIntegrityConfig = {}) {\n const dryRun = config.dryRun ?? false;\n const apiKey = config.apiKey ?? process.env.FIN_INTEGRITY_KEY;\n if (!apiKey && !dryRun && !config.transport) {\n throw new ConfigError(\n \"fin-integrity: apiKey is required (pass config.apiKey or set FIN_INTEGRITY_KEY). Use { dryRun: true } to test without a key.\",\n );\n }\n this.apiKey = apiKey ?? \"dry-run\";\n this.endpoint = config.endpoint ?? process.env.FIN_INTEGRITY_ENDPOINT ?? DEFAULT_ENDPOINT;\n this.idempotencyMode = config.idempotency ?? \"deterministic\";\n this.maxSize = config.batch?.maxSize ?? 50;\n this.flushMs = config.batch?.flushMs ?? 2000;\n this.maxQueueSize = config.maxQueueSize ?? 1000;\n this.sampleRate = config.sampleRate ?? 1.0;\n this.environment = cleanEnvironment(config.environment ?? process.env.NODE_ENV);\n this.beforeSend = config.beforeSend;\n this.debug = config.debug ?? false;\n this.onError = config.onError ?? ((e) => { if (this.debug) console.warn(\"[fin-integrity]\", e); });\n\n if (config.transport) {\n this.transport = config.transport;\n } else if (dryRun) {\n this.memory = new MemoryTransport();\n this.transport = this.memory;\n } else {\n this.transport = new HttpTransport({\n endpoint: this.endpoint,\n apiKey: this.apiKey,\n retries: config.retries ?? 3,\n debug: this.debug,\n });\n }\n\n this.processor = {\n record: (input) => this.record(\"processor\", input),\n recordPayout: (input) => this.recordPayout(input),\n recordSubscription: (input) => this.recordSubscription(input),\n };\n this.ledger = { record: (input) => this.record(\"ledger\", input) };\n\n this.timer = setInterval(() => void this.flush(), this.flushMs);\n if (typeof this.timer.unref === \"function\") this.timer.unref();\n\n process.once(\"beforeExit\", () => void this.flush());\n process.once(\"SIGTERM\", () => this.onSigterm());\n }\n\n /**\n * Drain on SIGTERM, then hand the process back its normal fate.\n *\n * Node disables its default terminate-on-SIGTERM as soon as ANY listener is\n * registered, so simply attaching one made this library silently decide that\n * SIGTERM no longer kills the host process — a bare script would ignore\n * `docker stop` and hang until SIGKILL, which is also when the queued events\n * we were trying to protect get dropped anyway.\n *\n * So: flush, then exit ourselves — but only if nothing else is listening. If\n * the app registered its own handler it owns the shutdown sequence, and a\n * library must not exit out from under it. `once` has already removed our own\n * listener by the time this runs, so any remaining count is the app's.\n */\n private onSigterm(): void {\n const appHandlesIt = process.listenerCount(\"SIGTERM\") > 0;\n void this.flush().finally(() => {\n if (!appHandlesIt) process.exit(143); // 128 + SIGTERM(15), the conventional code\n });\n }\n\n /** Low-level escape hatch: capture a fully-specified event (both adapters use this). */\n capture(input: RecordInput & { side: Side }): void {\n this.record(input.side, input);\n }\n\n private record(side: Side, input: RecordInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side,\n source: input.source ?? (side === \"ledger\" ? \"ledger.internal\" : \"custom\"),\n event_type: input.type,\n reference: input.reference,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.fee != null\n ? { fee: { minor: toMinorString(input.fee.minor), currency: input.fee.currency.toLowerCase() } }\n : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.payoutId != null ? { payout_id: input.payoutId } : {}),\n ...(input.subscriptionId != null ? { subscription_id: input.subscriptionId } : {}),\n ...(input.parentExternalId != null ? { parent_external_id: input.parentExternalId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...(input.direction != null ? { direction: input.direction } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open — never throw into the caller\n }\n }\n\n /**\n * Capture a recurring billing container. Not money movement — this is what a\n * charge is expected to arrive in, which is what lets reconciliation catch a\n * billing period that produced no charge at all.\n *\n * Send it whenever the subscription changes (created, renewed, status change)\n * so `currentPeriodEnd` stays current.\n */\n private recordSubscription(input: SubscriptionInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"subscription\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n status: input.status,\n ...(input.interval != null ? { interval: input.interval } : {}),\n ...(input.currentPeriodStart != null ? { current_period_start: toIso(input.currentPeriodStart) } : {}),\n ...(input.currentPeriodEnd != null ? { current_period_end: toIso(input.currentPeriodEnd) } : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Capture a processor payout (processor → bank). Stored separately; links to\n * transactions via their payoutId. */\n private recordPayout(input: PayoutInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"payout\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.arrivalAt != null ? { arrival_at: toIso(input.arrivalAt) } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Per-event override wins over the client default; an invalid value falls back\n * to the default (and, if that's absent too, the server defaults to production). */\n private envFields(perEvent?: string): { environment?: string } {\n const environment = cleanEnvironment(perEvent) ?? this.environment;\n return environment != null ? { environment } : {};\n }\n\n private enqueue(env: EventEnvelope): void {\n if (this.sampleRate < 1 && Math.random() > this.sampleRate) return;\n let out: EventEnvelope | null | undefined = env;\n if (this.beforeSend) out = this.beforeSend(env);\n if (!out) return;\n if (this.queue.length >= this.maxQueueSize) {\n this.queue.shift(); // drop-oldest\n this.dropped++;\n }\n this.queue.push(out);\n if (this.queue.length >= this.maxSize) void this.flush();\n }\n\n /** Send all queued events now. Safe to await (e.g. in a serverless `finally`). */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n const batch = this.queue.splice(0, this.queue.length);\n const dropped = this.dropped;\n this.dropped = 0;\n try {\n await this.transport.send(batch, { dropped });\n } catch (err) {\n this.onError(err); // fail-open: batch is lost, SDK stays alive\n }\n }\n\n /** Drain and stop the client (call before a long-lived process exits). */\n async shutdown(): Promise<void> {\n if (this.timer) clearInterval(this.timer);\n await this.flush();\n }\n\n /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */\n inspect(): EventEnvelope[] {\n return this.memory ? [...this.memory.sent, ...this.queue] : [...this.queue];\n }\n}\n\nfunction toMinorString(m: number | bigint): string {\n if (typeof m === \"bigint\") return m.toString();\n if (!Number.isInteger(m)) {\n throw new FinIntegrityError(`amount.minor must be an integer in minor units, got ${m}`);\n }\n return String(m);\n}\nfunction toIso(v?: string | Date): string {\n if (!v) return new Date().toISOString();\n return v instanceof Date ? v.toISOString() : v;\n}\n","import type { FinIntegrityClient } from \"./client.js\";\nimport type { EventType } from \"./types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Wrap the Stripe client you pass in so `charges.create`, `paymentIntents.create`,\n * and `refunds.create` are captured automatically as fin-integrity processor events.\n *\n * We wrap the exact instance you hand us — no global monkey-patching — so it's\n * predictable and ESM/bundler-safe. Capture runs off the hot path and never blocks\n * or alters your Stripe call. Returns the same (now instrumented) client.\n */\nexport function instrumentStripe<T>(stripe: T, fi: FinIntegrityClient): T {\n const s = stripe as any;\n wrap(s?.charges, \"create\", fi, \"payment\");\n wrap(s?.paymentIntents, \"create\", fi, \"payment\");\n wrap(s?.refunds, \"create\", fi, \"refund\");\n return stripe;\n}\n\nfunction wrap(resource: any, method: string, fi: FinIntegrityClient, type: EventType): void {\n if (!resource || typeof resource[method] !== \"function\") return;\n const original = resource[method];\n if (original.__fiWrapped) return; // idempotent — never double-wrap\n\n const wrapped = async function (this: any, ...args: any[]) {\n const result = await original.apply(this, args); // never block/alter the real call\n queueMicrotask(() => {\n try {\n captureStripe(fi, type, result);\n } catch {\n /* swallowed — must never break the Stripe call path */\n }\n });\n return result;\n };\n wrapped.__fiWrapped = true;\n resource[method] = wrapped;\n}\n\nfunction captureStripe(fi: FinIntegrityClient, type: EventType, obj: any): void {\n if (!obj || typeof obj !== \"object\" || typeof obj.id !== \"string\") return;\n const amount = type === \"refund\" ? obj.amount : obj.amount_received ?? obj.amount;\n const reference =\n obj.metadata?.reference ??\n obj.metadata?.order_id ??\n obj.metadata?.reconciliation_id ??\n (type === \"refund\" ? obj.charge ?? obj.payment_intent ?? obj.id : obj.id);\n\n fi.capture({\n side: \"processor\",\n type,\n source: \"stripe\",\n reference: String(reference),\n external_id: obj.id,\n amount: { minor: typeof amount === \"number\" ? amount : 0, currency: String(obj.currency ?? \"\") },\n ...(obj.status ? { status: String(obj.status) } : {}),\n ...(typeof obj.created === \"number\" ? { occurred_at: new Date(obj.created * 1000) } : {}),\n metadata: { stripe_object: obj.object },\n });\n}\n","import { FinIntegrityClient } from \"./client.js\";\nimport type { FinIntegrityConfig } from \"./types.js\";\n\nexport { FinIntegrityClient } from \"./client.js\";\nexport { instrumentStripe } from \"./stripe.js\";\nexport { FinIntegrityError, ConfigError } from \"./errors.js\";\n// Reaches onError whenever a 2xx carries per-event rejections — callers can't\n// branch on an error they have no way to import. Python exports it; parity.\nexport { RejectedEventsError, type RejectedEvent } from \"./transport.js\";\nexport type {\n FinIntegrityConfig,\n RecordInput,\n PayoutInput,\n SubscriptionInput,\n EventEnvelope,\n Money,\n Side,\n EventType,\n WireEventType,\n Direction,\n Transport,\n} from \"./types.js\";\n\nlet current: FinIntegrityClient | undefined;\n\n/** Create and configure the client. Returns it (also stored as the module singleton). */\nexport function init(config?: FinIntegrityConfig): FinIntegrityClient {\n current = new FinIntegrityClient(config);\n return current;\n}\n\n/** The client from the most recent init() — convenient in scripts. */\nexport function getClient(): FinIntegrityClient {\n if (!current) throw new Error(\"fin-integrity: call init() before getClient()\");\n return current;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/environment.ts","../src/errors.ts","../src/idempotency.ts","../src/transport.ts","../src/client.ts","../src/stripe.ts","../src/index.ts"],"sourcesContent":["// Sentry-style environment tags, validated the same way the ingest server does\n// (kept in sync by hand — the SDK has no shared dependency on the backend):\n// - trimmed; empty is treated as \"not provided\"\n// - max 64 chars\n// - no whitespace (incl. newlines) or forward slashes\n// - not the literal \"none\" (case-insensitive)\n// Case is otherwise preserved (environments are case-sensitive).\n\nconst MAX_LEN = 64;\nconst INVALID = /[\\s/]/;\n\n/** Returns the cleaned environment, or undefined if absent/invalid (the caller\n * falls back to its default, and ultimately the server defaults to \"production\"). */\nexport function cleanEnvironment(raw: unknown): string | undefined {\n if (typeof raw !== \"string\") return undefined;\n const v = raw.trim();\n if (!v || v.length > MAX_LEN || INVALID.test(v) || v.toLowerCase() === \"none\") return undefined;\n return v;\n}\n","export class FinIntegrityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FinIntegrityError\";\n }\n}\n\n/** Thrown at init() for invalid configuration (fail fast). Runtime capture never throws. */\nexport class ConfigError extends FinIntegrityError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\";\nimport type { EventEnvelope } from \"./types.js\";\n\ntype KeyBasis = Pick<EventEnvelope, \"source\" | \"side\" | \"external_id\" | \"event_type\"> &\n Partial<Pick<EventEnvelope, \"status\" | \"current_period_end\" | \"arrival_at\" | \"environment\">> & {\n amount?: { minor: string };\n };\n\n/**\n * Deterministic content-hash key so a client crash/retry of the *same* underlying\n * fact collapses to one row.\n *\n * The basis is identity + observed state. Identity alone is not enough: the\n * server dedupes on this key and drops the event before it can update anything,\n * so any field that legitimately changes over an entity's life must be in here\n * or the update is silently lost. That bites the states that matter most — a\n * dispute going needs_response -> lost (only `lost` is money out), a\n * subscription renewing into its next period, a payout going pending -> paid.\n *\n * Retry safety is preserved: same fact in the same state = same key = collapsed.\n * A real change produces a new key, reaches the server, and upserts the row.\n */\nexport function deterministicKey(e: KeyBasis): string {\n const basis = [\n e.source,\n e.side,\n e.external_id,\n e.event_type,\n // Environment is part of identity: the same external_id in staging vs\n // production are distinct facts that must not collapse to one row.\n e.environment ?? \"\",\n // Mutable state. Absent fields collapse to \"\" so unused ones cost nothing.\n e.status ?? \"\",\n e.amount?.minor ?? \"\",\n e.current_period_end ?? \"\",\n e.arrival_at ?? \"\",\n ].join(\":\");\n return \"fi_\" + createHash(\"sha256\").update(basis).digest(\"hex\").slice(0, 40);\n}\n\nexport function uuidKey(): string {\n return \"fi_\" + randomUUID();\n}\n","import { FinIntegrityError } from \"./errors.js\";\nimport type { EventEnvelope, Transport } from \"./types.js\";\n\nexport interface HttpTransportOptions {\n endpoint: string;\n apiKey: string;\n retries: number;\n debug: boolean;\n}\n\n/** Batched HTTP transport. Retries 5xx/429/network with backoff; honors Retry-After. */\nexport class HttpTransport implements Transport {\n constructor(private readonly opts: HttpTransportOptions) {}\n\n async send(batch: EventEnvelope[], meta: { dropped: number }): Promise<void> {\n const url = this.opts.endpoint.replace(/\\/+$/, \"\") + \"/v1/events\";\n const body = JSON.stringify({ sent_at: new Date().toISOString(), dropped: meta.dropped, events: batch });\n\n for (let attempt = 0; ; attempt++) {\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${this.opts.apiKey}`,\n \"idempotency-key\": batch[0]?.idempotency_key ?? \"\",\n },\n body,\n });\n } catch (netErr) {\n if (attempt >= this.opts.retries) throw netErr;\n await sleep(backoff(attempt));\n continue;\n }\n\n if (res.ok) {\n // A 200 means the batch was received, NOT that every event was stored:\n // ingest validates per event and reports rejects in the body. Treating\n // 200 as total success hides dropped money events behind a success log.\n const rejected = await rejectedFrom(res);\n if (rejected.length > 0) {\n throw new RejectedEventsError(rejected, batch.length);\n }\n if (this.opts.debug) console.log(`[fin-integrity] delivered ${batch.length} event(s)`);\n return;\n }\n if (res.status === 429 || res.status >= 500) {\n if (attempt >= this.opts.retries) throw new Error(`fin-integrity ingest ${res.status}`);\n const ra = Number(res.headers.get(\"retry-after\"));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n // 4xx — terminal, do not retry\n throw new Error(`fin-integrity ingest ${res.status}: ${await safeText(res)}`);\n }\n }\n}\n\n/** In-memory transport for dryRun and tests. */\nexport class MemoryTransport implements Transport {\n sent: EventEnvelope[] = [];\n async send(batch: EventEnvelope[]): Promise<void> {\n this.sent.push(...batch);\n }\n}\n\nfunction backoff(n: number): number {\n return Math.min(1000 * 2 ** n, 15000) + Math.random() * 250;\n}\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n/** Per-event rejections inside an HTTP 200. Surfaced via onError, never thrown to the caller. */\nexport class RejectedEventsError extends FinIntegrityError {\n constructor(\n readonly rejected: RejectedEvent[],\n readonly batchSize: number,\n ) {\n const detail = rejected.map((r) => `${r.event_id}: ${r.error}`).join(\"; \");\n super(`fin-integrity: ingest rejected ${rejected.length}/${batchSize} event(s) — ${detail}`);\n this.name = \"RejectedEventsError\";\n }\n}\n\nexport interface RejectedEvent {\n event_id: string;\n error: string;\n}\n\n/** Rejected entries from a 200 body. An unparseable body means nothing to report. */\nasync function rejectedFrom(res: Response): Promise<RejectedEvent[]> {\n try {\n const body = (await res.clone().json()) as {\n results?: Array<{ event_id?: string; status?: string; error?: string }>;\n };\n if (!Array.isArray(body?.results)) return [];\n return body.results\n .filter((r) => r?.status === \"rejected\")\n .map((r) => ({ event_id: r.event_id ?? \"unknown\", error: r.error ?? \"unknown error\" }));\n } catch {\n return [];\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text();\n } catch {\n return \"\";\n }\n}\n","import { cleanEnvironment } from \"./environment.js\";\nimport { ConfigError, FinIntegrityError } from \"./errors.js\";\nimport { deterministicKey, uuidKey } from \"./idempotency.js\";\nimport { HttpTransport, MemoryTransport } from \"./transport.js\";\nimport type { EventEnvelope, FinIntegrityConfig, PayoutInput, RecordInput, Side, SubscriptionInput, Transport } from \"./types.js\";\n\nconst DEFAULT_ENDPOINT = \"https://ingest.fin-integrity.com\";\n\nexport class FinIntegrityClient {\n private readonly apiKey: string;\n private readonly endpoint: string;\n private readonly idempotencyMode: \"deterministic\" | \"uuid\";\n private readonly maxSize: number;\n private readonly flushMs: number;\n private readonly maxQueueSize: number;\n private readonly sampleRate: number;\n private readonly environment?: string;\n private readonly beforeSend?: FinIntegrityConfig[\"beforeSend\"];\n private readonly debug: boolean;\n private readonly onError: (err: unknown) => void;\n private readonly transport: Transport;\n private readonly memory?: MemoryTransport;\n\n private queue: EventEnvelope[] = [];\n private dropped = 0;\n private timer?: ReturnType<typeof setInterval>;\n\n /** Capture money-movement observed from a payment processor (Stripe, Adyen, bank, …). */\n readonly processor: {\n record: (input: RecordInput) => void;\n recordPayout: (input: PayoutInput) => void;\n recordSubscription: (input: SubscriptionInput) => void;\n };\n /** Capture entries from your own internal ledger / books. */\n readonly ledger: { record: (input: RecordInput) => void };\n\n constructor(config: FinIntegrityConfig = {}) {\n const dryRun = config.dryRun ?? false;\n const apiKey = config.apiKey ?? process.env.FIN_INTEGRITY_KEY;\n if (!apiKey && !dryRun && !config.transport) {\n throw new ConfigError(\n \"fin-integrity: apiKey is required (pass config.apiKey or set FIN_INTEGRITY_KEY). Use { dryRun: true } to test without a key.\",\n );\n }\n this.apiKey = apiKey ?? \"dry-run\";\n this.endpoint = config.endpoint ?? process.env.FIN_INTEGRITY_ENDPOINT ?? DEFAULT_ENDPOINT;\n this.idempotencyMode = config.idempotency ?? \"deterministic\";\n this.maxSize = config.batch?.maxSize ?? 50;\n this.flushMs = config.batch?.flushMs ?? 2000;\n this.maxQueueSize = config.maxQueueSize ?? 1000;\n this.sampleRate = config.sampleRate ?? 1.0;\n this.environment = cleanEnvironment(config.environment ?? process.env.NODE_ENV);\n this.beforeSend = config.beforeSend;\n this.debug = config.debug ?? false;\n this.onError = config.onError ?? ((e) => { if (this.debug) console.warn(\"[fin-integrity]\", e); });\n\n if (config.transport) {\n this.transport = config.transport;\n } else if (dryRun) {\n this.memory = new MemoryTransport();\n this.transport = this.memory;\n } else {\n this.transport = new HttpTransport({\n endpoint: this.endpoint,\n apiKey: this.apiKey,\n retries: config.retries ?? 3,\n debug: this.debug,\n });\n }\n\n this.processor = {\n record: (input) => this.record(\"processor\", input),\n recordPayout: (input) => this.recordPayout(input),\n recordSubscription: (input) => this.recordSubscription(input),\n };\n this.ledger = { record: (input) => this.record(\"ledger\", input) };\n\n this.timer = setInterval(() => void this.flush(), this.flushMs);\n if (typeof this.timer.unref === \"function\") this.timer.unref();\n\n process.once(\"beforeExit\", () => void this.flush());\n process.once(\"SIGTERM\", () => this.onSigterm());\n }\n\n /**\n * Drain on SIGTERM, then hand the process back its normal fate.\n *\n * Node disables its default terminate-on-SIGTERM as soon as ANY listener is\n * registered, so simply attaching one made this library silently decide that\n * SIGTERM no longer kills the host process — a bare script would ignore\n * `docker stop` and hang until SIGKILL, which is also when the queued events\n * we were trying to protect get dropped anyway.\n *\n * So: flush, then exit ourselves — but only if nothing else is listening. If\n * the app registered its own handler it owns the shutdown sequence, and a\n * library must not exit out from under it. `once` has already removed our own\n * listener by the time this runs, so any remaining count is the app's.\n */\n private onSigterm(): void {\n const appHandlesIt = process.listenerCount(\"SIGTERM\") > 0;\n void this.flush().finally(() => {\n if (!appHandlesIt) process.exit(143); // 128 + SIGTERM(15), the conventional code\n });\n }\n\n /** Low-level escape hatch: capture a fully-specified event (both adapters use this). */\n capture(input: RecordInput & { side: Side }): void {\n this.record(input.side, input);\n }\n\n private record(side: Side, input: RecordInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side,\n source: input.source ?? (side === \"ledger\" ? \"ledger.internal\" : \"custom\"),\n event_type: input.type,\n reference: input.reference,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.fee != null\n ? { fee: { minor: toMinorString(input.fee.minor), currency: input.fee.currency.toLowerCase() } }\n : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.payoutId != null ? { payout_id: input.payoutId } : {}),\n ...(input.subscriptionId != null ? { subscription_id: input.subscriptionId } : {}),\n ...(input.parentExternalId != null ? { parent_external_id: input.parentExternalId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...(input.direction != null ? { direction: input.direction } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open — never throw into the caller\n }\n }\n\n /**\n * Capture a recurring billing container. Not money movement — this is what a\n * charge is expected to arrive in, which is what lets reconciliation catch a\n * billing period that produced no charge at all.\n *\n * Send it whenever the subscription changes (created, renewed, status change)\n * so `currentPeriodEnd` stays current.\n */\n private recordSubscription(input: SubscriptionInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"subscription\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n status: input.status,\n ...(input.interval != null ? { interval: input.interval } : {}),\n ...(input.currentPeriodStart != null ? { current_period_start: toIso(input.currentPeriodStart) } : {}),\n ...(input.currentPeriodEnd != null ? { current_period_end: toIso(input.currentPeriodEnd) } : {}),\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Capture a processor payout (processor → bank). Stored separately; links to\n * transactions via their payoutId. */\n private recordPayout(input: PayoutInput): void {\n try {\n const env: EventEnvelope = {\n schema_version: \"1.0\",\n event_id: uuidKey(),\n idempotency_key: \"\",\n side: \"processor\",\n source: input.source ?? \"custom\",\n event_type: \"payout\",\n reference: input.external_id,\n external_id: input.external_id,\n amount: {\n minor: toMinorString(input.amount.minor),\n currency: input.amount.currency.toLowerCase(),\n ...(input.amount.exponent != null ? { exponent: input.amount.exponent } : {}),\n },\n ...(input.traceId != null ? { trace_id: input.traceId } : {}),\n ...(input.arrivalAt != null ? { arrival_at: toIso(input.arrivalAt) } : {}),\n occurred_at: toIso(input.occurred_at),\n captured_at: new Date().toISOString(),\n ...(input.status != null ? { status: input.status } : {}),\n ...this.envFields(input.environment),\n ...(input.metadata != null ? { metadata: input.metadata } : {}),\n };\n env.idempotency_key = this.idempotencyMode === \"uuid\" ? uuidKey() : deterministicKey(env);\n this.enqueue(env);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Per-event override wins over the client default; an invalid value falls back\n * to the default (and, if that's absent too, the server defaults to production). */\n private envFields(perEvent?: string): { environment?: string } {\n const environment = cleanEnvironment(perEvent) ?? this.environment;\n return environment != null ? { environment } : {};\n }\n\n private enqueue(env: EventEnvelope): void {\n if (this.sampleRate < 1 && Math.random() > this.sampleRate) return;\n let out: EventEnvelope | null | undefined = env;\n if (this.beforeSend) out = this.beforeSend(env);\n if (!out) return;\n if (this.queue.length >= this.maxQueueSize) {\n this.queue.shift(); // drop-oldest\n this.dropped++;\n }\n this.queue.push(out);\n if (this.queue.length >= this.maxSize) void this.flush();\n }\n\n /** Send all queued events now. Safe to await (e.g. in a serverless `finally`). */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n const batch = this.queue.splice(0, this.queue.length);\n const dropped = this.dropped;\n this.dropped = 0;\n try {\n await this.transport.send(batch, { dropped });\n } catch (err) {\n this.onError(err); // fail-open: batch is lost, SDK stays alive\n }\n }\n\n /** Drain and stop the client (call before a long-lived process exits). */\n async shutdown(): Promise<void> {\n if (this.timer) clearInterval(this.timer);\n await this.flush();\n }\n\n /** Record a deploy marker so reconciliation can attribute a discrepancy spike\n * to the release that caused it. Infrequent; sent directly (not batched).\n * Fail-open — never throws into your deploy pipeline. */\n async recordDeploy(\n release: string,\n opts: { environment?: string; deployedAt?: string | Date } = {},\n ): Promise<void> {\n try {\n const clean = cleanReleaseLabel(release);\n if (!clean) return;\n const body: Record<string, unknown> = { release: clean, source: \"sdk\" };\n if (opts.environment != null) body.environment = opts.environment;\n if (opts.deployedAt != null) {\n body.deployed_at = opts.deployedAt instanceof Date ? opts.deployedAt.toISOString() : String(opts.deployedAt);\n }\n const res = await fetch(this.endpoint.replace(/\\/+$/, \"\") + \"/v1/deploys\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${this.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw new Error(`fin-integrity: recordDeploy got ${res.status}`);\n } catch (err) {\n this.onError(err); // fail-open\n }\n }\n\n /** Envelopes captured so far (dryRun / MemoryTransport only). Great for tests. */\n inspect(): EventEnvelope[] {\n return this.memory ? [...this.memory.sent, ...this.queue] : [...this.queue];\n }\n}\n\nfunction toMinorString(m: number | bigint): string {\n if (typeof m === \"bigint\") return m.toString();\n if (!Number.isInteger(m)) {\n throw new FinIntegrityError(`amount.minor must be an integer in minor units, got ${m}`);\n }\n return String(m);\n}\nfunction toIso(v?: string | Date): string {\n if (!v) return new Date().toISOString();\n return v instanceof Date ? v.toISOString() : v;\n}\nfunction cleanReleaseLabel(raw: unknown): string | undefined {\n if (typeof raw !== \"string\") return undefined;\n const v = raw.trim();\n if (!v || v.length > 200 || /[\\n\\t]/.test(v)) return undefined;\n return v;\n}\n","import type { FinIntegrityClient } from \"./client.js\";\nimport type { EventType } from \"./types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Wrap the Stripe client you pass in so `charges.create`, `paymentIntents.create`,\n * and `refunds.create` are captured automatically as fin-integrity processor events.\n *\n * We wrap the exact instance you hand us — no global monkey-patching — so it's\n * predictable and ESM/bundler-safe. Capture runs off the hot path and never blocks\n * or alters your Stripe call. Returns the same (now instrumented) client.\n */\nexport function instrumentStripe<T>(stripe: T, fi: FinIntegrityClient): T {\n const s = stripe as any;\n wrap(s?.charges, \"create\", fi, \"payment\");\n wrap(s?.paymentIntents, \"create\", fi, \"payment\");\n wrap(s?.refunds, \"create\", fi, \"refund\");\n return stripe;\n}\n\nfunction wrap(resource: any, method: string, fi: FinIntegrityClient, type: EventType): void {\n if (!resource || typeof resource[method] !== \"function\") return;\n const original = resource[method];\n if (original.__fiWrapped) return; // idempotent — never double-wrap\n\n const wrapped = async function (this: any, ...args: any[]) {\n const result = await original.apply(this, args); // never block/alter the real call\n queueMicrotask(() => {\n try {\n captureStripe(fi, type, result);\n } catch {\n /* swallowed — must never break the Stripe call path */\n }\n });\n return result;\n };\n wrapped.__fiWrapped = true;\n resource[method] = wrapped;\n}\n\nfunction captureStripe(fi: FinIntegrityClient, type: EventType, obj: any): void {\n if (!obj || typeof obj !== \"object\" || typeof obj.id !== \"string\") return;\n const amount = type === \"refund\" ? obj.amount : obj.amount_received ?? obj.amount;\n const reference =\n obj.metadata?.reference ??\n obj.metadata?.order_id ??\n obj.metadata?.reconciliation_id ??\n (type === \"refund\" ? obj.charge ?? obj.payment_intent ?? obj.id : obj.id);\n\n fi.capture({\n side: \"processor\",\n type,\n source: \"stripe\",\n reference: String(reference),\n external_id: obj.id,\n amount: { minor: typeof amount === \"number\" ? amount : 0, currency: String(obj.currency ?? \"\") },\n ...(obj.status ? { status: String(obj.status) } : {}),\n ...(typeof obj.created === \"number\" ? { occurred_at: new Date(obj.created * 1000) } : {}),\n metadata: { stripe_object: obj.object },\n });\n}\n","import { FinIntegrityClient } from \"./client.js\";\nimport type { FinIntegrityConfig } from \"./types.js\";\n\nexport { FinIntegrityClient } from \"./client.js\";\nexport { instrumentStripe } from \"./stripe.js\";\nexport { FinIntegrityError, ConfigError } from \"./errors.js\";\n// Reaches onError whenever a 2xx carries per-event rejections — callers can't\n// branch on an error they have no way to import. Python exports it; parity.\nexport { RejectedEventsError, type RejectedEvent } from \"./transport.js\";\nexport type {\n FinIntegrityConfig,\n RecordInput,\n PayoutInput,\n SubscriptionInput,\n EventEnvelope,\n Money,\n Side,\n EventType,\n WireEventType,\n Direction,\n Transport,\n} from \"./types.js\";\n\nlet current: FinIntegrityClient | undefined;\n\n/** Create and configure the client. Returns it (also stored as the module singleton). */\nexport function init(config?: FinIntegrityConfig): FinIntegrityClient {\n current = new FinIntegrityClient(config);\n return current;\n}\n\n/** The client from the most recent init() — convenient in scripts. */\nexport function getClient(): FinIntegrityClient {\n if (!current) throw new Error(\"fin-integrity: call init() before getClient()\");\n return current;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fin-integrity/node",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Reconciliation-as-you-code — capture Stripe and ledger events from your backend and catch every payment that doesn't reconcile.",
5
5
  "keywords": [
6
6
  "reconciliation",