@vinaverse/server 0.0.0-stage → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +165 -2
  2. package/dist/api.cjs +528 -0
  3. package/dist/api.cjs.map +1 -0
  4. package/dist/api.d.cts +453 -0
  5. package/dist/api.d.ts +453 -0
  6. package/dist/api.js +516 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/chunk-FEEJNQXV.js +64 -0
  9. package/dist/chunk-FEEJNQXV.js.map +1 -0
  10. package/dist/chunk-GTPMQKGX.js +277 -0
  11. package/dist/chunk-GTPMQKGX.js.map +1 -0
  12. package/dist/chunk-NPXO6SMZ.js +84 -0
  13. package/dist/chunk-NPXO6SMZ.js.map +1 -0
  14. package/dist/chunk-SDJFZPHJ.js +141 -0
  15. package/dist/chunk-SDJFZPHJ.js.map +1 -0
  16. package/dist/express.cjs +397 -0
  17. package/dist/express.cjs.map +1 -0
  18. package/dist/express.d.cts +43 -0
  19. package/dist/express.d.ts +43 -0
  20. package/dist/express.js +87 -0
  21. package/dist/express.js.map +1 -0
  22. package/dist/fastify.cjs +363 -0
  23. package/dist/fastify.cjs.map +1 -0
  24. package/dist/fastify.d.cts +62 -0
  25. package/dist/fastify.d.ts +62 -0
  26. package/dist/fastify.js +54 -0
  27. package/dist/fastify.js.map +1 -0
  28. package/dist/hono.cjs +421 -0
  29. package/dist/hono.cjs.map +1 -0
  30. package/dist/hono.d.cts +21 -0
  31. package/dist/hono.d.ts +21 -0
  32. package/dist/hono.js +34 -0
  33. package/dist/hono.js.map +1 -0
  34. package/dist/index.cjs +1481 -0
  35. package/dist/index.cjs.map +1 -0
  36. package/dist/index.d.cts +196 -0
  37. package/dist/index.d.ts +196 -0
  38. package/dist/index.js +920 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/lambda.cjs +405 -0
  41. package/dist/lambda.cjs.map +1 -0
  42. package/dist/lambda.d.cts +53 -0
  43. package/dist/lambda.d.ts +53 -0
  44. package/dist/lambda.js +86 -0
  45. package/dist/lambda.js.map +1 -0
  46. package/dist/nonces-scwljZwl.d.cts +92 -0
  47. package/dist/nonces-scwljZwl.d.ts +92 -0
  48. package/dist/provider-BqfTvF3g.d.ts +2016 -0
  49. package/dist/provider-Miaa9V7I.d.cts +2016 -0
  50. package/dist/stores.cjs +315 -0
  51. package/dist/stores.cjs.map +1 -0
  52. package/dist/stores.d.cts +52 -0
  53. package/dist/stores.d.ts +52 -0
  54. package/dist/stores.js +306 -0
  55. package/dist/stores.js.map +1 -0
  56. package/dist/testing.cjs +135 -0
  57. package/dist/testing.cjs.map +1 -0
  58. package/dist/testing.d.cts +29 -0
  59. package/dist/testing.d.ts +29 -0
  60. package/dist/testing.js +49 -0
  61. package/dist/testing.js.map +1 -0
  62. package/dist/vinaverse-v1.d-BVc4uyUd.d.cts +3460 -0
  63. package/dist/vinaverse-v1.d-BVc4uyUd.d.ts +3460 -0
  64. package/package.json +226 -4
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/webhooks/crypto.ts","../src/internal/bytes.ts","../src/webhooks/errors.ts","../src/webhooks/events.ts","../src/webhooks/signature.ts","../src/webhooks/verify.ts","../src/adapters/handler.ts","../src/adapters/lambda.ts"],"names":[],"mappings":"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","file":"lambda.cjs","sourcesContent":["// Web Crypto wherever the package runs. Node 20+, AWS Lambda, edge runtimes\n// and React Native expose it as `globalThis.crypto`; Node 18 has the same API\n// but only as `webcrypto` in its crypto module, so on Node 18 it is loaded\n// from there, once.\n\n/** No Web Crypto in this runtime: the package cannot verify anything here. */\nexport class WebCryptoUnavailableError extends Error {\n constructor() {\n super(\n 'Web Crypto (crypto.subtle) is not available in this runtime; @vinaverse/server needs Node 18+, an edge runtime or another runtime with Web Crypto',\n );\n this.name = 'WebCryptoUnavailableError';\n }\n}\n\ntype MaybeNode = { process?: { versions?: { node?: unknown } } };\n\nlet fromNode: Promise<Crypto> | undefined;\n\n/** The runtime's Web Crypto: `crypto.subtle` and `crypto.getRandomValues`. */\nexport function webCrypto(): Promise<Crypto> {\n const global = (globalThis as { crypto?: Crypto }).crypto;\n if (global?.subtle) return Promise.resolve(global);\n fromNode ??= nodeWebCrypto();\n return fromNode;\n}\n\nexport async function subtleCrypto(): Promise<SubtleCrypto> {\n return (await webCrypto()).subtle;\n}\n\nasync function nodeWebCrypto(): Promise<Crypto> {\n if (typeof (globalThis as MaybeNode).process?.versions?.node !== 'string') {\n throw new WebCryptoUnavailableError();\n }\n // Built at run time on purpose: bundlers for edge runtimes and React Native,\n // where this line never runs, must not try to resolve a Node module.\n const specifier = ['node', 'crypto'].join(':');\n const mod = (await import(\n /* webpackIgnore: true */ /* @vite-ignore */ specifier\n )) as { webcrypto?: Crypto };\n if (!mod.webcrypto?.subtle) throw new WebCryptoUnavailableError();\n return mod.webcrypto;\n}\n","// Byte helpers on Web APIs only (no Buffer), shared by the signature checks.\nimport { subtleCrypto } from '../webhooks/crypto.js';\n\nconst encoder = new TextEncoder();\n\nexport function utf8(text: string): Uint8Array<ArrayBuffer> {\n return encoder.encode(text);\n}\n\nexport function toBytes(body: string | Uint8Array | ArrayBuffer): Uint8Array {\n if (typeof body === 'string') return utf8(body);\n if (body instanceof Uint8Array) return body;\n return new Uint8Array(body);\n}\n\nexport function hexToBytes(hex: string): Uint8Array<ArrayBuffer> {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport async function sha256Hex(data: Uint8Array): Promise<string> {\n const subtle = await subtleCrypto();\n return bytesToHex(new Uint8Array(await subtle.digest('SHA-256', copy(data))));\n}\n\nexport async function hmacKey(\n secret: string,\n usage: 'sign' | 'verify',\n): Promise<CryptoKey> {\n const subtle = await subtleCrypto();\n return subtle.importKey(\n 'raw',\n utf8(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n [usage],\n );\n}\n\n// Web Crypto takes an ArrayBuffer-backed view; a Node Buffer may sit on a\n// shared pool, so a view is copied when it does not own its whole buffer.\nexport function copy(data: Uint8Array): Uint8Array<ArrayBuffer> {\n const out = new Uint8Array(data.length);\n out.set(data);\n return out;\n}\n\nexport function concat(...parts: Uint8Array[]): Uint8Array<ArrayBuffer> {\n const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));\n let at = 0;\n for (const p of parts) {\n out.set(p, at);\n at += p.length;\n }\n return out;\n}\n","/**\n * Why a delivery was refused, in the conformance vectors' words\n * (vinaverse-contracts `conformance/webhooks.json`). Every one is answered with\n * `400`, so Vinaverse retries it; none of them is ever a valid delivery.\n *\n * - `missing`: no `Vinaverse-Signature` header.\n * - `malformed`: the header is not `t=<unix seconds>,v1=<hex>[,v1=<hex>]`\n * (no single timestamp, or no `v1` signature).\n * - `stale`: signed more than the tolerance (300 seconds) before or after now:\n * a replay, or a clock far off.\n * - `mismatch`: no `v1` signature matches the body with any secret: a wrong\n * secret (or the secret without its `vv_whsec_` prefix), a changed body, or a\n * body parsed and serialized again.\n * - `invalid_body`: signed by Vinaverse, but not a webhook envelope this\n * package can read.\n */\nexport type WebhookErrorCode =\n | 'missing'\n | 'malformed'\n | 'stale'\n | 'mismatch'\n | 'invalid_body';\n\nexport interface WebhookError {\n readonly code: WebhookErrorCode;\n readonly message: string;\n}\n\nexport function webhookError(\n code: WebhookErrorCode,\n message: string,\n): WebhookError {\n return { code, message };\n}\n","// The webhook events, typed from the pinned contract (vinaverse-v1.yaml,\n// `webhooks`), and the reading of a verified body into one of them.\nimport type { components, webhooks } from '../generated/vinaverse-v1.js';\nimport { type WebhookError, webhookError } from './errors.js';\n\ntype Schemas = components['schemas'];\n\n/** The envelope every webhook body has. `data` depends on `type`. */\nexport type WebhookEnvelope = Schemas['WebhookEnvelope'];\n\n/** Every event type the targeted contract defines. */\nexport type WebhookEventType = WebhookEnvelope['type'] & keyof webhooks;\n\ntype BodyOf<T extends WebhookEventType> = NonNullable<\n webhooks[T]['post']['requestBody']\n>['content']['application/json'];\n\n/** One event of type `T`: the envelope, with `data` as the contract says. */\nexport type WebhookEventOf<T extends WebhookEventType> = Omit<\n WebhookEnvelope,\n 'type' | 'data'\n> & {\n type: T;\n data: NonNullable<BodyOf<T>['data']>;\n};\n\n/** Any event this package version knows; narrow it on `type`. */\nexport type WebhookEvent = {\n [T in WebhookEventType]: WebhookEventOf<T>;\n}[WebhookEventType];\n\nexport type ConversationEventType =\n | 'conversation.updated'\n | 'conversation.completed'\n | 'conversation.failed'\n | 'conversation.expired';\n\n/** A guided-flow conversation's state changed: `data` is its `ConversationState`. */\nexport type ConversationEvent = {\n [T in ConversationEventType]: WebhookEventOf<T>;\n}[ConversationEventType];\n\nexport type ConversationState = Schemas['ConversationState'];\n\n// Kept in step with the contract by a test that reads the pinned YAML.\nexport const WEBHOOK_EVENT_TYPES: readonly WebhookEventType[] = [\n 'moderation.item.completed',\n 'moderation.job.completed',\n 'document_check.completed',\n 'session.completed',\n 'subject.erased',\n 'usage.threshold_reached',\n 'feature.state_changed',\n 'media.job.queued',\n 'media.job.progress',\n 'media.job.step.completed',\n 'media.job.completed',\n 'media.job.failed',\n 'media.job.cancelled',\n 'conversation.updated',\n 'conversation.completed',\n 'conversation.failed',\n 'conversation.expired',\n];\n\nconst KNOWN = new Set<string>(WEBHOOK_EVENT_TYPES);\n\n// The statuses each conversation event may carry (vinaverse-v1.yaml, webhooks).\nconst CONVERSATION_STATUSES: Readonly<Record<string, readonly string[]>> = {\n 'conversation.updated': ['in_progress', 'failed'],\n 'conversation.completed': ['completed'],\n 'conversation.failed': ['failed'],\n 'conversation.expired': ['expired'],\n};\nconst ENVIRONMENTS = new Set(['mock', 'development', 'production']);\n\nexport function isConversationEvent(\n event: WebhookEvent,\n): event is ConversationEvent {\n return event.type.startsWith('conversation.');\n}\n\n/** What a verified body is: a known event, a test delivery, or a type newer than this package. */\nexport type ReadBody =\n | { kind: 'event'; event: WebhookEvent }\n | { kind: 'test'; envelope: WebhookEnvelope }\n | { kind: 'unrecognized'; envelope: WebhookEnvelope };\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Reads a verified body: it must be the webhook envelope (`id`, `type`,\n * `created_at`, `environment`, `data`). A test delivery from Studio carries\n * `data: { test: true }` and no payload. A conversation event must carry a\n * guided flow's state with the status its type allows and the fields its\n * ordering depends on (`conversation_id`, `sequence`); other payloads are as\n * Vinaverse signed them. A type newer than this package is `unrecognized`,\n * never an error: answer it 2xx and upgrade.\n */\nexport function readBody(text: string): ReadBody | WebhookError {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return webhookError('invalid_body', 'the body is not JSON');\n }\n if (\n !isObject(parsed) ||\n typeof parsed.id !== 'string' ||\n typeof parsed.type !== 'string' ||\n typeof parsed.created_at !== 'string' ||\n typeof parsed.environment !== 'string' ||\n !ENVIRONMENTS.has(parsed.environment) ||\n !isObject(parsed.data)\n ) {\n return webhookError(\n 'invalid_body',\n 'the body is not a webhook envelope (id, type, created_at, environment, data)',\n );\n }\n const envelope = parsed as WebhookEnvelope;\n if (parsed.data.test === true) return { kind: 'test', envelope };\n if (!KNOWN.has(parsed.type)) return { kind: 'unrecognized', envelope };\n const statuses = CONVERSATION_STATUSES[parsed.type];\n if (statuses) {\n const { conversation_id, sequence, status, flow } = parsed.data;\n if (\n typeof conversation_id !== 'string' ||\n !Number.isSafeInteger(sequence) ||\n (sequence as number) < 1 ||\n typeof status !== 'string' ||\n !statuses.includes(status) ||\n typeof flow !== 'string'\n ) {\n return webhookError(\n 'invalid_body',\n `a ${parsed.type} event carries a guided flow's state: conversation_id, a positive integer sequence, a flow, and status ${statuses.join(' or ')}`,\n );\n }\n }\n return { kind: 'event', event: parsed as WebhookEvent };\n}\n","// The webhook signature, exactly as the Vinaverse API signs and checks it\n// (contract: docs/conversation-state.md §1, \"Delivery\"):\n// Vinaverse-Signature: t=<unix seconds>,v1=<hex>[,v1=<hex>]\n// `v1` is the lowercase hex HMAC-SHA256, keyed with the endpoint's whole\n// signing secret as UTF-8 (the `vv_whsec_` prefix included, never decoded),\n// over `<t>.` followed by the raw request body. During a secret rotation the\n// header carries one `v1` per valid secret. A signature more than 300 seconds\n// from now, either way, is refused.\nimport { concat, hexToBytes, hmacKey, utf8 } from '../internal/bytes.js';\nimport { subtleCrypto } from './crypto.js';\nimport { type WebhookError, webhookError } from './errors.js';\n\nexport const SIGNATURE_HEADER = 'Vinaverse-Signature';\nexport const TOLERANCE_SECONDS = 300;\n\nconst DIGITS = /^[0-9]+$/;\nconst V1 = /^[0-9a-f]{64}$/;\n\nexport interface ParsedSignature {\n /** The signed timestamp, in Unix seconds. */\n readonly timestamp: bigint;\n /** Each `v1` signature, decoded. */\n readonly signatures: readonly Uint8Array[];\n}\n\n/**\n * Reads the header the way the API's own verifier does: comma-separated\n * `key=value` parts (a space around a part changes nothing), exactly one `t`\n * of digits, and the `v1` values. A `v1`\n * that is not 64 lowercase hex digits can never match, so it is left out; a\n * header left with no `v1` is malformed.\n */\nexport function parseSignatureHeader(\n header: string,\n): ParsedSignature | WebhookError {\n const parts = header\n .split(',')\n .map((p) => p.trim())\n .filter((p) => p.includes('='))\n .map((p) => {\n const at = p.indexOf('=');\n return [p.slice(0, at), p.slice(at + 1)] as const;\n });\n const timestamps = parts.filter(([k]) => k === 't').map(([, v]) => v);\n const [t] = timestamps;\n if (timestamps.length !== 1 || t === undefined || !DIGITS.test(t)) {\n return webhookError(\n 'malformed',\n 'the signature header needs exactly one timestamp, t=<unix seconds>',\n );\n }\n const signatures = parts\n .filter(([k, v]) => k === 'v1' && V1.test(v))\n .map(([, v]) => hexToBytes(v));\n if (signatures.length === 0) {\n return webhookError(\n 'malformed',\n 'the signature header has no v1 signature',\n );\n }\n return { timestamp: BigInt(t), signatures };\n}\n\n/**\n * Checks a delivery's signature: the header's form, its timestamp against\n * `now`, then each `v1` against each secret, in constant time (Web Crypto's\n * `verify`). `secrets` is more than one while the receiver rolls a new secret\n * out. Returns null when the signature is valid.\n */\nexport async function checkSignature(options: {\n body: Uint8Array;\n header: string;\n secrets: readonly string[];\n now: Date;\n toleranceSeconds: number;\n}): Promise<WebhookError | null> {\n const parsed = parseSignatureHeader(options.header);\n if ('code' in parsed) return parsed;\n const now = BigInt(Math.floor(options.now.getTime() / 1000));\n const skew =\n now > parsed.timestamp ? now - parsed.timestamp : parsed.timestamp - now;\n if (skew > BigInt(options.toleranceSeconds)) {\n return webhookError(\n 'stale',\n `the signature is ${skew} seconds from now; at most ${options.toleranceSeconds} are accepted`,\n );\n }\n const message = concat(utf8(`${parsed.timestamp}.`), options.body);\n const subtle = await subtleCrypto();\n for (const secret of options.secrets) {\n const key = await hmacKey(secret, 'verify');\n for (const signature of parsed.signatures) {\n // Every signature is decoded into its own ArrayBuffer (hexToBytes).\n if (\n await subtle.verify(\n 'HMAC',\n key,\n signature as Uint8Array<ArrayBuffer>,\n message,\n )\n )\n return null;\n }\n }\n return webhookError(\n 'mismatch',\n 'no signature matches the body with the signing secret: check the secret, and verify the raw body exactly as received',\n );\n}\n","import { toBytes } from '../internal/bytes.js';\nimport { type WebhookError, webhookError } from './errors.js';\nimport { type ReadBody, readBody } from './events.js';\nimport { checkSignature, TOLERANCE_SECONDS } from './signature.js';\n\nexport interface VerifyWebhookOptions {\n /**\n * The request body exactly as received, before any JSON parsing: a string,\n * or bytes (`Uint8Array`, which a Node `Buffer` is, or `ArrayBuffer`). A\n * body parsed and serialized again never verifies.\n */\n rawBody: string | Uint8Array | ArrayBuffer;\n /** The `Vinaverse-Signature` header (a framework's string array is accepted). */\n header: string | readonly string[] | null | undefined;\n /**\n * The endpoint's signing secret (`vv_whsec_…`), whole. Pass two while you\n * roll a new one out: a delivery verifies if either matches.\n */\n secret: string | readonly string[];\n /** The time to check the signature's timestamp against; default now. */\n now?: Date;\n /** How far from `now` a signature may be: whole seconds, 0 to 300 (the contract's window, the default). */\n toleranceSeconds?: number;\n}\n\nexport type VerifyWebhookResult =\n | ({ ok: true } & ReadBody)\n | { ok: false; error: WebhookError };\n\n/**\n * Verifies a Vinaverse webhook delivery and reads it, in one call:\n *\n * - `{ ok: true, kind: 'event', event }`: a verified event; narrow it on `event.type`.\n * - `{ ok: true, kind: 'test', envelope }`: a test delivery from Studio; answer 2xx, do nothing.\n * - `{ ok: true, kind: 'unrecognized', envelope }`: verified, but a type newer than this\n * package; answer 2xx, and upgrade to handle it.\n * - `{ ok: false, error }`: refused (`error.code` says why); answer 400.\n *\n * Deliveries are at least once: deduplicate on `event.id`, and order a\n * conversation's states with `sequenceVerdict` or `applyConversationState`.\n * It never throws for a bad delivery; it throws a `TypeError` for a missing\n * secret or a tolerance that is not a whole number of seconds from 0 to 300,\n * and `WebCryptoUnavailableError` in a runtime without Web Crypto.\n */\nexport async function verifyWebhook(\n options: VerifyWebhookOptions,\n): Promise<VerifyWebhookResult> {\n const secrets = signingSecrets(options.secret);\n const toleranceSeconds = checkTolerance(options.toleranceSeconds);\n const header = singleHeader(options.header);\n if (header === undefined) {\n return {\n ok: false,\n error: webhookError('missing', 'no Vinaverse-Signature header'),\n };\n }\n if (header === null) {\n return {\n ok: false,\n error: webhookError(\n 'malformed',\n 'more than one Vinaverse-Signature header',\n ),\n };\n }\n const body = toBytes(options.rawBody);\n const refused = await checkSignature({\n body,\n header,\n secrets,\n now: options.now ?? new Date(),\n toleranceSeconds,\n });\n if (refused) return { ok: false, error: refused };\n let text: string;\n try {\n text = new TextDecoder('utf-8', { fatal: true }).decode(body);\n } catch {\n return {\n ok: false,\n error: webhookError('invalid_body', 'the body is not UTF-8'),\n };\n }\n const read = readBody(text);\n return 'code' in read ? { ok: false, error: read } : { ok: true, ...read };\n}\n\n// undefined: absent; null: more than one; otherwise the header.\nfunction singleHeader(\n header: string | readonly string[] | null | undefined,\n): string | null | undefined {\n if (header === null || header === undefined) return undefined;\n if (typeof header === 'string') return header === '' ? undefined : header;\n if (header.length === 0) return undefined;\n return header.length === 1 ? header[0] : null;\n}\n\n/** The signing secrets, checked: a TypeError for none, an empty one, or an unset variable. */\nexport function signingSecrets(secret: unknown): string[] {\n const list =\n typeof secret === 'string'\n ? [secret]\n : Array.isArray(secret)\n ? [...secret]\n : [];\n if (\n list.length === 0 ||\n list.some((s) => typeof s !== 'string' || s === '')\n ) {\n throw new TypeError(\n 'the webhook signing secret is required (vv_whsec_…), and none was given',\n );\n }\n return list as string[];\n}\n\n/**\n * The tolerance, checked once: whole seconds from 0 to 300. A wider window is\n * a longer replay window than the contract allows.\n */\nexport function checkTolerance(seconds: number | undefined): number {\n if (seconds === undefined) return TOLERANCE_SECONDS;\n if (\n !Number.isSafeInteger(seconds) ||\n seconds < 0 ||\n seconds > TOLERANCE_SECONDS\n ) {\n throw new TypeError(\n `toleranceSeconds must be a whole number of seconds from 0 to ${TOLERANCE_SECONDS}, not ${seconds}`,\n );\n }\n return seconds;\n}\n","// What every adapter does with a delivery once it has the raw body and the\n// signature header: verify, call the tenant's handler for the result, and\n// answer. A refused delivery is answered 400 (Vinaverse retries, then gives\n// up); a handled one 200. A handler that throws is the adapter's to surface,\n// so the delivery fails and Vinaverse retries it.\nimport type { WebhookError } from '../webhooks/errors.js';\nimport type { WebhookEnvelope, WebhookEvent } from '../webhooks/events.js';\nimport {\n checkTolerance,\n signingSecrets,\n verifyWebhook,\n} from '../webhooks/verify.js';\n\nexport interface WebhookHandlerOptions {\n /** The endpoint's signing secret, or two while rolling a new one out. */\n secret: string | readonly string[];\n /**\n * Called once per verified delivery of a known event. Answer quickly (the\n * contract allows 5 seconds) and do the work afterwards; deliveries are at\n * least once, so deduplicate on `event.id`.\n */\n onEvent(event: WebhookEvent): void | Promise<void>;\n /** A test delivery from Studio; by default it is acknowledged and ignored. */\n onTest?(envelope: WebhookEnvelope): void | Promise<void>;\n /** A verified type newer than this package; by default acknowledged and ignored. */\n onUnrecognized?(envelope: WebhookEnvelope): void | Promise<void>;\n /** A refused delivery, for logging; it is answered 400 either way. */\n onRejected?(error: WebhookError): void | Promise<void>;\n /** How far from now a signature may be, in seconds; default 300. */\n toleranceSeconds?: number;\n /**\n * The largest body accepted, in bytes; default 1 MiB (a conversation\n * webhook is at most 64 KB). A larger one is answered 413 unread.\n */\n maxBodyBytes?: number;\n /** The clock; default the system clock. */\n now?: () => Date;\n}\n\nexport interface WebhookResponse {\n readonly status: 200 | 400 | 413;\n readonly body: string;\n}\n\nexport const MAX_BODY_BYTES = 1024 * 1024;\nconst RECEIVED = JSON.stringify({ received: true });\n\nexport function tooLarge(): WebhookResponse {\n return {\n status: 413,\n body: JSON.stringify({ error: { code: 'body_too_large' } }),\n };\n}\n\nexport function byteLength(body: string | Uint8Array | ArrayBuffer): number {\n return typeof body === 'string'\n ? new TextEncoder().encode(body).length\n : body.byteLength;\n}\n\nexport async function handleWebhook(\n options: WebhookHandlerOptions,\n rawBody: string | Uint8Array | ArrayBuffer,\n header: string | readonly string[] | null | undefined,\n): Promise<WebhookResponse> {\n if (byteLength(rawBody) > (options.maxBodyBytes ?? MAX_BODY_BYTES)) {\n return tooLarge();\n }\n const result = await verifyWebhook({\n rawBody,\n header,\n secret: options.secret,\n ...(options.now ? { now: options.now() } : {}),\n ...(options.toleranceSeconds === undefined\n ? {}\n : { toleranceSeconds: options.toleranceSeconds }),\n });\n if (!result.ok) {\n await options.onRejected?.(result.error);\n return {\n status: 400,\n body: JSON.stringify({ error: { code: result.error.code } }),\n };\n }\n if (result.kind === 'event') await options.onEvent(result.event);\n else if (result.kind === 'test') await options.onTest?.(result.envelope);\n else await options.onUnrecognized?.(result.envelope);\n return { status: 200, body: RECEIVED };\n}\n\n/** A header's value from a record whose names may have any case. */\nexport function headerValue(\n headers:\n | Readonly<Record<string, string | readonly string[] | undefined>>\n | null\n | undefined,\n name: string,\n): string | readonly string[] | undefined {\n if (!headers) return undefined;\n const wanted = name.toLowerCase();\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === wanted && value !== undefined) return value;\n }\n return undefined;\n}\n\n/**\n * Checks a handler's options once, when the adapter is made, so a wrong value\n * fails at start-up instead of answering every delivery with an error.\n */\nexport function checkHandlerOptions(options: WebhookHandlerOptions): void {\n signingSecrets(options.secret);\n checkTolerance(options.toleranceSeconds);\n if (typeof options.onEvent !== 'function') {\n throw new TypeError(\n 'onEvent is required: it receives every verified event',\n );\n }\n const max = options.maxBodyBytes;\n if (max !== undefined && (!Number.isSafeInteger(max) || max <= 0)) {\n throw new TypeError(\n `maxBodyBytes must be a positive whole number of bytes, not ${max}`,\n );\n }\n}\n","// AWS Lambda behind API Gateway (REST API, payload v1; HTTP API, payload v2)\n// or a function URL (payload v2). Both payloads carry the body as a string,\n// base64-encoded when `isBase64Encoded` is true; the signature is over the\n// bytes Vinaverse sent, so a base64 body is decoded to bytes, never read as text.\n//\n// export const handler = createLambdaWebhookHandler({ secret, onEvent });\nimport {\n checkHandlerOptions,\n handleWebhook,\n headerValue,\n type WebhookHandlerOptions,\n} from './handler.js';\n\nexport type { WebhookHandlerOptions } from './handler.js';\n\nimport type { ToolProvider } from '../tools/provider.js';\n\n/** The fields of an API Gateway (v1 or v2) or function URL event the handler reads. */\nexport interface LambdaHttpEvent {\n body?: string | null;\n isBase64Encoded?: boolean;\n headers?: Readonly<Record<string, string | undefined>> | null;\n /** v1 only. */\n multiValueHeaders?: Readonly<\n Record<string, readonly string[] | undefined>\n > | null;\n}\n\n/** A result both payload versions accept. */\nexport interface LambdaHttpResult {\n statusCode: number;\n headers: Record<string, string>;\n body: string;\n}\n\nexport function createLambdaWebhookHandler(\n options: WebhookHandlerOptions,\n): (event: LambdaHttpEvent) => Promise<LambdaHttpResult> {\n checkHandlerOptions(options);\n return async (event) => {\n const header =\n headerValue(event.headers, 'vinaverse-signature') ??\n headerValue(event.multiValueHeaders, 'vinaverse-signature');\n const raw = event.body ?? '';\n let body: string | Uint8Array;\n if (event.isBase64Encoded) {\n try {\n body = base64ToBytes(raw);\n } catch {\n body = new Uint8Array(0); // not base64: nothing can verify against it\n }\n } else {\n body = raw;\n }\n const response = await handleWebhook(options, body, header);\n return {\n statusCode: response.status,\n headers: { 'content-type': 'application/json' },\n body: response.body,\n };\n };\n}\n\nexport function base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\n/** The fields of an API Gateway (v1 or v2) or function URL event the tools handler reads. */\nexport interface LambdaToolEvent extends LambdaHttpEvent {\n /** v2 and function URLs: the path and query exactly as received. */\n version?: string;\n rawPath?: string;\n rawQueryString?: string;\n requestContext?: {\n http?: { method?: string };\n path?: string;\n httpMethod?: string;\n };\n /** v1. */\n httpMethod?: string;\n path?: string;\n multiValueQueryStringParameters?: Readonly<\n Record<string, readonly string[] | undefined>\n > | null;\n}\n\n/**\n * A Lambda handler serving a tenant's tools: `export const handler = createLambdaToolHandler(provider)`.\n *\n * The signature covers the request target exactly as sent. HTTP APIs\n * (payload v2) and function URLs pass it raw (`rawPath`, `rawQueryString`).\n * A REST API (payload v1) passes the query decoded, so it is encoded again the\n * way the Vinaverse API's client encodes it (form encoding: a space as `+`,\n * only `A-Z a-z 0-9 - . _ ~` left as they are), in the order API Gateway lists\n * the parameters: prefer an HTTP API or a function URL for tools.\n */\nexport function createLambdaToolHandler(\n provider: ToolProvider,\n): (event: LambdaToolEvent) => Promise<LambdaHttpResult> {\n return async (event) => {\n const v2 = event.version === '2.0' || event.rawPath !== undefined;\n const method =\n (v2\n ? event.requestContext?.http?.method\n : (event.httpMethod ?? event.requestContext?.httpMethod)) ?? 'GET';\n const target = v2\n ? `${event.rawPath ?? '/'}${event.rawQueryString ? `?${event.rawQueryString}` : ''}`\n : `${event.requestContext?.path ?? event.path ?? '/'}${formQuery(event.multiValueQueryStringParameters)}`;\n const raw = event.body ?? null;\n let body: string | Uint8Array | null = raw;\n if (raw !== null && event.isBase64Encoded) {\n try {\n body = base64ToBytes(raw);\n } catch {\n body = new Uint8Array(0);\n }\n }\n const headers = event.headers;\n const multi = event.multiValueHeaders;\n const response = await provider.handle({\n method,\n target,\n header: (name) => {\n const one = headerValue(headers, name);\n if (one !== undefined)\n return typeof one === 'string' ? one : one.join(', ');\n const many = headerValue(multi, name);\n return many === undefined\n ? undefined\n : typeof many === 'string'\n ? many\n : many.join(', ');\n },\n body,\n });\n return {\n statusCode: response.status,\n headers: { ...response.headers },\n body: response.body,\n };\n };\n}\n\n/** `?k=v&…` form-encoded as the Vinaverse API's client encodes it, or '' for none. */\nexport function formQuery(\n params:\n | Readonly<Record<string, readonly string[] | undefined>>\n | null\n | undefined,\n): string {\n const parts: string[] = [];\n for (const [key, values] of Object.entries(params ?? {})) {\n for (const value of values ?? [])\n parts.push(`${formEncode(key)}=${formEncode(value)}`);\n }\n return parts.length ? `?${parts.join('&')}` : '';\n}\n\nfunction formEncode(value: string): string {\n return encodeURIComponent(value)\n .replace(\n /[!'()*]/g,\n (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,\n )\n .replace(/%20/g, '+');\n}\n"]}
@@ -0,0 +1,53 @@
1
+ import { T as ToolProvider, W as WebhookHandlerOptions } from './provider-Miaa9V7I.cjs';
2
+ import './vinaverse-v1.d-BVc4uyUd.cjs';
3
+ import './nonces-scwljZwl.cjs';
4
+
5
+ /** The fields of an API Gateway (v1 or v2) or function URL event the handler reads. */
6
+ interface LambdaHttpEvent {
7
+ body?: string | null;
8
+ isBase64Encoded?: boolean;
9
+ headers?: Readonly<Record<string, string | undefined>> | null;
10
+ /** v1 only. */
11
+ multiValueHeaders?: Readonly<Record<string, readonly string[] | undefined>> | null;
12
+ }
13
+ /** A result both payload versions accept. */
14
+ interface LambdaHttpResult {
15
+ statusCode: number;
16
+ headers: Record<string, string>;
17
+ body: string;
18
+ }
19
+ declare function createLambdaWebhookHandler(options: WebhookHandlerOptions): (event: LambdaHttpEvent) => Promise<LambdaHttpResult>;
20
+ declare function base64ToBytes(base64: string): Uint8Array;
21
+ /** The fields of an API Gateway (v1 or v2) or function URL event the tools handler reads. */
22
+ interface LambdaToolEvent extends LambdaHttpEvent {
23
+ /** v2 and function URLs: the path and query exactly as received. */
24
+ version?: string;
25
+ rawPath?: string;
26
+ rawQueryString?: string;
27
+ requestContext?: {
28
+ http?: {
29
+ method?: string;
30
+ };
31
+ path?: string;
32
+ httpMethod?: string;
33
+ };
34
+ /** v1. */
35
+ httpMethod?: string;
36
+ path?: string;
37
+ multiValueQueryStringParameters?: Readonly<Record<string, readonly string[] | undefined>> | null;
38
+ }
39
+ /**
40
+ * A Lambda handler serving a tenant's tools: `export const handler = createLambdaToolHandler(provider)`.
41
+ *
42
+ * The signature covers the request target exactly as sent. HTTP APIs
43
+ * (payload v2) and function URLs pass it raw (`rawPath`, `rawQueryString`).
44
+ * A REST API (payload v1) passes the query decoded, so it is encoded again the
45
+ * way the Vinaverse API's client encodes it (form encoding: a space as `+`,
46
+ * only `A-Z a-z 0-9 - . _ ~` left as they are), in the order API Gateway lists
47
+ * the parameters: prefer an HTTP API or a function URL for tools.
48
+ */
49
+ declare function createLambdaToolHandler(provider: ToolProvider): (event: LambdaToolEvent) => Promise<LambdaHttpResult>;
50
+ /** `?k=v&…` form-encoded as the Vinaverse API's client encodes it, or '' for none. */
51
+ declare function formQuery(params: Readonly<Record<string, readonly string[] | undefined>> | null | undefined): string;
52
+
53
+ export { type LambdaHttpEvent, type LambdaHttpResult, type LambdaToolEvent, WebhookHandlerOptions, base64ToBytes, createLambdaToolHandler, createLambdaWebhookHandler, formQuery };
@@ -0,0 +1,53 @@
1
+ import { T as ToolProvider, W as WebhookHandlerOptions } from './provider-BqfTvF3g.js';
2
+ import './vinaverse-v1.d-BVc4uyUd.js';
3
+ import './nonces-scwljZwl.js';
4
+
5
+ /** The fields of an API Gateway (v1 or v2) or function URL event the handler reads. */
6
+ interface LambdaHttpEvent {
7
+ body?: string | null;
8
+ isBase64Encoded?: boolean;
9
+ headers?: Readonly<Record<string, string | undefined>> | null;
10
+ /** v1 only. */
11
+ multiValueHeaders?: Readonly<Record<string, readonly string[] | undefined>> | null;
12
+ }
13
+ /** A result both payload versions accept. */
14
+ interface LambdaHttpResult {
15
+ statusCode: number;
16
+ headers: Record<string, string>;
17
+ body: string;
18
+ }
19
+ declare function createLambdaWebhookHandler(options: WebhookHandlerOptions): (event: LambdaHttpEvent) => Promise<LambdaHttpResult>;
20
+ declare function base64ToBytes(base64: string): Uint8Array;
21
+ /** The fields of an API Gateway (v1 or v2) or function URL event the tools handler reads. */
22
+ interface LambdaToolEvent extends LambdaHttpEvent {
23
+ /** v2 and function URLs: the path and query exactly as received. */
24
+ version?: string;
25
+ rawPath?: string;
26
+ rawQueryString?: string;
27
+ requestContext?: {
28
+ http?: {
29
+ method?: string;
30
+ };
31
+ path?: string;
32
+ httpMethod?: string;
33
+ };
34
+ /** v1. */
35
+ httpMethod?: string;
36
+ path?: string;
37
+ multiValueQueryStringParameters?: Readonly<Record<string, readonly string[] | undefined>> | null;
38
+ }
39
+ /**
40
+ * A Lambda handler serving a tenant's tools: `export const handler = createLambdaToolHandler(provider)`.
41
+ *
42
+ * The signature covers the request target exactly as sent. HTTP APIs
43
+ * (payload v2) and function URLs pass it raw (`rawPath`, `rawQueryString`).
44
+ * A REST API (payload v1) passes the query decoded, so it is encoded again the
45
+ * way the Vinaverse API's client encodes it (form encoding: a space as `+`,
46
+ * only `A-Z a-z 0-9 - . _ ~` left as they are), in the order API Gateway lists
47
+ * the parameters: prefer an HTTP API or a function URL for tools.
48
+ */
49
+ declare function createLambdaToolHandler(provider: ToolProvider): (event: LambdaToolEvent) => Promise<LambdaHttpResult>;
50
+ /** `?k=v&…` form-encoded as the Vinaverse API's client encodes it, or '' for none. */
51
+ declare function formQuery(params: Readonly<Record<string, readonly string[] | undefined>> | null | undefined): string;
52
+
53
+ export { type LambdaHttpEvent, type LambdaHttpResult, type LambdaToolEvent, WebhookHandlerOptions, base64ToBytes, createLambdaToolHandler, createLambdaWebhookHandler, formQuery };
package/dist/lambda.js ADDED
@@ -0,0 +1,86 @@
1
+ import { checkHandlerOptions, headerValue, handleWebhook } from './chunk-FEEJNQXV.js';
2
+ import './chunk-GTPMQKGX.js';
3
+
4
+ // src/adapters/lambda.ts
5
+ function createLambdaWebhookHandler(options) {
6
+ checkHandlerOptions(options);
7
+ return async (event) => {
8
+ const header = headerValue(event.headers, "vinaverse-signature") ?? headerValue(event.multiValueHeaders, "vinaverse-signature");
9
+ const raw = event.body ?? "";
10
+ let body;
11
+ if (event.isBase64Encoded) {
12
+ try {
13
+ body = base64ToBytes(raw);
14
+ } catch {
15
+ body = new Uint8Array(0);
16
+ }
17
+ } else {
18
+ body = raw;
19
+ }
20
+ const response = await handleWebhook(options, body, header);
21
+ return {
22
+ statusCode: response.status,
23
+ headers: { "content-type": "application/json" },
24
+ body: response.body
25
+ };
26
+ };
27
+ }
28
+ function base64ToBytes(base64) {
29
+ const binary = atob(base64);
30
+ const bytes = new Uint8Array(binary.length);
31
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
32
+ return bytes;
33
+ }
34
+ function createLambdaToolHandler(provider) {
35
+ return async (event) => {
36
+ const v2 = event.version === "2.0" || event.rawPath !== void 0;
37
+ const method = (v2 ? event.requestContext?.http?.method : event.httpMethod ?? event.requestContext?.httpMethod) ?? "GET";
38
+ const target = v2 ? `${event.rawPath ?? "/"}${event.rawQueryString ? `?${event.rawQueryString}` : ""}` : `${event.requestContext?.path ?? event.path ?? "/"}${formQuery(event.multiValueQueryStringParameters)}`;
39
+ const raw = event.body ?? null;
40
+ let body = raw;
41
+ if (raw !== null && event.isBase64Encoded) {
42
+ try {
43
+ body = base64ToBytes(raw);
44
+ } catch {
45
+ body = new Uint8Array(0);
46
+ }
47
+ }
48
+ const headers = event.headers;
49
+ const multi = event.multiValueHeaders;
50
+ const response = await provider.handle({
51
+ method,
52
+ target,
53
+ header: (name) => {
54
+ const one = headerValue(headers, name);
55
+ if (one !== void 0)
56
+ return typeof one === "string" ? one : one.join(", ");
57
+ const many = headerValue(multi, name);
58
+ return many === void 0 ? void 0 : typeof many === "string" ? many : many.join(", ");
59
+ },
60
+ body
61
+ });
62
+ return {
63
+ statusCode: response.status,
64
+ headers: { ...response.headers },
65
+ body: response.body
66
+ };
67
+ };
68
+ }
69
+ function formQuery(params) {
70
+ const parts = [];
71
+ for (const [key, values] of Object.entries(params ?? {})) {
72
+ for (const value of values ?? [])
73
+ parts.push(`${formEncode(key)}=${formEncode(value)}`);
74
+ }
75
+ return parts.length ? `?${parts.join("&")}` : "";
76
+ }
77
+ function formEncode(value) {
78
+ return encodeURIComponent(value).replace(
79
+ /[!'()*]/g,
80
+ (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
81
+ ).replace(/%20/g, "+");
82
+ }
83
+
84
+ export { base64ToBytes, createLambdaToolHandler, createLambdaWebhookHandler, formQuery };
85
+ //# sourceMappingURL=lambda.js.map
86
+ //# sourceMappingURL=lambda.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/lambda.ts"],"names":[],"mappings":"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","file":"lambda.js","sourcesContent":["// AWS Lambda behind API Gateway (REST API, payload v1; HTTP API, payload v2)\n// or a function URL (payload v2). Both payloads carry the body as a string,\n// base64-encoded when `isBase64Encoded` is true; the signature is over the\n// bytes Vinaverse sent, so a base64 body is decoded to bytes, never read as text.\n//\n// export const handler = createLambdaWebhookHandler({ secret, onEvent });\nimport {\n checkHandlerOptions,\n handleWebhook,\n headerValue,\n type WebhookHandlerOptions,\n} from './handler.js';\n\nexport type { WebhookHandlerOptions } from './handler.js';\n\nimport type { ToolProvider } from '../tools/provider.js';\n\n/** The fields of an API Gateway (v1 or v2) or function URL event the handler reads. */\nexport interface LambdaHttpEvent {\n body?: string | null;\n isBase64Encoded?: boolean;\n headers?: Readonly<Record<string, string | undefined>> | null;\n /** v1 only. */\n multiValueHeaders?: Readonly<\n Record<string, readonly string[] | undefined>\n > | null;\n}\n\n/** A result both payload versions accept. */\nexport interface LambdaHttpResult {\n statusCode: number;\n headers: Record<string, string>;\n body: string;\n}\n\nexport function createLambdaWebhookHandler(\n options: WebhookHandlerOptions,\n): (event: LambdaHttpEvent) => Promise<LambdaHttpResult> {\n checkHandlerOptions(options);\n return async (event) => {\n const header =\n headerValue(event.headers, 'vinaverse-signature') ??\n headerValue(event.multiValueHeaders, 'vinaverse-signature');\n const raw = event.body ?? '';\n let body: string | Uint8Array;\n if (event.isBase64Encoded) {\n try {\n body = base64ToBytes(raw);\n } catch {\n body = new Uint8Array(0); // not base64: nothing can verify against it\n }\n } else {\n body = raw;\n }\n const response = await handleWebhook(options, body, header);\n return {\n statusCode: response.status,\n headers: { 'content-type': 'application/json' },\n body: response.body,\n };\n };\n}\n\nexport function base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\n/** The fields of an API Gateway (v1 or v2) or function URL event the tools handler reads. */\nexport interface LambdaToolEvent extends LambdaHttpEvent {\n /** v2 and function URLs: the path and query exactly as received. */\n version?: string;\n rawPath?: string;\n rawQueryString?: string;\n requestContext?: {\n http?: { method?: string };\n path?: string;\n httpMethod?: string;\n };\n /** v1. */\n httpMethod?: string;\n path?: string;\n multiValueQueryStringParameters?: Readonly<\n Record<string, readonly string[] | undefined>\n > | null;\n}\n\n/**\n * A Lambda handler serving a tenant's tools: `export const handler = createLambdaToolHandler(provider)`.\n *\n * The signature covers the request target exactly as sent. HTTP APIs\n * (payload v2) and function URLs pass it raw (`rawPath`, `rawQueryString`).\n * A REST API (payload v1) passes the query decoded, so it is encoded again the\n * way the Vinaverse API's client encodes it (form encoding: a space as `+`,\n * only `A-Z a-z 0-9 - . _ ~` left as they are), in the order API Gateway lists\n * the parameters: prefer an HTTP API or a function URL for tools.\n */\nexport function createLambdaToolHandler(\n provider: ToolProvider,\n): (event: LambdaToolEvent) => Promise<LambdaHttpResult> {\n return async (event) => {\n const v2 = event.version === '2.0' || event.rawPath !== undefined;\n const method =\n (v2\n ? event.requestContext?.http?.method\n : (event.httpMethod ?? event.requestContext?.httpMethod)) ?? 'GET';\n const target = v2\n ? `${event.rawPath ?? '/'}${event.rawQueryString ? `?${event.rawQueryString}` : ''}`\n : `${event.requestContext?.path ?? event.path ?? '/'}${formQuery(event.multiValueQueryStringParameters)}`;\n const raw = event.body ?? null;\n let body: string | Uint8Array | null = raw;\n if (raw !== null && event.isBase64Encoded) {\n try {\n body = base64ToBytes(raw);\n } catch {\n body = new Uint8Array(0);\n }\n }\n const headers = event.headers;\n const multi = event.multiValueHeaders;\n const response = await provider.handle({\n method,\n target,\n header: (name) => {\n const one = headerValue(headers, name);\n if (one !== undefined)\n return typeof one === 'string' ? one : one.join(', ');\n const many = headerValue(multi, name);\n return many === undefined\n ? undefined\n : typeof many === 'string'\n ? many\n : many.join(', ');\n },\n body,\n });\n return {\n statusCode: response.status,\n headers: { ...response.headers },\n body: response.body,\n };\n };\n}\n\n/** `?k=v&…` form-encoded as the Vinaverse API's client encodes it, or '' for none. */\nexport function formQuery(\n params:\n | Readonly<Record<string, readonly string[] | undefined>>\n | null\n | undefined,\n): string {\n const parts: string[] = [];\n for (const [key, values] of Object.entries(params ?? {})) {\n for (const value of values ?? [])\n parts.push(`${formEncode(key)}=${formEncode(value)}`);\n }\n return parts.length ? `?${parts.join('&')}` : '';\n}\n\nfunction formEncode(value: string): string {\n return encodeURIComponent(value)\n .replace(\n /[!'()*]/g,\n (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,\n )\n .replace(/%20/g, '+');\n}\n"]}
@@ -0,0 +1,92 @@
1
+ /** What a store holds for a key. `pending` while the first call runs. */
2
+ interface IdempotencyRecord {
3
+ /** The hex SHA-256 of what the call asked (never the request itself). */
4
+ readonly fingerprint: string;
5
+ readonly state: 'pending' | 'done';
6
+ /** The stored answer, once done. */
7
+ readonly status?: number;
8
+ readonly body?: string;
9
+ }
10
+ /**
11
+ * Every write is tied to the call that started the key (`owner`, random per
12
+ * call): a call whose pending lease lapsed and was taken by another can
13
+ * neither store its answer over that call's nor release that call's lease.
14
+ */
15
+ interface IdempotencyStore {
16
+ /**
17
+ * Creates a pending record for `key`, held by `owner`, and returns null, or,
18
+ * when one exists, returns it unchanged. Must be atomic across every
19
+ * instance sharing the store. A pending record lapses after
20
+ * `pendingSeconds`, so a call that crashed does not hold its key forever.
21
+ */
22
+ start(key: string, fingerprint: string, pendingSeconds: number, owner: string): Promise<IdempotencyRecord | null>;
23
+ /**
24
+ * Stores the answer for `key`, kept for `keepSeconds`, when `owner` still
25
+ * holds the pending record (or nobody holds the key); returns false and
26
+ * stores nothing when another call holds it or has answered.
27
+ */
28
+ finish(key: string, record: {
29
+ fingerprint: string;
30
+ status: number;
31
+ body: string;
32
+ }, keepSeconds: number, owner: string): Promise<boolean>;
33
+ /** Drops the record if `owner` still holds it pending (the call failed without an answer to keep). */
34
+ release(key: string, owner: string): Promise<void>;
35
+ }
36
+ /**
37
+ * An in-process store: right for one instance and for tests. Expired records
38
+ * are dropped on one `start` in `sweepEvery` (default 256).
39
+ */
40
+ declare class MemoryIdempotencyStore implements IdempotencyStore {
41
+ #private;
42
+ constructor(options?: {
43
+ now?: () => number;
44
+ sweepEvery?: number;
45
+ });
46
+ start(key: string, fingerprint: string, pendingSeconds: number, owner: string): Promise<IdempotencyRecord | null>;
47
+ finish(key: string, record: {
48
+ fingerprint: string;
49
+ status: number;
50
+ body: string;
51
+ }, keepSeconds: number, owner: string): Promise<boolean>;
52
+ release(key: string, owner: string): Promise<void>;
53
+ /** Records held, expired ones included until a sweep drops them. */
54
+ get size(): number;
55
+ }
56
+ /** The fingerprint of a request: the hex SHA-256 of its canonical JSON. */
57
+ declare function fingerprint(value: unknown): Promise<string>;
58
+ /**
59
+ * JSON with keys sorted at every level and no insignificant whitespace, so
60
+ * two bodies equal as JSON (key order aside, numbers by value: `1` and `1.0`)
61
+ * have one fingerprint.
62
+ */
63
+ declare function canonicalJson(value: unknown): string;
64
+
65
+ /** Keep each nonce this long after the call's `t` (the contract's minimum is the 300-second window). */
66
+ declare const NONCE_KEEP_SECONDS = 360;
67
+ interface NonceStore {
68
+ /**
69
+ * Takes `nonce` until `keepUntil` (Unix seconds): true the first time it is
70
+ * seen, false for a replay. Must be atomic across every instance that
71
+ * shares the store.
72
+ */
73
+ claim(nonce: string, keepUntil: number): Promise<boolean>;
74
+ }
75
+ /**
76
+ * An in-process store: right for one instance (a single server, tests, one
77
+ * Lambda with reserved concurrency of 1). Behind several instances, use a
78
+ * shared store (`@vinaverse/server/stores`: Redis, DynamoDB, Postgres).
79
+ * Expired nonces are dropped on one claim in `sweepEvery` (default 256).
80
+ */
81
+ declare class MemoryNonceStore implements NonceStore {
82
+ #private;
83
+ constructor(options?: {
84
+ now?: () => number;
85
+ sweepEvery?: number;
86
+ });
87
+ claim(nonce: string, keepUntil: number): Promise<boolean>;
88
+ /** Nonces held, expired ones included until a sweep drops them. */
89
+ get size(): number;
90
+ }
91
+
92
+ export { type IdempotencyRecord as I, MemoryIdempotencyStore as M, NONCE_KEEP_SECONDS as N, type IdempotencyStore as a, MemoryNonceStore as b, type NonceStore as c, canonicalJson as d, fingerprint as f };
@@ -0,0 +1,92 @@
1
+ /** What a store holds for a key. `pending` while the first call runs. */
2
+ interface IdempotencyRecord {
3
+ /** The hex SHA-256 of what the call asked (never the request itself). */
4
+ readonly fingerprint: string;
5
+ readonly state: 'pending' | 'done';
6
+ /** The stored answer, once done. */
7
+ readonly status?: number;
8
+ readonly body?: string;
9
+ }
10
+ /**
11
+ * Every write is tied to the call that started the key (`owner`, random per
12
+ * call): a call whose pending lease lapsed and was taken by another can
13
+ * neither store its answer over that call's nor release that call's lease.
14
+ */
15
+ interface IdempotencyStore {
16
+ /**
17
+ * Creates a pending record for `key`, held by `owner`, and returns null, or,
18
+ * when one exists, returns it unchanged. Must be atomic across every
19
+ * instance sharing the store. A pending record lapses after
20
+ * `pendingSeconds`, so a call that crashed does not hold its key forever.
21
+ */
22
+ start(key: string, fingerprint: string, pendingSeconds: number, owner: string): Promise<IdempotencyRecord | null>;
23
+ /**
24
+ * Stores the answer for `key`, kept for `keepSeconds`, when `owner` still
25
+ * holds the pending record (or nobody holds the key); returns false and
26
+ * stores nothing when another call holds it or has answered.
27
+ */
28
+ finish(key: string, record: {
29
+ fingerprint: string;
30
+ status: number;
31
+ body: string;
32
+ }, keepSeconds: number, owner: string): Promise<boolean>;
33
+ /** Drops the record if `owner` still holds it pending (the call failed without an answer to keep). */
34
+ release(key: string, owner: string): Promise<void>;
35
+ }
36
+ /**
37
+ * An in-process store: right for one instance and for tests. Expired records
38
+ * are dropped on one `start` in `sweepEvery` (default 256).
39
+ */
40
+ declare class MemoryIdempotencyStore implements IdempotencyStore {
41
+ #private;
42
+ constructor(options?: {
43
+ now?: () => number;
44
+ sweepEvery?: number;
45
+ });
46
+ start(key: string, fingerprint: string, pendingSeconds: number, owner: string): Promise<IdempotencyRecord | null>;
47
+ finish(key: string, record: {
48
+ fingerprint: string;
49
+ status: number;
50
+ body: string;
51
+ }, keepSeconds: number, owner: string): Promise<boolean>;
52
+ release(key: string, owner: string): Promise<void>;
53
+ /** Records held, expired ones included until a sweep drops them. */
54
+ get size(): number;
55
+ }
56
+ /** The fingerprint of a request: the hex SHA-256 of its canonical JSON. */
57
+ declare function fingerprint(value: unknown): Promise<string>;
58
+ /**
59
+ * JSON with keys sorted at every level and no insignificant whitespace, so
60
+ * two bodies equal as JSON (key order aside, numbers by value: `1` and `1.0`)
61
+ * have one fingerprint.
62
+ */
63
+ declare function canonicalJson(value: unknown): string;
64
+
65
+ /** Keep each nonce this long after the call's `t` (the contract's minimum is the 300-second window). */
66
+ declare const NONCE_KEEP_SECONDS = 360;
67
+ interface NonceStore {
68
+ /**
69
+ * Takes `nonce` until `keepUntil` (Unix seconds): true the first time it is
70
+ * seen, false for a replay. Must be atomic across every instance that
71
+ * shares the store.
72
+ */
73
+ claim(nonce: string, keepUntil: number): Promise<boolean>;
74
+ }
75
+ /**
76
+ * An in-process store: right for one instance (a single server, tests, one
77
+ * Lambda with reserved concurrency of 1). Behind several instances, use a
78
+ * shared store (`@vinaverse/server/stores`: Redis, DynamoDB, Postgres).
79
+ * Expired nonces are dropped on one claim in `sweepEvery` (default 256).
80
+ */
81
+ declare class MemoryNonceStore implements NonceStore {
82
+ #private;
83
+ constructor(options?: {
84
+ now?: () => number;
85
+ sweepEvery?: number;
86
+ });
87
+ claim(nonce: string, keepUntil: number): Promise<boolean>;
88
+ /** Nonces held, expired ones included until a sweep drops them. */
89
+ get size(): number;
90
+ }
91
+
92
+ export { type IdempotencyRecord as I, MemoryIdempotencyStore as M, NONCE_KEEP_SECONDS as N, type IdempotencyStore as a, MemoryNonceStore as b, type NonceStore as c, canonicalJson as d, fingerprint as f };