@josephomills/esign 0.7.1 → 0.9.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/tokens.ts","../../src/server/audit-chain.ts","../../src/server/errors.ts","../../src/server/types.ts","../../src/server/uid.ts","../../src/server/campaign.ts","../../src/server/coverage.ts","../../src/server/delete.ts","../../src/server/documents.ts","../../src/server/route-utils.ts","../../src/server/flow.ts","../../src/server/audit-cert.ts","../../src/server/seal.ts","../../src/server/sign.ts","../../src/server/routes/sign-actions.ts","../../src/server/routes/sign-serve.ts","../../src/server/configure.ts","../../src/server/subjects.ts"],"names":["createHash","randomBytes","z","ok","PDFDocument","rgb","StandardFonts"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\n\n/**\n * No-login signer token. We follow the share-link convention from the host\n * apps: generate a random token, return the cleartext exactly once (it goes\n * only into the `/sign/<token>` URL), and persist nothing but its sha256. A\n * leaked database never yields a usable link.\n */\nexport interface SigningToken {\n /** Goes into the signer URL only — never stored. */\n cleartext: string;\n /** sha256(cleartext) — the value stored in `SigningRequest.tokenHash`. */\n tokenHash: string;\n}\n\n/** sha256 of a string or bytes, lowercase hex (64 chars). */\nexport function sha256Hex(input: string | Uint8Array): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\n/** A fresh signing token. `bytes` of entropy, base64url-encoded cleartext. */\nexport function newSigningToken(bytes = 32): SigningToken {\n const cleartext = randomBytes(bytes).toString(\"base64url\");\n return { cleartext, tokenHash: sha256Hex(cleartext) };\n}\n","import { sha256Hex } from \"./tokens\";\n\n/**\n * Tamper-evident audit log (Level-1 seal). Every signing request accumulates an\n * append-only chain of events (CREATED → NOTIFIED → VIEWED → CONSENTED → SIGNED\n * → SEALED). Each link's `hash` covers the previous hash plus this link's\n * contents, so altering any earlier event invalidates every hash after it. The\n * chain is rendered onto the sealed PDF's certificate page and re-checkable with\n * `verifyChain`.\n */\n\nexport interface AuditEventInput {\n type: string;\n payload: Record<string, unknown>;\n /** ISO instant; passed in (never `Date.now()`) so seals are reproducible. */\n occurredAt: string;\n}\n\nexport interface AuditLink extends AuditEventInput {\n seq: number;\n prevHash: string | null;\n hash: string;\n}\n\n/** Deterministic JSON: object keys sorted, `undefined` normalized to null. */\nexport function canonicalize(value: unknown): string {\n if (value === undefined) return \"null\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalize).join(\",\")}]`;\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`).join(\",\")}}`;\n}\n\n/** The hash bound into a link: sha256(prevHash | seq | type | occurredAt | payload). */\nexport function linkHash(\n prevHash: string | null,\n seq: number,\n type: string,\n occurredAt: string,\n payload: unknown,\n): string {\n return sha256Hex(\n `${prevHash ?? \"\"}|${seq}|${type}|${occurredAt}|${canonicalize(payload)}`,\n );\n}\n\n/** Append one event to a chain (or start it when `prev` is null). */\nexport function appendEvent(\n prev: AuditLink | null,\n input: AuditEventInput,\n): AuditLink {\n const seq = prev ? prev.seq + 1 : 0;\n const prevHash = prev ? prev.hash : null;\n const hash = linkHash(prevHash, seq, input.type, input.occurredAt, input.payload);\n return { ...input, seq, prevHash, hash };\n}\n\n/** Fold a list of events into a verified chain. */\nexport function buildChain(inputs: AuditEventInput[]): AuditLink[] {\n const out: AuditLink[] = [];\n let prev: AuditLink | null = null;\n for (const input of inputs) {\n prev = appendEvent(prev, input);\n out.push(prev);\n }\n return out;\n}\n\n/** Recompute every hash; `brokenAt` is the seq of the first bad link, else null. */\nexport function verifyChain(links: AuditLink[]): {\n ok: boolean;\n brokenAt: number | null;\n} {\n let prev: AuditLink | null = null;\n for (const link of links) {\n const expectedSeq = prev ? prev.seq + 1 : 0;\n const expectedPrev = prev ? prev.hash : null;\n const expectedHash = linkHash(\n expectedPrev,\n link.seq,\n link.type,\n link.occurredAt,\n link.payload,\n );\n if (\n link.seq !== expectedSeq ||\n link.prevHash !== expectedPrev ||\n link.hash !== expectedHash\n ) {\n return { ok: false, brokenAt: link.seq };\n }\n prev = link;\n }\n return { ok: true, brokenAt: null };\n}\n","export type EsignErrorCode =\n | \"UNAUTHENTICATED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"INVALID_INPUT\"\n | \"CONFLICT\"\n | \"GONE\"\n | \"RATE_LIMITED\"\n | \"PAYLOAD_TOO_LARGE\"\n | \"STORAGE_ERROR\"\n | \"INTERNAL\";\n\nexport class EsignError extends Error {\n readonly code: EsignErrorCode;\n readonly details?: unknown;\n readonly status: number;\n\n constructor(code: EsignErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = \"EsignError\";\n this.code = code;\n this.details = details;\n this.status = statusFor(code);\n }\n}\n\nfunction statusFor(code: EsignErrorCode): number {\n switch (code) {\n case \"UNAUTHENTICATED\":\n return 401;\n case \"FORBIDDEN\":\n return 403;\n case \"NOT_FOUND\":\n return 404;\n case \"INVALID_INPUT\":\n return 422;\n case \"CONFLICT\":\n return 409;\n case \"GONE\":\n return 410;\n case \"RATE_LIMITED\":\n return 429;\n case \"PAYLOAD_TOO_LARGE\":\n return 413;\n case \"STORAGE_ERROR\":\n return 502;\n case \"INTERNAL\":\n default:\n return 500;\n }\n}\n\nexport function toErrorResponse(err: unknown): Response {\n if (err instanceof EsignError) {\n return Response.json(\n { error: { code: err.code, message: err.message, details: err.details } },\n { status: err.status },\n );\n }\n console.error(\"[esign] unexpected error\", err);\n return Response.json(\n { error: { code: \"INTERNAL\", message: \"Unexpected error.\" } },\n { status: 500 },\n );\n}\n","import { z } from \"zod\";\n\nimport type { EsignStatus } from \"./flow\";\n\n// ---------------------------------------------------------------------------\n// Channels\n// ---------------------------------------------------------------------------\n\n// Mirrors the host Channel enum (dhm-estates: EMAIL/TELEGRAM/SMS/WHATSAPP). A\n// host only offers the channels its NotifierPort.configuredChannels() reports,\n// so listing all four here costs nothing when some aren't wired yet.\nexport type EsignChannel = \"EMAIL\" | \"TELEGRAM\" | \"SMS\" | \"WHATSAPP\";\nexport const ESIGN_CHANNELS: readonly EsignChannel[] = [\n \"EMAIL\",\n \"TELEGRAM\",\n \"SMS\",\n \"WHATSAPP\",\n];\nexport const esignChannelSchema = z.enum([\"EMAIL\", \"TELEGRAM\", \"SMS\", \"WHATSAPP\"]);\n\n// ---------------------------------------------------------------------------\n// Signature placement — normalized 0..1 fractions of the target page, origin\n// top-left (the designer's coordinate space). Converted to pdf-lib's\n// bottom-left space at seal time using the page's real width/height.\n// ---------------------------------------------------------------------------\n\nexport interface Placement {\n page: number; // 1-based\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nconst unit = z.number().min(0).max(1);\nexport const placementSchema = z\n .object({\n page: z.number().int().min(1),\n x: unit,\n y: unit,\n w: z.number().min(0.01).max(1),\n h: z.number().min(0.01).max(1),\n })\n .strict();\n\n/**\n * A named signature field — a placement with an id + label. A document version\n * carries one or more; the signer signs once and the signature is stamped at\n * every field. Labels organize the fields in the designer (\"Signature\", \"Initials\n * page 2\", …); the signer always sees \"Sign here\".\n */\nexport interface SignatureField extends Placement {\n id: string;\n label: string;\n}\n\nexport const signatureFieldSchema = placementSchema.extend({\n id: z.string().min(1).max(64),\n label: z.string().trim().max(80),\n});\nexport const placementsSchema = z.array(signatureFieldSchema).min(1).max(20);\n\n// ---------------------------------------------------------------------------\n// Subjects + targeting\n// ---------------------------------------------------------------------------\n\n/** A resolved recipient — the only thing the fan-out needs. subjectId = the host's profileId. */\nexport interface Recipient {\n name: string;\n email?: string | null;\n /** Phone for SMS (and WhatsApp when `whatsapp` is absent). */\n phone?: string | null;\n whatsapp?: string | null;\n subjectType: string;\n subjectId: string;\n /** Snapshot of the targeted classification, persisted as SigningRequest.subjectGroup. */\n group?: string | null;\n}\n\n/** Resolve the address to use for a channel from a recipient's contacts. */\nexport function addressFor(\n recipient: Recipient,\n channel: EsignChannel,\n): string | null {\n switch (channel) {\n case \"EMAIL\":\n return recipient.email ?? null;\n case \"SMS\":\n return recipient.phone ?? null;\n case \"WHATSAPP\":\n return recipient.whatsapp ?? recipient.phone ?? null;\n case \"TELEGRAM\":\n return null; // host wires a Telegram address resolver when that channel lands\n }\n}\n\n/** A subject row rendered by the targeting picker. */\nexport interface SubjectSummary {\n subjectType: string;\n subjectId: string;\n label: string;\n sublabel?: string;\n group?: string | null;\n groupLabel?: string | null;\n eligible: boolean;\n ineligibleReason?: string;\n}\n\n/** A subject that could not be sent to at resolve time. */\nexport interface SkippedSubject {\n subjectType: string;\n subjectId: string;\n label: string;\n reason: string;\n}\n\n/** A declarative filter facet the picker renders as a control. */\nexport interface SubjectFilterField {\n key: string;\n label: string;\n kind: \"enum\" | \"boolean\" | \"text\" | \"scope\";\n options?: { value: string; label: string }[];\n}\n\nexport type SubjectFilter = Record<\n string,\n string | boolean | string[] | undefined\n>;\n\n/**\n * How a target is expressed. \"all\" sends to the whole group (optionally a\n * classification + filters); \"ids\" sends to an explicit subset.\n */\nexport type SubjectSelection =\n | { mode: \"all\"; type: string; group?: string; filter?: SubjectFilter }\n | { mode: \"ids\"; type: string; subjectIds: string[] };\n\nexport const subjectSelectionSchema: z.ZodType<SubjectSelection> = z.union([\n z\n .object({\n mode: z.literal(\"all\"),\n type: z.string().min(1),\n group: z.string().min(1).optional(),\n filter: z.record(z.unknown()).optional() as z.ZodType<\n SubjectFilter | undefined\n >,\n })\n .strict(),\n z\n .object({\n mode: z.literal(\"ids\"),\n type: z.string().min(1),\n subjectIds: z.array(z.string().min(1)).min(1),\n })\n .strict(),\n]);\n\n/** Restrict a resend to a subset of the live group, diffed against existing requests. */\nexport type ResendPolicy = \"all\" | \"outstanding\" | \"olderVersion\" | \"uncovered\";\n\n/** Whether a green-check requires the current version or any version. */\nexport type VersionPolicy = \"current\" | \"any\";\n\n// ---------------------------------------------------------------------------\n// Read DTOs\n// ---------------------------------------------------------------------------\n\nexport interface SigningDocumentDTO {\n id: string;\n scopeId: string | null;\n documentType: string | null;\n title: string;\n audience: SubjectSelection | null;\n currentVersionId: string | null;\n createdById: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SigningDocumentVersionDTO {\n id: string;\n documentId: string;\n version: number;\n sourceObjectKey: string;\n sourceSha256: string;\n placements: SignatureField[];\n changeNote: string | null;\n createdById: string | null;\n createdAt: string;\n}\n\nexport interface SigningCampaignDTO {\n id: string;\n documentId: string;\n documentVersionId: string;\n scopeId: string | null;\n note: string | null;\n emailReceipt: boolean;\n targeting: SubjectSelection;\n expiresAt: string;\n createdById: string | null;\n createdAt: string;\n}\n\nexport interface SigningRequestDTO {\n id: string;\n campaignId: string;\n documentId: string;\n documentVersionId: string;\n scopeId: string | null;\n subjectType: string;\n subjectId: string;\n subjectGroup: string | null;\n recipientName: string;\n recipientEmail: string | null;\n recipientWhatsapp: string | null;\n channels: EsignChannel[];\n status: EsignStatus;\n viewedAt: string | null;\n signedAt: string | null;\n declinedAt: string | null;\n expiresAt: string;\n revokedAt: string | null;\n sealedObjectKey: string | null;\n sealedSha256: string | null;\n createdAt: string;\n}\n\nexport interface SigningAuditEventDTO {\n id: string;\n requestId: string;\n seq: number;\n type: string;\n payload: unknown;\n prevHash: string | null;\n hash: string;\n occurredAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Green-check + stats result shapes\n// ---------------------------------------------------------------------------\n\nexport type SubjectSigningState =\n | \"NONE\"\n | \"PENDING\"\n | \"VIEWED\"\n | \"SIGNED\"\n | \"DECLINED\"\n | \"NEEDS_RESIGN\";\n\nexport interface SubjectSigningStatus {\n state: SubjectSigningState;\n signedAt: string | null;\n signedVersion: number | null;\n requestId: string | null;\n sealedObjectKey: string | null;\n}\n\nexport type StatusCountMap = Record<EsignStatus, number>;\n\nexport interface OutstandingRequest {\n id: string;\n campaignId: string;\n documentId: string;\n subjectType: string;\n subjectId: string;\n recipientName: string;\n channels: EsignChannel[];\n status: Extract<EsignStatus, \"PENDING\" | \"VIEWED\">;\n viewedAt: string | null;\n createdAt: string;\n expiresAt: string;\n}\n\nexport interface GroupBreakdown {\n group: string | null;\n counts: StatusCountMap;\n total: number;\n}\n\nexport interface CampaignStatsRow {\n campaignId: string;\n counts: StatusCountMap;\n total: number;\n viewedNotSigned: number;\n completionRate: number;\n avgTimeToSignMs: number | null;\n byGroup: GroupBreakdown[];\n outstanding: OutstandingRequest[];\n}\n\nexport interface DocumentStatsRow {\n documentId: string;\n counts: StatusCountMap;\n total: number;\n completionRate: number;\n byGroup: GroupBreakdown[];\n bySubjectType: { subjectType: string; counts: StatusCountMap; total: number }[];\n}\n\nexport interface ScopeStatsRow {\n campaignsSent: number;\n requestsSent: number;\n counts: StatusCountMap;\n completionRate: number;\n bySubjectType: { subjectType: string; counts: StatusCountMap; total: number }[];\n oldestOutstanding: OutstandingRequest[];\n}\n\nexport interface StatsRange {\n from?: Date;\n to?: Date;\n}\n\n/** documentCoverage() result — re-derived from the live group every call. */\nexport interface CoverageReport {\n documentId: string;\n totalNow: number;\n signed: number;\n outstanding: number;\n needsResign: number;\n uncovered: SubjectSummary[];\n departed: { subjectType: string; subjectId: string }[];\n}\n\n// ---------------------------------------------------------------------------\n// Signer-side request bodies\n// ---------------------------------------------------------------------------\n\n/** A drawn or typed signature, as a PNG data URL produced by the signer UI. */\nexport const submitSignatureSchema = z\n .object({\n signaturePng: z.string().min(1).max(1_500_000), // ~1MB cap on the data URL\n signerName: z.string().trim().min(1).max(200),\n consent: z.literal(true),\n })\n .strict();\nexport type SubmitSignatureInput = z.infer<typeof submitSignatureSchema>;\n\nexport const declineSchema = z\n .object({ reason: z.string().trim().max(500).optional() })\n .strict();\nexport type DeclineInput = z.infer<typeof declineSchema>;\n","import { randomBytes } from \"node:crypto\";\n\n// 62-char URL-safe alphabet. 16 chars ≈ 95 bits of entropy — ample for row ids.\nconst ALPHABET =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\n/**\n * A 16-char unique id, matching the host `@db.VarChar(16)` convention. The\n * package generates ids in code (the Prisma fragment carries no `@default`), so\n * every esign-owned row gets a uid the same way across dhm-estates / flc-missions\n * / flc-hr. Rejection sampling keeps the distribution uniform (no modulo bias).\n */\nexport function uid(size = 16): string {\n let out = \"\";\n while (out.length < size) {\n for (const byte of randomBytes(size)) {\n if (byte < 248) {\n // 248 = floor(256 / 62) * 62 — discard the biased tail.\n out += ALPHABET[byte % 62];\n if (out.length === size) break;\n }\n }\n }\n return out;\n}\n","import { appendEvent, type AuditEventInput, type AuditLink } from \"./audit-chain\";\nimport { EsignError } from \"./errors\";\nimport type {\n Clock,\n NewRequestRow,\n NotifierPort,\n PersistencePort,\n SubjectsPort,\n} from \"./ports\";\nimport { newSigningToken } from \"./tokens\";\nimport {\n addressFor,\n type EsignChannel,\n type ResendPolicy,\n type SkippedSubject,\n type SubjectSelection,\n} from \"./types\";\nimport { uid } from \"./uid\";\n\n/**\n * Persist one audit link and return it, so the caller can thread the chain tip\n * into the next event. Shared by the fan-out here and the signer submit handler.\n */\nexport async function recordEvent(\n persistence: PersistencePort,\n requestId: string,\n prev: AuditLink | null,\n input: AuditEventInput,\n): Promise<AuditLink> {\n const link = appendEvent(prev, input);\n await persistence.appendAuditEvent({\n requestId,\n seq: link.seq,\n type: link.type,\n payload: link.payload,\n prevHash: link.prevHash,\n hash: link.hash,\n });\n return link;\n}\n\nexport interface ChannelContent {\n subject: string;\n body: string;\n}\n\nexport type CampaignContentBuilder = (ctx: {\n documentTitle: string;\n note: string | null;\n recipientName: string;\n}) => ChannelContent;\n\nconst defaultContent: CampaignContentBuilder = ({\n documentTitle,\n note,\n recipientName,\n}) => ({\n subject: `Please sign: ${documentTitle}`,\n body: [\n `Hello ${recipientName},`,\n note ?? `You have a document to review and sign: ${documentTitle}.`,\n \"Open the secure link to sign — no account or login needed.\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n});\n\nexport interface CreateCampaignDeps {\n persistence: PersistencePort;\n subjects: SubjectsPort;\n notifier: NotifierPort;\n clock: Clock;\n baseUrl: string;\n defaultExpiryDays: number;\n content?: CampaignContentBuilder;\n}\n\nexport interface CreateCampaignArgs {\n /** Opaque host scope (estate id / country id / null) — already authorized by the route. */\n scopeId?: string | null;\n documentVersionId: string;\n selection: SubjectSelection;\n channels: EsignChannel[];\n note?: string | null;\n emailReceipt?: boolean;\n expiresInDays?: number;\n resendPolicy?: ResendPolicy;\n createdById?: string | null;\n}\n\nexport interface CreateCampaignResult {\n /** null when the (filtered) target group resolved to nobody — e.g. \"uncovered\" with no new subjects. */\n campaignId: string | null;\n sent: number;\n skipped: SkippedSubject[];\n}\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Send a version to a target group. Resolves recipients server-side via the\n * SubjectsPort, applies the resend policy by diffing against existing requests,\n * mints no-login tokens, creates the request rows, and fans out one notification\n * per recipient × channel — recording a CREATED + per-send NOTIFIED audit chain.\n */\nexport async function createCampaign(\n deps: CreateCampaignDeps,\n args: CreateCampaignArgs,\n): Promise<CreateCampaignResult> {\n const { persistence, subjects, notifier, clock, baseUrl, defaultExpiryDays } = deps;\n const content = deps.content ?? defaultContent;\n\n if (args.channels.length === 0) {\n throw new EsignError(\"INVALID_INPUT\", \"Choose at least one channel.\");\n }\n\n const version = await persistence.getVersion(args.documentVersionId);\n if (!version) throw new EsignError(\"NOT_FOUND\", \"Document version not found.\");\n const document = await persistence.getDocument(version.documentId);\n if (!document) throw new EsignError(\"NOT_FOUND\", \"Document not found.\");\n\n const descriptor = subjects.get(args.selection.type);\n if (!descriptor) {\n throw new EsignError(\n \"INVALID_INPUT\",\n `Unknown subject type: ${args.selection.type}.`,\n );\n }\n\n const configured = new Set(notifier.configuredChannels());\n const channels = args.channels.filter((c) => configured.has(c));\n if (channels.length === 0) {\n throw new EsignError(\n \"INVALID_INPUT\",\n \"None of the chosen channels are configured.\",\n );\n }\n\n const scopeId = args.scopeId ?? document.scopeId;\n const resolved = await descriptor.resolveRecipients({\n scopeId,\n selection: args.selection,\n channels,\n });\n const skipped = resolved.skipped;\n let recipients = resolved.recipients;\n\n // Resend policy: keep only the slice the policy targets, diffed against the\n // document's existing requests.\n if (args.resendPolicy && args.resendPolicy !== \"all\") {\n const summaries = await persistence.requestSummaryBySubject(version.documentId);\n const byId = new Map(summaries.map((s) => [s.subjectId, s]));\n const vNum = version.version;\n recipients = recipients.filter((r) => {\n const s = byId.get(r.subjectId);\n switch (args.resendPolicy) {\n case \"uncovered\":\n return !s;\n case \"outstanding\":\n return !(s && s.status === \"SIGNED\" && s.version >= vNum);\n case \"olderVersion\":\n return Boolean(s && s.status === \"SIGNED\" && s.version < vNum);\n default:\n return true;\n }\n });\n }\n\n if (recipients.length === 0) return { campaignId: null, sent: 0, skipped };\n\n const now = clock.now();\n const expiresAt = new Date(\n now.getTime() + (args.expiresInDays ?? defaultExpiryDays) * DAY_MS,\n );\n\n const campaign = await persistence.createCampaign({\n documentId: version.documentId,\n documentVersionId: version.id,\n scopeId,\n note: args.note ?? null,\n emailReceipt: args.emailReceipt ?? false,\n targeting: args.selection,\n expiresAt,\n createdById: args.createdById ?? null,\n });\n\n const targetedGroup =\n args.selection.mode === \"all\" ? (args.selection.group ?? null) : null;\n\n // Engine mints request ids (createRequests returns void), keeping the cleartext\n // token + recipient alongside each row for the fan-out.\n const prepared = recipients.map((r) => {\n const token = newSigningToken();\n const row: NewRequestRow = {\n id: uid(),\n campaignId: campaign.id,\n documentId: version.documentId,\n documentVersionId: version.id,\n scopeId,\n subjectType: r.subjectType,\n subjectId: r.subjectId,\n subjectGroup: targetedGroup ?? r.group ?? null,\n recipientName: r.name,\n recipientEmail: r.email ?? null,\n recipientWhatsapp: r.whatsapp ?? null,\n channels,\n tokenHash: token.tokenHash,\n expiresAt,\n };\n return { row, cleartext: token.cleartext, recipient: r };\n });\n\n await persistence.createRequests(prepared.map((p) => p.row));\n\n const base = baseUrl.replace(/\\/$/, \"\");\n const nowIso = now.toISOString();\n let sent = 0;\n\n for (const { row, cleartext, recipient } of prepared) {\n let prev = await recordEvent(persistence, row.id, null, {\n type: \"CREATED\",\n payload: {\n subjectType: row.subjectType,\n subjectId: row.subjectId,\n by: args.createdById ?? null,\n },\n occurredAt: nowIso,\n });\n\n const actionUrl = `${base}/sign/${cleartext}`;\n const c = content({\n documentTitle: document.title,\n note: args.note ?? null,\n recipientName: recipient.name,\n });\n\n for (const channel of channels) {\n const address = addressFor(recipient, channel);\n if (!address) continue;\n let ok = false;\n let error: string | null = null;\n try {\n const result = await notifier.send({\n channel,\n recipient: address,\n subject: c.subject,\n body: c.body,\n actionUrl,\n idempotencyKey: row.id,\n });\n ok = result.ok;\n error = result.error ?? null;\n } catch (err) {\n ok = false;\n error = err instanceof Error ? err.message : String(err);\n }\n prev = await recordEvent(persistence, row.id, prev, {\n type: \"NOTIFIED\",\n payload: { channel, ok, error },\n occurredAt: nowIso,\n });\n }\n sent++;\n }\n\n return { campaignId: campaign.id, sent, skipped };\n}\n","import { EsignError } from \"./errors\";\nimport type { PersistencePort, SubjectsPort } from \"./ports\";\nimport type { CoverageReport, SubjectSummary } from \"./types\";\n\nexport interface CoverageDeps {\n persistence: PersistencePort;\n subjects: SubjectsPort;\n}\n\n/**\n * Re-derive a document's coverage from the LIVE group (via the stored audience\n * selection) so subjects added after a send are detected. Buckets every subject\n * into signed / outstanding / needs-resign / uncovered / departed.\n */\nexport async function documentCoverage(\n deps: CoverageDeps,\n documentId: string,\n): Promise<CoverageReport> {\n const { persistence, subjects } = deps;\n const doc = await persistence.getDocument(documentId);\n if (!doc) throw new EsignError(\"NOT_FOUND\", \"Document not found.\");\n\n const summaries = await persistence.requestSummaryBySubject(documentId);\n const summaryIds = new Set(summaries.map((s) => s.subjectId));\n\n let currentNumber = 0;\n if (doc.currentVersionId) {\n const v = await persistence.getVersion(doc.currentVersionId);\n currentNumber = v?.version ?? 0;\n }\n\n let signed = 0;\n let outstanding = 0;\n let needsResign = 0;\n for (const s of summaries) {\n if (s.status === \"SIGNED\") {\n if (s.version >= currentNumber) signed++;\n else needsResign++;\n } else if (s.status === \"PENDING\" || s.status === \"VIEWED\") {\n outstanding++;\n }\n }\n\n // Live group (labelled) from the audience selection.\n let live: SubjectSummary[] = [];\n if (doc.audience) {\n const descriptor = subjects.get(doc.audience.type);\n if (descriptor) {\n const page = await descriptor.listSubjects({\n scopeId: doc.scopeId,\n group: doc.audience.mode === \"all\" ? doc.audience.group : undefined,\n filter: doc.audience.mode === \"all\" ? doc.audience.filter : undefined,\n limit: 1000,\n });\n live = page.subjects;\n }\n }\n const liveIds = new Set(live.map((s) => s.subjectId));\n\n const uncovered = live.filter((s) => !summaryIds.has(s.subjectId));\n const departed = doc.audience\n ? summaries\n .filter((s) => !liveIds.has(s.subjectId))\n .map((s) => ({ subjectType: doc.audience!.type, subjectId: s.subjectId }))\n : [];\n\n return {\n documentId,\n totalNow: live.length,\n signed,\n outstanding,\n needsResign,\n uncovered,\n departed,\n };\n}\n","import type {\n Clock,\n DocumentDeletionContext,\n HooksPort,\n PersistencePort,\n StoragePort,\n} from \"./ports\";\n\nexport type DeleteMode = \"soft\" | \"purge\";\n\nexport interface DeleteDocumentInput {\n documentId: string;\n /**\n * \"soft\" (default) archives reversibly — hides the document + campaigns, revokes\n * live links, keeps the sealed PDFs + audit trail. \"purge\" permanently removes\n * all rows and the source/sealed objects, and is refused once anything is signed.\n */\n mode?: DeleteMode;\n}\n\nexport type DeleteDocumentResult =\n | { ok: true; mode: DeleteMode; documentId: string; objectsPurged: number }\n | { ok: false; reason: \"not_found\" | \"has_signatures\" };\n\nexport interface DeleteDocumentDeps {\n persistence: PersistencePort;\n storage: StoragePort;\n clock: Clock;\n hooks?: HooksPort;\n}\n\n/**\n * Delete a logical document and everything under it. Soft by default (reversible,\n * preserves signed evidence); purge permanently removes rows + storage objects but\n * is refused when any request is SIGNED. Either way the affected subjects are\n * reported through {@link HooksPort.onDocumentDeleted} so the host can react\n * (milestone-grid retraction lives in the host, never in this package).\n */\nexport async function deleteDocument(\n deps: DeleteDocumentDeps,\n input: DeleteDocumentInput,\n): Promise<DeleteDocumentResult> {\n const mode: DeleteMode = input.mode ?? \"soft\";\n const ctx = await deps.persistence.getDocumentDeletionContext(input.documentId);\n if (!ctx) return { ok: false, reason: \"not_found\" };\n\n // A signed document is legal evidence — never hard-delete it.\n if (mode === \"purge\" && ctx.signedCount > 0) {\n return { ok: false, reason: \"has_signatures\" };\n }\n\n if (mode === \"purge\") {\n // DB first (transactional source of truth); storage cleanup is best-effort\n // after. An orphaned object is harmless and sweepable; a row pointing at a\n // deleted object is not — so we never delete objects before the rows.\n await deps.persistence.hardDeleteDocument(input.documentId);\n const keys = [...ctx.sourceKeys, ...ctx.sealedKeys];\n for (const key of keys) {\n await deps.storage.delete(key).catch(() => undefined);\n }\n await emitDeleted(deps.hooks, ctx, \"purge\");\n return { ok: true, mode: \"purge\", documentId: input.documentId, objectsPurged: keys.length };\n }\n\n await deps.persistence.softDeleteDocument(input.documentId, deps.clock.now());\n await emitDeleted(deps.hooks, ctx, \"soft\");\n return { ok: true, mode: \"soft\", documentId: input.documentId, objectsPurged: 0 };\n}\n\nasync function emitDeleted(\n hooks: HooksPort | undefined,\n ctx: DocumentDeletionContext,\n mode: DeleteMode,\n): Promise<void> {\n if (!hooks?.onDocumentDeleted) return;\n try {\n await hooks.onDocumentDeleted({\n documentId: ctx.documentId,\n documentType: ctx.documentType,\n scopeId: ctx.scopeId,\n mode,\n affectedSubjects: ctx.affectedSubjects,\n });\n } catch {\n // A host hook failure must never block the delete it's reacting to.\n }\n}\n","import { PDFDocument } from \"pdf-lib\";\n\nimport { EsignError } from \"./errors\";\nimport type { PersistencePort, StoragePort } from \"./ports\";\nimport { sha256Hex } from \"./tokens\";\nimport type {\n SignatureField,\n SigningDocumentDTO,\n SigningDocumentVersionDTO,\n SubjectSelection,\n} from \"./types\";\n\nexport interface CreateDocumentInput {\n scopeId?: string | null;\n documentType?: string | null;\n title: string;\n audience?: SubjectSelection | null;\n createdById?: string | null;\n}\n\nexport async function createDocument(\n persistence: PersistencePort,\n input: CreateDocumentInput,\n): Promise<SigningDocumentDTO> {\n if (!input.title.trim()) {\n throw new EsignError(\"INVALID_INPUT\", \"A document title is required.\");\n }\n return persistence.createDocument({\n scopeId: input.scopeId ?? null,\n documentType: input.documentType ?? null,\n title: input.title,\n audience: input.audience ?? null,\n createdById: input.createdById ?? null,\n });\n}\n\n/** A new version supplies its PDF either by an already-uploaded key or raw bytes. */\nexport type VersionSource =\n | { objectKey: string }\n | { pdfBytes: Uint8Array; scopeId?: string | null };\n\nexport interface AddVersionInput {\n documentId: string;\n placements: SignatureField[];\n source: VersionSource;\n changeNote?: string | null;\n createdById?: string | null;\n}\n\n/** Fail fast on a non-PDF / encrypted upload so it can't reach the seal step. */\nasync function assertReadablePdf(bytes: Uint8Array): Promise<void> {\n try {\n await PDFDocument.load(bytes);\n } catch {\n throw new EsignError(\n \"INVALID_INPUT\",\n \"The upload is not a readable PDF (it may be encrypted or corrupt).\",\n );\n }\n}\n\n/**\n * Add an immutable version to a document: validate + hash the source PDF, store\n * it (when bytes were passed), persist the next-numbered version, and point the\n * document at it as current.\n */\nexport async function addVersion(\n deps: { persistence: PersistencePort; storage: StoragePort },\n input: AddVersionInput,\n): Promise<SigningDocumentVersionDTO> {\n const { persistence, storage } = deps;\n\n let sourceObjectKey: string;\n let bytes: Uint8Array;\n if (\"objectKey\" in input.source) {\n sourceObjectKey = input.source.objectKey;\n const fetched = await storage.get(sourceObjectKey);\n if (!fetched) {\n throw new EsignError(\"INVALID_INPUT\", \"Uploaded PDF was not found in storage.\");\n }\n bytes = fetched.bytes;\n } else {\n bytes = input.source.pdfBytes;\n sourceObjectKey = storage.stampKey({\n scopeId: input.source.scopeId ?? null,\n documentId: input.documentId,\n contentType: \"application/pdf\",\n });\n await storage.put({\n objectKey: sourceObjectKey,\n bytes,\n contentType: \"application/pdf\",\n });\n }\n\n await assertReadablePdf(bytes);\n\n const latest = await persistence.latestVersion(input.documentId);\n const version = await persistence.createVersion({\n documentId: input.documentId,\n version: (latest?.version ?? 0) + 1,\n sourceObjectKey,\n sourceSha256: sha256Hex(bytes),\n placements: input.placements,\n changeNote: input.changeNote ?? null,\n createdById: input.createdById ?? null,\n });\n\n await persistence.updateDocument(input.documentId, {\n currentVersionId: version.id,\n });\n\n return version;\n}\n","import type { ZodType } from \"zod\";\n\nimport { EsignError, toErrorResponse } from \"./errors\";\nimport type { AuthPort } from \"./ports\";\n\nexport interface RouteEnv<S> {\n auth: AuthPort<S>;\n}\n\n/** Auth + admin-check + JSON-error envelope around a Next-style handler. */\nexport function adminRoute<S, Ctx = unknown>(\n env: RouteEnv<S>,\n handler: (req: Request, ctx: Ctx, scope: S) => Promise<Response>,\n) {\n return async (req: Request, ctx: Ctx): Promise<Response> => {\n try {\n const scope = await env.auth.requireAuth(req);\n if (!env.auth.isAdmin(scope)) {\n throw new EsignError(\"FORBIDDEN\", \"Admin role required.\");\n }\n return await handler(req, ctx, scope);\n } catch (err) {\n return toErrorResponse(err);\n }\n };\n}\n\n/** Authenticated (non-admin) handler with the JSON-error envelope. */\nexport function authedRoute<S, Ctx = unknown>(\n env: RouteEnv<S>,\n handler: (req: Request, ctx: Ctx, scope: S) => Promise<Response>,\n) {\n return async (req: Request, ctx: Ctx): Promise<Response> => {\n try {\n const scope = await env.auth.requireAuth(req);\n return await handler(req, ctx, scope);\n } catch (err) {\n return toErrorResponse(err);\n }\n };\n}\n\n/** Public (no-auth) handler — the token-gated signer surface. */\nexport function publicRoute<Ctx = unknown>(\n handler: (req: Request, ctx: Ctx) => Promise<Response>,\n) {\n return async (req: Request, ctx: Ctx): Promise<Response> => {\n try {\n return await handler(req, ctx);\n } catch (err) {\n return toErrorResponse(err);\n }\n };\n}\n\nexport async function parseBody<T>(req: Request, schema: ZodType<T>): Promise<T> {\n let raw: unknown;\n try {\n raw = await req.json();\n } catch {\n throw new EsignError(\"INVALID_INPUT\", \"Request body must be valid JSON.\");\n }\n const parsed = schema.safeParse(raw);\n if (!parsed.success) {\n throw new EsignError(\"INVALID_INPUT\", \"Validation failed.\", parsed.error.flatten());\n }\n return parsed.data;\n}\n\nexport function ok(data: unknown, init?: ResponseInit): Response {\n return Response.json(data, init);\n}\n\n/** Best-effort client IP from forwarding headers (for the audit trail). */\nexport function clientIp(req: Request): string | null {\n const fwd = req.headers.get(\"x-forwarded-for\");\n if (fwd) return fwd.split(\",\")[0]?.trim() ?? null;\n return req.headers.get(\"x-real-ip\");\n}\n","import { EsignError } from \"./errors\";\n\n/**\n * Lifecycle of a single signing request. PENDING/VIEWED are the only active\n * states; SIGNED/DECLINED/EXPIRED/REVOKED are terminal. The submit handler is\n * idempotent, so a no-op transition to the same state is always allowed.\n */\nexport type EsignStatus =\n | \"PENDING\"\n | \"VIEWED\"\n | \"SIGNED\"\n | \"DECLINED\"\n | \"EXPIRED\"\n | \"REVOKED\";\n\nexport const ESIGN_STATUSES: readonly EsignStatus[] = [\n \"PENDING\",\n \"VIEWED\",\n \"SIGNED\",\n \"DECLINED\",\n \"EXPIRED\",\n \"REVOKED\",\n];\n\n/** Active (still-actionable) states — eligible for view/sign/decline. */\nexport const ACTIVE_STATUSES: readonly EsignStatus[] = [\"PENDING\", \"VIEWED\"];\n\n/** Terminal states — no further transitions. */\nexport const TERMINAL_STATUSES: readonly EsignStatus[] = [\n \"SIGNED\",\n \"DECLINED\",\n \"EXPIRED\",\n \"REVOKED\",\n];\n\nconst TRANSITIONS: Record<EsignStatus, readonly EsignStatus[]> = {\n PENDING: [\"VIEWED\", \"SIGNED\", \"DECLINED\", \"EXPIRED\", \"REVOKED\"],\n VIEWED: [\"SIGNED\", \"DECLINED\", \"EXPIRED\", \"REVOKED\"],\n SIGNED: [],\n DECLINED: [],\n EXPIRED: [],\n REVOKED: [],\n};\n\nexport function isActive(status: EsignStatus): boolean {\n return ACTIVE_STATUSES.includes(status);\n}\n\nexport function isTerminal(status: EsignStatus): boolean {\n return TERMINAL_STATUSES.includes(status);\n}\n\n/** Whether `from → to` is a legal move (a same-state no-op counts as legal). */\nexport function canTransition(from: EsignStatus, to: EsignStatus): boolean {\n if (from === to) return true;\n return TRANSITIONS[from].includes(to);\n}\n\n/** Throw `EsignError('CONFLICT')` on an illegal transition. */\nexport function assertTransition(from: EsignStatus, to: EsignStatus): void {\n if (!canTransition(from, to)) {\n throw new EsignError(\n \"CONFLICT\",\n `Illegal signing-request transition: ${from} → ${to}.`,\n );\n }\n}\n","import { type PDFDocument, type PDFFont, rgb, StandardFonts } from \"pdf-lib\";\n\nimport type { AuditLink } from \"./audit-chain\";\n\n/**\n * Human-readable signature certificate appended as the final page of every\n * sealed PDF. It prints the signer, the document content SHA-256, the audit\n * chain tip, and the full event log — so the seal is verifiable by eye, and the\n * printed hashes let anyone re-check integrity out of band.\n */\nexport interface CertInfo {\n documentTitle: string;\n signerName: string;\n signedAt: string;\n signerIp: string | null;\n requestId: string;\n /** sha256 of the flattened, signature-stamped content (pre-certificate). */\n documentSha256: string;\n /** The audit chain tip (SigningRequest.finalAuditHash). */\n finalHash: string;\n links: AuditLink[];\n}\n\nconst A4: [number, number] = [595.28, 841.89];\nconst MARGIN = 48;\nconst INK = rgb(0.12, 0.12, 0.14);\nconst MUTED = rgb(0.4, 0.42, 0.46);\n\nexport async function renderAuditCertificatePage(\n pdf: PDFDocument,\n info: CertInfo,\n): Promise<void> {\n const page = pdf.addPage(A4);\n const font = await pdf.embedFont(StandardFonts.Helvetica);\n const bold = await pdf.embedFont(StandardFonts.HelveticaBold);\n const mono = await pdf.embedFont(StandardFonts.Courier);\n const [pageW, pageH] = A4;\n\n let y = pageH - MARGIN;\n const draw = (\n text: string,\n opts: { x?: number; size?: number; font?: PDFFont; color?: typeof INK } = {},\n ) => {\n page.drawText(text, {\n x: opts.x ?? MARGIN,\n y,\n size: opts.size ?? 10,\n font: opts.font ?? font,\n color: opts.color ?? INK,\n });\n };\n const advance = (by: number) => {\n y -= by;\n };\n\n draw(\"Signature Certificate\", { size: 20, font: bold });\n advance(14);\n draw(\"Electronic signature with a tamper-evident (Level-1 sealed) audit trail.\", {\n size: 9,\n color: MUTED,\n });\n advance(28);\n\n const field = (label: string, value: string, valueFont: PDFFont = font) => {\n draw(label, { size: 8, font: bold, color: MUTED });\n advance(13);\n draw(value, { size: 10, font: valueFont });\n advance(20);\n };\n\n field(\"DOCUMENT\", info.documentTitle);\n field(\"SIGNED BY\", info.signerName);\n field(\"SIGNED AT\", info.signedAt);\n field(\"SIGNER IP\", info.signerIp ?? \"—\");\n field(\"REQUEST ID\", info.requestId, mono);\n field(\"DOCUMENT SHA-256\", info.documentSha256, mono);\n field(\"AUDIT CHAIN TIP\", info.finalHash, mono);\n\n advance(6);\n draw(\"AUDIT TRAIL\", { size: 8, font: bold, color: MUTED });\n advance(16);\n\n // Column header\n draw(\"#\", { x: MARGIN, size: 8, font: bold, color: MUTED });\n draw(\"EVENT\", { x: MARGIN + 24, size: 8, font: bold, color: MUTED });\n draw(\"WHEN\", { x: MARGIN + 170, size: 8, font: bold, color: MUTED });\n draw(\"HASH\", { x: MARGIN + 330, size: 8, font: bold, color: MUTED });\n advance(4);\n page.drawLine({\n start: { x: MARGIN, y },\n end: { x: pageW - MARGIN, y },\n thickness: 0.5,\n color: MUTED,\n });\n advance(14);\n\n for (const link of info.links) {\n if (y < MARGIN + 20) break; // single-page cert; chain is also stored in the DB\n draw(String(link.seq), { x: MARGIN, size: 9 });\n draw(link.type, { x: MARGIN + 24, size: 9 });\n draw(link.occurredAt, { x: MARGIN + 170, size: 8, color: MUTED });\n draw(`${link.hash.slice(0, 16)}…`, { x: MARGIN + 330, size: 8, font: mono });\n advance(15);\n }\n}\n","import { PDFDocument, rgb, StandardFonts } from \"pdf-lib\";\n\nimport { appendEvent, type AuditLink } from \"./audit-chain\";\nimport { renderAuditCertificatePage } from \"./audit-cert\";\nimport { EsignError } from \"./errors\";\nimport { sha256Hex } from \"./tokens\";\nimport type { Placement } from \"./types\";\n\n/**\n * The Level-1 seal. Loads the version's source PDF, stamps the signature within\n * the manager's placement box, appends SIGNED + SEALED audit links, renders the\n * certificate page, and returns the flattened bytes plus the content hash and\n * chain tip. Pure + deterministic: a fixed input (incl. `signedAt`) yields\n * byte-identical output, so `sealedSha256` is reproducible and testable.\n *\n * `documentSha256` is the hash of the stamped content *before* the certificate\n * page (the bytes that were actually signed); `sealedSha256` covers the final\n * file. A future Level-2 PAdES seal wraps the returned `sealedPdf` unchanged.\n */\nexport interface SealInput {\n sourcePdf: Uint8Array;\n /** PNG bytes of the drawn or typed signature. */\n signaturePng: Uint8Array;\n /** One or more boxes; the signature is stamped at each. */\n placements: Placement[];\n signerName: string;\n /** ISO instant — also pins the PDF metadata dates for reproducibility. */\n signedAt: string;\n signerIp: string | null;\n documentTitle: string;\n requestId: string;\n /** Existing chain (CREATED…CONSENTED). SIGNED + SEALED are appended here. */\n priorChain: AuditLink[];\n}\n\nexport interface SealResult {\n sealedPdf: Uint8Array;\n sealedSha256: string;\n documentSha256: string;\n finalHash: string;\n /** The SIGNED and SEALED links — the caller persists them. */\n newLinks: AuditLink[];\n}\n\nexport async function sealPdf(input: SealInput): Promise<SealResult> {\n let pdf: PDFDocument;\n try {\n pdf = await PDFDocument.load(input.sourcePdf);\n } catch {\n throw new EsignError(\n \"INVALID_INPUT\",\n \"Could not read the PDF — it may be encrypted or corrupt.\",\n );\n }\n\n const when = new Date(input.signedAt);\n pdf.setCreationDate(when);\n pdf.setModificationDate(when);\n pdf.setProducer(\"@josephomills/esign\");\n pdf.setCreator(\"@josephomills/esign\");\n\n const pages = pdf.getPages();\n const png = await pdf.embedPng(input.signaturePng);\n const font = await pdf.embedFont(StandardFonts.Helvetica);\n const caption = `Signed by ${input.signerName} · ${input.signedAt}${\n input.signerIp ? ` · IP ${input.signerIp}` : \"\"\n }`;\n\n // Stamp the signature at each placement (caption once, under the first).\n input.placements.forEach((placement, i) => {\n const pageIndex = Math.min(Math.max(placement.page - 1, 0), pages.length - 1);\n const page = pages[pageIndex]!;\n const pageW = page.getWidth();\n const pageH = page.getHeight();\n // Placement is normalized top-left origin; pdf-lib is bottom-left.\n const boxX = placement.x * pageW;\n const boxW = placement.w * pageW;\n const boxH = placement.h * pageH;\n const boxBottomY = pageH * (1 - placement.y - placement.h);\n const scale = Math.min(boxW / png.width, boxH / png.height);\n const drawW = png.width * scale;\n const drawH = png.height * scale;\n page.drawImage(png, {\n x: boxX + (boxW - drawW) / 2,\n y: boxBottomY + (boxH - drawH) / 2,\n width: drawW,\n height: drawH,\n });\n if (i === 0) {\n page.drawText(caption, {\n x: boxX,\n y: Math.max(boxBottomY - 11, 4),\n size: 7,\n font,\n color: rgb(0.35, 0.35, 0.4),\n });\n }\n });\n\n // Content hash: the stamped document, before the certificate page is added.\n const stampedBytes = await pdf.save({ useObjectStreams: false });\n const documentSha256 = sha256Hex(stampedBytes);\n\n const last = input.priorChain.at(-1) ?? null;\n const signed = appendEvent(last, {\n type: \"SIGNED\",\n payload: {\n signerName: input.signerName,\n signerIp: input.signerIp,\n signedAt: input.signedAt,\n },\n occurredAt: input.signedAt,\n });\n const sealed = appendEvent(signed, {\n type: \"SEALED\",\n payload: { documentSha256 },\n occurredAt: input.signedAt,\n });\n const finalHash = sealed.hash;\n\n await renderAuditCertificatePage(pdf, {\n documentTitle: input.documentTitle,\n signerName: input.signerName,\n signedAt: input.signedAt,\n signerIp: input.signerIp,\n requestId: input.requestId,\n documentSha256,\n finalHash,\n links: [...input.priorChain, signed, sealed],\n });\n\n const sealedPdf = await pdf.save({ useObjectStreams: false });\n return {\n sealedPdf,\n sealedSha256: sha256Hex(sealedPdf),\n documentSha256,\n finalHash,\n newLinks: [signed, sealed],\n };\n}\n","import type { AuditLink } from \"./audit-chain\";\nimport { recordEvent } from \"./campaign\";\nimport { EsignError } from \"./errors\";\nimport { isActive } from \"./flow\";\nimport type {\n Clock,\n HooksPort,\n NotifierPort,\n PersistencePort,\n StoragePort,\n} from \"./ports\";\nimport { sealPdf } from \"./seal\";\nimport { sha256Hex } from \"./tokens\";\nimport type { SignatureField, SigningAuditEventDTO, SigningRequestDTO } from \"./types\";\n\nexport interface SignDeps {\n persistence: PersistencePort;\n storage: StoragePort;\n clock: Clock;\n notifier: NotifierPort;\n hooks?: HooksPort;\n}\n\nconst toLink = (e: SigningAuditEventDTO): AuditLink => ({\n seq: e.seq,\n type: e.type,\n payload: (e.payload as Record<string, unknown>) ?? {},\n prevHash: e.prevHash,\n hash: e.hash,\n occurredAt: e.occurredAt,\n});\n\n/** Resolve a request from its cleartext token, with no existence oracle. */\nasync function resolve(\n persistence: PersistencePort,\n token: string,\n): Promise<SigningRequestDTO | null> {\n return persistence.findRequestByTokenHash(sha256Hex(token));\n}\n\nexport interface SigningView {\n request: SigningRequestDTO;\n /** Source PDF object key + signature fields for the signer page to render. */\n sourceObjectKey: string;\n placements: SignatureField[];\n documentTitle: string;\n}\n\n/**\n * Data for the public signing page. Returns null for unknown / expired / revoked\n * / already-finished requests so the host shows one \"unavailable\" screen.\n */\nexport async function getSigningView(\n deps: Pick<SignDeps, \"persistence\" | \"clock\">,\n token: string,\n): Promise<SigningView | null> {\n const request = await resolve(deps.persistence, token);\n if (!request) return null;\n if (!isActive(request.status)) return null;\n if (request.revokedAt) return null;\n if (new Date(request.expiresAt) < deps.clock.now()) return null;\n\n const version = await deps.persistence.getVersion(request.documentVersionId);\n if (!version) return null;\n const document = await deps.persistence.getDocument(request.documentId);\n return {\n request,\n sourceObjectKey: version.sourceObjectKey,\n placements: version.placements,\n documentTitle: document?.title ?? \"Document\",\n };\n}\n\n/** Mark first view PENDING→VIEWED, recording a VIEWED audit event. Idempotent. */\nexport async function recordView(\n deps: Pick<SignDeps, \"persistence\" | \"clock\" | \"hooks\">,\n token: string,\n): Promise<void> {\n const request = await resolve(deps.persistence, token);\n if (!request || request.status !== \"PENDING\") return;\n const existing = (await deps.persistence.listAuditEvents(request.id)).map(toLink);\n const now = deps.clock.now();\n await recordEvent(deps.persistence, request.id, existing.at(-1) ?? null, {\n type: \"VIEWED\",\n payload: {},\n occurredAt: now.toISOString(),\n });\n const updated = await deps.persistence.updateRequest(request.id, {\n status: \"VIEWED\",\n viewedAt: now,\n });\n if (deps.hooks?.onRequestViewed) await deps.hooks.onRequestViewed(updated);\n}\n\nexport interface SubmitInput {\n token: string;\n signaturePng: Uint8Array;\n signerName: string;\n ip: string | null;\n userAgent: string | null;\n}\n\nexport interface SubmitResult {\n requestId: string;\n sealedObjectKey: string;\n alreadySigned: boolean;\n}\n\n/**\n * The signer submit: consent → seal → store → persist SIGNED → fire hook →\n * optional emailed receipt. Idempotent — a re-submit of a signed request returns\n * the existing sealed key instead of re-sealing.\n */\nexport async function submitSignature(\n deps: SignDeps,\n input: SubmitInput,\n): Promise<SubmitResult> {\n const { persistence, storage, clock, notifier, hooks } = deps;\n const request = await resolve(persistence, input.token);\n if (!request) throw new EsignError(\"NOT_FOUND\", \"This signing link is not valid.\");\n\n if (request.status === \"SIGNED\") {\n return {\n requestId: request.id,\n sealedObjectKey: request.sealedObjectKey ?? \"\",\n alreadySigned: true,\n };\n }\n if (!isActive(request.status) || request.revokedAt) {\n throw new EsignError(\"GONE\", \"This signing link is no longer available.\");\n }\n const now = clock.now();\n if (new Date(request.expiresAt) < now) {\n await persistence.updateRequest(request.id, { status: \"EXPIRED\" });\n throw new EsignError(\"GONE\", \"This signing link has expired.\");\n }\n\n const version = await persistence.getVersion(request.documentVersionId);\n if (!version) throw new EsignError(\"INTERNAL\", \"Document version missing.\");\n const src = await storage.get(version.sourceObjectKey);\n if (!src) throw new EsignError(\"INTERNAL\", \"Source document missing.\");\n const document = await persistence.getDocument(request.documentId);\n\n const existing = (await persistence.listAuditEvents(request.id)).map(toLink);\n const nowIso = now.toISOString();\n const consented = await recordEvent(persistence, request.id, existing.at(-1) ?? null, {\n type: \"CONSENTED\",\n payload: {\n signerName: input.signerName,\n ip: input.ip,\n userAgent: input.userAgent,\n },\n occurredAt: nowIso,\n });\n\n const seal = await sealPdf({\n sourcePdf: src.bytes,\n signaturePng: input.signaturePng,\n placements: version.placements,\n signerName: input.signerName,\n signedAt: nowIso,\n signerIp: input.ip,\n documentTitle: document?.title ?? \"Document\",\n requestId: request.id,\n priorChain: [...existing, consented],\n });\n\n const sealedObjectKey = storage.sealedKey({\n scopeId: request.scopeId,\n campaignId: request.campaignId,\n requestId: request.id,\n });\n await storage.put({\n objectKey: sealedObjectKey,\n bytes: seal.sealedPdf,\n contentType: \"application/pdf\",\n });\n\n await persistence.updateRequest(request.id, {\n status: \"SIGNED\",\n signedAt: now,\n signerName: input.signerName,\n signerIp: input.ip ?? undefined,\n signerUserAgent: input.userAgent ?? undefined,\n sealedObjectKey,\n sealedSha256: seal.sealedSha256,\n finalAuditHash: seal.finalHash,\n });\n\n for (const link of seal.newLinks) {\n await persistence.appendAuditEvent({\n requestId: request.id,\n seq: link.seq,\n type: link.type,\n payload: link.payload,\n prevHash: link.prevHash,\n hash: link.hash,\n });\n }\n\n if (hooks?.onRequestSigned) {\n await hooks.onRequestSigned({\n subjectType: request.subjectType,\n subjectId: request.subjectId,\n documentId: request.documentId,\n documentType: document?.documentType ?? null,\n requestId: request.id,\n sealedObjectKey,\n signedAt: nowIso,\n });\n }\n\n // Optional emailed receipt — never blocks the signing result.\n const campaign = await persistence.getCampaign(request.campaignId);\n if (campaign?.emailReceipt && request.recipientEmail) {\n const title = document?.title ?? \"Document\";\n try {\n await notifier.send({\n channel: \"EMAIL\",\n recipient: request.recipientEmail,\n subject: `Signed copy: ${title}`,\n body: `Hello ${request.recipientName},\\n\\nAttached is your signed copy of \"${title}\".`,\n idempotencyKey: `${request.id}:receipt`,\n attachments: [\n {\n filename: `${title.replace(/[^a-z0-9-_ ]/gi, \"_\")}.pdf`,\n content: seal.sealedPdf,\n contentType: \"application/pdf\",\n },\n ],\n });\n } catch {\n // receipt delivery is best-effort\n }\n }\n\n return { requestId: request.id, sealedObjectKey, alreadySigned: false };\n}\n\nexport interface DeclineRequestInput {\n token: string;\n reason: string | null;\n}\n\n/** Signer declines: PENDING/VIEWED → DECLINED, recording a DECLINED event. */\nexport async function declineRequest(\n deps: Pick<SignDeps, \"persistence\" | \"clock\" | \"hooks\">,\n input: DeclineRequestInput,\n): Promise<void> {\n const request = await resolve(deps.persistence, input.token);\n if (!request || !isActive(request.status) || request.revokedAt) {\n throw new EsignError(\"GONE\", \"This signing link is no longer available.\");\n }\n const existing = (await deps.persistence.listAuditEvents(request.id)).map(toLink);\n const now = deps.clock.now();\n await recordEvent(deps.persistence, request.id, existing.at(-1) ?? null, {\n type: \"DECLINED\",\n payload: { reason: input.reason },\n occurredAt: now.toISOString(),\n });\n const updated = await deps.persistence.updateRequest(request.id, {\n status: \"DECLINED\",\n declinedAt: now,\n declineReason: input.reason ?? undefined,\n });\n if (deps.hooks?.onRequestDeclined) await deps.hooks.onRequestDeclined(updated);\n}\n","import { EsignError } from \"../errors\";\nimport { clientIp, ok, parseBody, publicRoute } from \"../route-utils\";\nimport { declineRequest, type SignDeps, submitSignature } from \"../sign\";\nimport { declineSchema, submitSignatureSchema } from \"../types\";\n\ntype RouteCtx = { params: { token: string } | Promise<{ token: string }> };\n\nconst PNG_MAGIC = [0x89, 0x50, 0x4e, 0x47];\n\n/** Decode a `data:image/png;base64,...` URL to bytes; reject anything not a PNG. */\nfunction pngFromDataUrl(dataUrl: string): Uint8Array {\n const comma = dataUrl.indexOf(\",\");\n const b64 = comma >= 0 ? dataUrl.slice(comma + 1) : dataUrl;\n const bytes = new Uint8Array(Buffer.from(b64, \"base64\"));\n const isPng = PNG_MAGIC.every((b, i) => bytes[i] === b);\n if (!isPng) {\n throw new EsignError(\"INVALID_INPUT\", \"Signature must be a PNG image.\");\n }\n return bytes;\n}\n\n/**\n * POST the signer action. `?action=decline` declines; otherwise it submits the\n * signature (consent → seal → SIGNED). Mount at `app/sign/[token]/submit/route.ts`.\n */\nexport function createSignActionsRoute(deps: SignDeps) {\n return {\n POST: publicRoute<RouteCtx>(async (req, ctx) => {\n const { token } = await ctx.params;\n const action = new URL(req.url).searchParams.get(\"action\");\n\n if (action === \"decline\") {\n const { reason } = await parseBody(req, declineSchema);\n await declineRequest(deps, { token, reason: reason ?? null });\n return ok({ ok: true, declined: true });\n }\n\n const body = await parseBody(req, submitSignatureSchema);\n const result = await submitSignature(deps, {\n token,\n signaturePng: pngFromDataUrl(body.signaturePng),\n signerName: body.signerName,\n ip: clientIp(req),\n userAgent: req.headers.get(\"user-agent\"),\n });\n return ok({\n ok: true,\n requestId: result.requestId,\n alreadySigned: result.alreadySigned,\n });\n }),\n };\n}\n","import { EsignError } from \"../errors\";\nimport type { Clock, PersistencePort, StoragePort } from \"../ports\";\nimport { publicRoute } from \"../route-utils\";\nimport { getSigningView } from \"../sign\";\n\ntype RouteCtx = { params: { token: string } | Promise<{ token: string }> };\n\nexport interface SignServeDeps {\n persistence: PersistencePort;\n storage: StoragePort;\n clock: Clock;\n}\n\n/**\n * GET the source PDF for the signer page, gated only by the (unguessable) token.\n * Bad / expired / revoked / finished tokens all 404 the same way (no oracle).\n * Mount at `app/api/esign/source/[token]/route.ts`; the host should rate-limit.\n */\nexport function createSignServeRoute(deps: SignServeDeps) {\n return {\n GET: publicRoute<RouteCtx>(async (_req, ctx) => {\n const { token } = await ctx.params;\n const view = await getSigningView(deps, token);\n if (!view) throw new EsignError(\"NOT_FOUND\", \"Not available.\");\n const obj = await deps.storage.get(view.sourceObjectKey);\n if (!obj) throw new EsignError(\"NOT_FOUND\", \"Not available.\");\n return new Response(obj.bytes as Uint8Array<ArrayBuffer>, {\n status: 200,\n headers: {\n \"content-type\": \"application/pdf\",\n \"content-disposition\": \"inline\",\n \"cache-control\": \"private, no-store\",\n \"x-robots-tag\": \"noindex\",\n },\n });\n }),\n };\n}\n","import {\n createCampaign,\n type CreateCampaignArgs,\n type CreateCampaignResult,\n} from \"./campaign\";\nimport { documentCoverage } from \"./coverage\";\nimport {\n deleteDocument,\n type DeleteDocumentInput,\n type DeleteDocumentResult,\n} from \"./delete\";\nimport {\n addVersion,\n type AddVersionInput,\n createDocument,\n type CreateDocumentInput,\n} from \"./documents\";\nimport type { Clock, EsignConfig } from \"./ports\";\nimport { createSignActionsRoute } from \"./routes/sign-actions\";\nimport { createSignServeRoute } from \"./routes/sign-serve\";\nimport {\n declineRequest,\n type DeclineRequestInput,\n getSigningView,\n recordView,\n type SigningView,\n type SubmitInput,\n type SubmitResult,\n submitSignature,\n} from \"./sign\";\nimport { newSigningToken } from \"./tokens\";\nimport type {\n CampaignStatsRow,\n CoverageReport,\n DocumentStatsRow,\n OutstandingRequest,\n ScopeStatsRow,\n SigningDocumentDTO,\n SigningDocumentVersionDTO,\n StatsRange,\n SubjectSigningStatus,\n VersionPolicy,\n} from \"./types\";\n\nconst DEFAULT_BASE = \"/api/esign\";\nconst DEFAULT_PRESIGN_TTL_S = 900;\nconst DEFAULT_EXPIRY_DAYS = 30;\n\nconst systemClock: Clock = { now: () => new Date() };\n\nexport type ResolvedEsignConfig<S> = EsignConfig<S> &\n Required<\n Pick<EsignConfig<S>, \"routeBasePath\" | \"presignTtlS\" | \"defaultExpiryDays\" | \"clock\">\n >;\n\nexport interface SubjectSigningStatusArgs {\n subjectType: string;\n subjectId: string;\n documentId?: string;\n documentType?: string;\n versionPolicy: VersionPolicy;\n}\n\n/**\n * The wired runtime: every engine function bound to the host's ports, plus the\n * route-handler factories the host mounts. Mirrors milestone-grid's\n * `configureMilestoneGrid(...) → { routes, ... }`.\n */\nexport interface EsignRuntime<S> {\n config: ResolvedEsignConfig<S>;\n newSigningToken: typeof newSigningToken;\n\n // Authoring\n createDocument(input: CreateDocumentInput): Promise<SigningDocumentDTO>;\n addVersion(input: AddVersionInput): Promise<SigningDocumentVersionDTO>;\n createCampaign(args: CreateCampaignArgs): Promise<CreateCampaignResult>;\n deleteDocument(input: DeleteDocumentInput): Promise<DeleteDocumentResult>;\n\n // Signing\n getSigningView(token: string): Promise<SigningView | null>;\n recordView(token: string): Promise<void>;\n submitSignature(input: SubmitInput): Promise<SubmitResult>;\n declineRequest(input: DeclineRequestInput): Promise<void>;\n\n // Status / coverage / stats\n subjectSigningStatus(args: SubjectSigningStatusArgs): Promise<SubjectSigningStatus>;\n documentCoverage(documentId: string): Promise<CoverageReport>;\n campaignStats(campaignId: string): Promise<CampaignStatsRow>;\n documentStats(documentId: string): Promise<DocumentStatsRow>;\n scopeStats(scopeId: string | null, range?: StatsRange): Promise<ScopeStatsRow>;\n outstandingRequests(filter: {\n scopeId?: string | null;\n documentId?: string;\n campaignId?: string;\n now: Date;\n limit?: number;\n }): Promise<OutstandingRequest[]>;\n\n routes: {\n signServe: ReturnType<typeof createSignServeRoute>;\n signActions: ReturnType<typeof createSignActionsRoute>;\n };\n}\n\nexport function configureEsign<S>(opts: EsignConfig<S>): EsignRuntime<S> {\n const config: ResolvedEsignConfig<S> = {\n ...opts,\n routeBasePath: opts.routeBasePath ?? DEFAULT_BASE,\n presignTtlS: opts.presignTtlS ?? DEFAULT_PRESIGN_TTL_S,\n defaultExpiryDays: opts.defaultExpiryDays ?? DEFAULT_EXPIRY_DAYS,\n clock: opts.clock ?? systemClock,\n };\n\n const { persistence, storage, notifier, subjects, hooks, clock, baseUrl } = config;\n const signDeps = { persistence, storage, clock, notifier, hooks };\n\n return {\n config,\n newSigningToken,\n\n createDocument: (input) => createDocument(persistence, input),\n addVersion: (input) => addVersion({ persistence, storage }, input),\n createCampaign: (args) =>\n createCampaign(\n {\n persistence,\n subjects,\n notifier,\n clock,\n baseUrl,\n defaultExpiryDays: config.defaultExpiryDays,\n },\n args,\n ),\n deleteDocument: (input) => deleteDocument({ persistence, storage, clock, hooks }, input),\n\n getSigningView: (token) => getSigningView({ persistence, clock }, token),\n recordView: (token) => recordView({ persistence, clock, hooks }, token),\n submitSignature: (input) => submitSignature(signDeps, input),\n declineRequest: (input) => declineRequest({ persistence, clock, hooks }, input),\n\n subjectSigningStatus: (args) => persistence.subjectSigningStatus(args),\n documentCoverage: (documentId) => documentCoverage({ persistence, subjects }, documentId),\n campaignStats: (campaignId) => persistence.campaignStats(campaignId),\n documentStats: (documentId) => persistence.documentStats(documentId),\n scopeStats: (scopeId, range) => persistence.scopeStats(scopeId, range),\n outstandingRequests: (filter) => persistence.outstandingRequests(filter),\n\n routes: {\n signServe: createSignServeRoute({ persistence, storage, clock }),\n signActions: createSignActionsRoute(signDeps),\n },\n };\n}\n","import type { SubjectsPort, SubjectTypeDescriptor } from \"./ports\";\n\n/**\n * Build a SubjectsPort from a list of host-defined subject-type descriptors.\n * The package renders targeting from `groupField` / `filterFields` and calls\n * the descriptor's enumeration/resolution methods; it never learns what a\n * \"MISSIONARY\" or \"APARTMENT\" actually is.\n */\nexport function registerSubjectTypes(types: SubjectTypeDescriptor[]): SubjectsPort {\n const map = new Map(types.map((t) => [t.type, t]));\n return {\n types,\n get: (type: string) => map.get(type),\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/server/tokens.ts","../../src/server/audit-chain.ts","../../src/server/errors.ts","../../src/shared/fields.ts","../../src/server/types.ts","../../src/server/uid.ts","../../src/server/campaign.ts","../../src/server/coverage.ts","../../src/server/delete.ts","../../src/server/documents.ts","../../src/server/route-utils.ts","../../src/server/flow.ts","../../src/server/audit-cert.ts","../../src/server/seal.ts","../../src/server/sign.ts","../../src/server/routes/sign-actions.ts","../../src/server/routes/sign-serve.ts","../../src/server/configure.ts","../../src/server/subjects.ts"],"names":["createHash","randomBytes","z","ok","PDFDocument","rgb","StandardFonts"],"mappings":";;;;;;;AAgBO,SAAS,UAAU,KAAA,EAAoC;AAC5D,EAAA,OAAOA,kBAAW,QAAQ,CAAA,CAAE,OAAO,KAAK,CAAA,CAAE,OAAO,KAAK,CAAA;AACxD;AAGO,SAAS,eAAA,CAAgB,QAAQ,EAAA,EAAkB;AACxD,EAAA,MAAM,SAAA,GAAYC,kBAAA,CAAY,KAAK,CAAA,CAAE,SAAS,WAAW,CAAA;AACzD,EAAA,OAAO,EAAE,SAAA,EAAW,SAAA,EAAW,SAAA,CAAU,SAAS,CAAA,EAAE;AACtD;;;ACCO,SAAS,aAAa,KAAA,EAAwB;AACnD,EAAA,IAAI,KAAA,KAAU,QAAW,OAAO,MAAA;AAChC,EAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,UAAU,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC5E,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,KAAA,CAAM,GAAA,CAAI,YAAY,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AACtE,EAAA,MAAM,GAAA,GAAM,KAAA;AACZ,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,GAAG,EAAE,IAAA,EAAK;AACnC,EAAA,OAAO,CAAA,CAAA,EAAI,KAAK,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,IAAA,CAAK,UAAU,CAAC,CAAC,IAAI,YAAA,CAAa,GAAA,CAAI,CAAC,CAAC,CAAC,EAAE,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AACtF;AAGO,SAAS,QAAA,CACd,QAAA,EACA,GAAA,EACA,IAAA,EACA,YACA,OAAA,EACQ;AACR,EAAA,OAAO,SAAA;AAAA,IACL,CAAA,EAAG,QAAA,IAAY,EAAE,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,EAAI,YAAA,CAAa,OAAO,CAAC,CAAA;AAAA,GACzE;AACF;AAGO,SAAS,WAAA,CACd,MACA,KAAA,EACW;AACX,EAAA,MAAM,GAAA,GAAM,IAAA,GAAO,IAAA,CAAK,GAAA,GAAM,CAAA,GAAI,CAAA;AAClC,EAAA,MAAM,QAAA,GAAW,IAAA,GAAO,IAAA,CAAK,IAAA,GAAO,IAAA;AACpC,EAAA,MAAM,IAAA,GAAO,SAAS,QAAA,EAAU,GAAA,EAAK,MAAM,IAAA,EAAM,KAAA,CAAM,UAAA,EAAY,KAAA,CAAM,OAAO,CAAA;AAChF,EAAA,OAAO,EAAE,GAAG,KAAA,EAAO,GAAA,EAAK,UAAU,IAAA,EAAK;AACzC;AAGO,SAAS,WAAW,MAAA,EAAwC;AACjE,EAAA,MAAM,MAAmB,EAAC;AAC1B,EAAA,IAAI,IAAA,GAAyB,IAAA;AAC7B,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAA,GAAO,WAAA,CAAY,MAAM,KAAK,CAAA;AAC9B,IAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,EACf;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,YAAY,KAAA,EAG1B;AACA,EAAA,IAAI,IAAA,GAAyB,IAAA;AAC7B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,WAAA,GAAc,IAAA,GAAO,IAAA,CAAK,GAAA,GAAM,CAAA,GAAI,CAAA;AAC1C,IAAA,MAAM,YAAA,GAAe,IAAA,GAAO,IAAA,CAAK,IAAA,GAAO,IAAA;AACxC,IAAA,MAAM,YAAA,GAAe,QAAA;AAAA,MACnB,YAAA;AAAA,MACA,IAAA,CAAK,GAAA;AAAA,MACL,IAAA,CAAK,IAAA;AAAA,MACL,IAAA,CAAK,UAAA;AAAA,MACL,IAAA,CAAK;AAAA,KACP;AACA,IAAA,IACE,IAAA,CAAK,QAAQ,WAAA,IACb,IAAA,CAAK,aAAa,YAAA,IAClB,IAAA,CAAK,SAAS,YAAA,EACd;AACA,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,QAAA,EAAU,KAAK,GAAA,EAAI;AAAA,IACzC;AACA,IAAA,IAAA,GAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,QAAA,EAAU,IAAA,EAAK;AACpC;;;ACnFO,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,EAC3B,IAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EAET,WAAA,CAAY,IAAA,EAAsB,OAAA,EAAiB,OAAA,EAAmB;AACpE,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,MAAA,GAAS,UAAU,IAAI,CAAA;AAAA,EAC9B;AACF;AAEA,SAAS,UAAU,IAAA,EAA8B;AAC/C,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,iBAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,eAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,UAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,cAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,mBAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,eAAA;AACH,MAAA,OAAO,GAAA;AAAA,IACT,KAAK,UAAA;AAAA,IACL;AACE,MAAA,OAAO,GAAA;AAAA;AAEb;AAEO,SAAS,gBAAgB,GAAA,EAAwB;AACtD,EAAA,IAAI,eAAe,UAAA,EAAY;AAC7B,IAAA,OAAO,QAAA,CAAS,IAAA;AAAA,MACd,EAAE,KAAA,EAAO,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,OAAA,EAAS,GAAA,CAAI,OAAA,EAAS,OAAA,EAAS,GAAA,CAAI,OAAA,EAAQ,EAAE;AAAA,MACxE,EAAE,MAAA,EAAQ,GAAA,CAAI,MAAA;AAAO,KACvB;AAAA,EACF;AACA,EAAA,OAAA,CAAQ,KAAA,CAAM,4BAA4B,GAAG,CAAA;AAC7C,EAAA,OAAO,QAAA,CAAS,IAAA;AAAA,IACd,EAAE,KAAA,EAAO,EAAE,MAAM,UAAA,EAAY,OAAA,EAAS,qBAAoB,EAAE;AAAA,IAC5D,EAAE,QAAQ,GAAA;AAAI,GAChB;AACF;;;AC5CO,IAAM,YAAA,GAAsC;AAAA,EACjD,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF;AACO,IAAM,mBAAA,GAAkC;AAE/C,IAAM,YAAA,GAAe,CAAC,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,OAAO,KAAK,CAAA;AACxG,IAAM,WAAA,GAAc,CAAC,SAAA,EAAW,UAAA,EAAY,OAAA,EAAS,OAAA,EAAS,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,WAAA,EAAa,SAAA,EAAW,YAAY,UAAU,CAAA;AAC7I,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,MAAM,CAAA,GAAI,CAAC,IAAA,EAAM,IAAA,EAAM,MAAM,IAAI,CAAA;AACjC,EAAA,MAAM,IAAI,CAAA,GAAI,GAAA;AACd,EAAA,OAAO,CAAA,EAAG,CAAC,CAAA,EAAG,CAAA,CAAA,CAAG,CAAA,GAAI,EAAA,IAAM,EAAE,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,CAAE,CAAC,CAAC,CAAA,CAAA;AAChD;AAGO,SAAS,gBAAA,CAAiB,KAAa,MAAA,EAA4B;AACxE,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,IAAI,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AAC3C,EAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,IAAK,CAAC,GAAG,OAAO,GAAA;AAC3B,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,YAAA;AACH,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,CAAC,CAAA,CAAA;AAAA,IACzB,KAAK,YAAA;AACH,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,CAAC,CAAA,CAAA;AAAA,IACzB,KAAK,YAAA;AACH,MAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,EAAE,IAAI,EAAE,CAAA,CAAA;AAAA,IACzB,KAAK,YAAA;AACH,MAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,YAAA,CAAa,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA,CAAA;AAAA,IACzC,KAAK,aAAA;AACH,MAAA,OAAO,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,aAAa,CAAA,GAAI,CAAC,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA;AAAA,IAClD,KAAK,cAAA;AACH,MAAA,OAAO,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,YAAY,CAAA,GAAI,CAAC,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA;AAAA,IACjD,KAAK,cAAA;AACH,MAAA,OAAO,CAAA,EAAG,YAAY,CAAA,GAAI,CAAC,CAAC,CAAA,CAAA,EAAI,CAAC,KAAK,CAAC,CAAA,CAAA;AAAA;AAE7C;AAGO,IAAM,kBAAA,GAAiD;AAAA,EAC5D,YAAA,EAAc,YAAA;AAAA,EACd,YAAA,EAAc,YAAA;AAAA,EACd,YAAA,EAAc,YAAA;AAAA,EACd,YAAA,EAAc,YAAA;AAAA,EACd,aAAA,EAAe,cAAA;AAAA,EACf,cAAA,EAAgB,kBAAA;AAAA,EAChB,cAAA,EAAgB;AAClB;;;ACpDO,IAAM,cAAA,GAA0C;AAAA,EACrD,OAAA;AAAA,EACA,UAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF;AACO,IAAM,kBAAA,GAAqBC,MAAE,IAAA,CAAK,CAAC,SAAS,UAAA,EAAY,KAAA,EAAO,UAAU,CAAC;AAgBjF,IAAM,IAAA,GAAOA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA;AAC7B,IAAM,eAAA,GAAkBA,MAC5B,MAAA,CAAO;AAAA,EACN,MAAMA,KAAA,CAAE,MAAA,GAAS,GAAA,EAAI,CAAE,IAAI,CAAC,CAAA;AAAA,EAC5B,CAAA,EAAG,IAAA;AAAA,EACH,CAAA,EAAG,IAAA;AAAA,EACH,CAAA,EAAGA,MAAE,MAAA,EAAO,CAAE,IAAI,IAAI,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,EAC7B,CAAA,EAAGA,MAAE,MAAA,EAAO,CAAE,IAAI,IAAI,CAAA,CAAE,IAAI,CAAC;AAC/B,CAAC,EACA,MAAA;AAyBH,IAAM,OAAA,GAAUA,KAAA,CAAE,MAAA,EAAO,CAAE,MAAM,qBAAqB,CAAA;AAC/C,IAAM,mBAAA,GAAsB,gBAChC,MAAA,CAAO;AAAA,EACN,EAAA,EAAIA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,EAAE,CAAA;AAAA,EAC5B,OAAOA,KAAA,CAAE,MAAA,GAAS,IAAA,EAAK,CAAE,IAAI,EAAE,CAAA;AAAA,EAC/B,IAAA,EAAMA,MAAE,IAAA,CAAK,CAAC,aAAa,MAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,WAAW,CAAA;AAAA,EACvD,UAAA,EAAYA,KAAA,CAAE,IAAA,CAAK,YAA6C,EAAE,QAAA,EAAS;AAAA,EAC3E,OAAA,EAAS,OAAA,CAAQ,QAAA,EAAS,CAAE,QAAA;AAC9B,CAAC,EACA,MAAA;AAEI,IAAM,oBAAA,GAAuB;AAC7B,IAAM,gBAAA,GAAmBA,MAC7B,KAAA,CAAM,mBAAmB,EACzB,GAAA,CAAI,CAAC,EACL,GAAA,CAAI,EAAE,EACN,MAAA,CAAO,CAAC,WAAW,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,WAAW,CAAA,EAAG;AAAA,EAC9D,OAAA,EAAS;AACX,CAAC;AAoBI,SAAS,UAAA,CACd,WACA,OAAA,EACe;AACf,EAAA,QAAQ,OAAA;AAAS,IACf,KAAK,OAAA;AACH,MAAA,OAAO,UAAU,KAAA,IAAS,IAAA;AAAA,IAC5B,KAAK,KAAA;AACH,MAAA,OAAO,UAAU,KAAA,IAAS,IAAA;AAAA,IAC5B,KAAK,UAAA;AACH,MAAA,OAAO,SAAA,CAAU,QAAA,IAAY,SAAA,CAAU,KAAA,IAAS,IAAA;AAAA,IAClD,KAAK,UAAA;AACH,MAAA,OAAO,IAAA;AAAA;AAEb;AA2CO,IAAM,sBAAA,GAAsDA,MAAE,KAAA,CAAM;AAAA,EACzEA,MACG,MAAA,CAAO;AAAA,IACN,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,KAAK,CAAA;AAAA,IACrB,IAAA,EAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,IACtB,OAAOA,KAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,IAClC,QAAQA,KAAA,CAAE,MAAA,CAAOA,MAAE,OAAA,EAAS,EAAE,QAAA;AAAS,GAGxC,EACA,MAAA,EAAO;AAAA,EACVA,MACG,MAAA,CAAO;AAAA,IACN,IAAA,EAAMA,KAAA,CAAE,OAAA,CAAQ,KAAK,CAAA;AAAA,IACrB,IAAA,EAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,IACtB,UAAA,EAAYA,KAAA,CAAE,KAAA,CAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC;AAAA,GAC7C,EACA,MAAA;AACL,CAAC;AAmLM,IAAM,qBAAA,GAAwBA,MAClC,MAAA,CAAO;AAAA,EACN,YAAA,EAAcA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,IAAS,CAAA;AAAA;AAAA,EAC7C,UAAA,EAAYA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAA,GAAO,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA;AAAA,EAC5C,OAAA,EAASA,KAAA,CAAE,OAAA,CAAQ,IAAI,CAAA;AAAA,EACvB,UAAA,EAAYA,KAAA,CAAE,MAAA,CAAOA,KAAA,CAAE,QAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,EAAE,CAAA,EAAG,OAAO,EAAE,QAAA;AAC3D,CAAC,EACA,MAAA;AAGI,IAAM,gBAAgBA,KAAA,CAC1B,MAAA,CAAO,EAAE,MAAA,EAAQA,MAAE,MAAA,EAAO,CAAE,IAAA,EAAK,CAAE,IAAI,GAAG,CAAA,CAAE,UAAS,EAAG,EACxD,MAAA;ACzXH,IAAM,QAAA,GACJ,gEAAA;AAQK,SAAS,GAAA,CAAI,OAAO,EAAA,EAAY;AACrC,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,OAAO,GAAA,CAAI,SAAS,IAAA,EAAM;AACxB,IAAA,KAAA,MAAW,IAAA,IAAQD,kBAAAA,CAAY,IAAI,CAAA,EAAG;AACpC,MAAA,IAAI,OAAO,GAAA,EAAK;AAEd,QAAA,GAAA,IAAO,QAAA,CAAS,OAAO,EAAE,CAAA;AACzB,QAAA,IAAI,GAAA,CAAI,WAAW,IAAA,EAAM;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;;;ACDA,eAAsB,WAAA,CACpB,WAAA,EACA,SAAA,EACA,IAAA,EACA,KAAA,EACoB;AACpB,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,IAAA,EAAM,KAAK,CAAA;AACpC,EAAA,MAAM,YAAY,gBAAA,CAAiB;AAAA,IACjC,SAAA;AAAA,IACA,KAAK,IAAA,CAAK,GAAA;AAAA,IACV,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,MAAM,IAAA,CAAK;AAAA,GACZ,CAAA;AACD,EAAA,OAAO,IAAA;AACT;AAaA,IAAM,iBAAyC,CAAC;AAAA,EAC9C,aAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,MAAO;AAAA,EACL,OAAA,EAAS,gBAAgB,aAAa,CAAA,CAAA;AAAA,EACtC,IAAA,EAAM;AAAA,IACJ,SAAS,aAAa,CAAA,CAAA,CAAA;AAAA,IACtB,IAAA,IAAQ,2CAA2C,aAAa,CAAA,CAAA,CAAA;AAAA,IAChE;AAAA,GACF,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,MAAM;AAChB,CAAA,CAAA;AAgCA,IAAM,MAAA,GAAS,KAAA;AAQf,eAAsB,cAAA,CACpB,MACA,IAAA,EAC+B;AAC/B,EAAA,MAAM,EAAE,WAAA,EAAa,QAAA,EAAU,UAAU,KAAA,EAAO,OAAA,EAAS,mBAAkB,GAAI,IAAA;AAC/E,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,cAAA;AAEhC,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AAC9B,IAAA,MAAM,IAAI,UAAA,CAAW,eAAA,EAAiB,8BAA8B,CAAA;AAAA,EACtE;AAEA,EAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,UAAA,CAAW,KAAK,iBAAiB,CAAA;AACnE,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,UAAA,CAAW,aAAa,6BAA6B,CAAA;AAC7E,EAAA,MAAM,QAAA,GAAW,MAAM,WAAA,CAAY,WAAA,CAAY,QAAQ,UAAU,CAAA;AACjE,EAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,UAAA,CAAW,aAAa,qBAAqB,CAAA;AAEtE,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,UAAU,IAAI,CAAA;AACnD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,eAAA;AAAA,MACA,CAAA,sBAAA,EAAyB,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,CAAA;AAAA,KAC9C;AAAA,EACF;AAEA,EAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,QAAA,CAAS,oBAAoB,CAAA;AACxD,EAAA,MAAM,QAAA,GAAW,KAAK,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,UAAA,CAAW,GAAA,CAAI,CAAC,CAAC,CAAA;AAC9D,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,eAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,QAAA,CAAS,OAAA;AACzC,EAAA,MAAM,QAAA,GAAW,MAAM,UAAA,CAAW,iBAAA,CAAkB;AAAA,IAClD,OAAA;AAAA,IACA,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB;AAAA,GACD,CAAA;AACD,EAAA,MAAM,UAAU,QAAA,CAAS,OAAA;AACzB,EAAA,IAAI,aAAa,QAAA,CAAS,UAAA;AAI1B,EAAA,IAAI,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,YAAA,KAAiB,KAAA,EAAO;AACpD,IAAA,MAAM,SAAA,GAAY,MAAM,WAAA,CAAY,uBAAA,CAAwB,QAAQ,UAAU,CAAA;AAC9E,IAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,SAAA,EAAW,CAAC,CAAC,CAAC,CAAA;AAC3D,IAAA,MAAM,OAAO,OAAA,CAAQ,OAAA;AACrB,IAAA,UAAA,GAAa,UAAA,CAAW,MAAA,CAAO,CAAC,CAAA,KAAM;AACpC,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,SAAS,CAAA;AAC9B,MAAA,QAAQ,KAAK,YAAA;AAAc,QACzB,KAAK,WAAA;AACH,UAAA,OAAO,CAAC,CAAA;AAAA,QACV,KAAK,aAAA;AACH,UAAA,OAAO,EAAE,CAAA,IAAK,CAAA,CAAE,MAAA,KAAW,QAAA,IAAY,EAAE,OAAA,IAAW,IAAA,CAAA;AAAA,QACtD,KAAK,cAAA;AACH,UAAA,OAAO,QAAQ,CAAA,IAAK,CAAA,CAAE,WAAW,QAAA,IAAY,CAAA,CAAE,UAAU,IAAI,CAAA;AAAA,QAC/D;AACE,UAAA,OAAO,IAAA;AAAA;AACX,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG,OAAO,EAAE,UAAA,EAAY,IAAA,EAAM,IAAA,EAAM,CAAA,EAAG,OAAA,EAAQ;AAEzE,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,EAAI;AACtB,EAAA,MAAM,YAAY,IAAI,IAAA;AAAA,IACpB,GAAA,CAAI,OAAA,EAAQ,GAAA,CAAK,IAAA,CAAK,iBAAiB,iBAAA,IAAqB;AAAA,GAC9D;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,WAAA,CAAY,cAAA,CAAe;AAAA,IAChD,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,mBAAmB,OAAA,CAAQ,EAAA;AAAA,IAC3B,OAAA;AAAA,IACA,IAAA,EAAM,KAAK,IAAA,IAAQ,IAAA;AAAA,IACnB,YAAA,EAAc,KAAK,YAAA,IAAgB,KAAA;AAAA,IACnC,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,SAAA;AAAA,IACA,WAAA,EAAa,KAAK,WAAA,IAAe;AAAA,GAClC,CAAA;AAED,EAAA,MAAM,aAAA,GACJ,KAAK,SAAA,CAAU,IAAA,KAAS,QAAS,IAAA,CAAK,SAAA,CAAU,SAAS,IAAA,GAAQ,IAAA;AAInE,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAM;AACrC,IAAA,MAAM,QAAQ,eAAA,EAAgB;AAC9B,IAAA,MAAM,GAAA,GAAqB;AAAA,MACzB,IAAI,GAAA,EAAI;AAAA,MACR,YAAY,QAAA,CAAS,EAAA;AAAA,MACrB,YAAY,OAAA,CAAQ,UAAA;AAAA,MACpB,mBAAmB,OAAA,CAAQ,EAAA;AAAA,MAC3B,OAAA;AAAA,MACA,aAAa,CAAA,CAAE,WAAA;AAAA,MACf,WAAW,CAAA,CAAE,SAAA;AAAA,MACb,YAAA,EAAc,aAAA,IAAiB,CAAA,CAAE,KAAA,IAAS,IAAA;AAAA,MAC1C,eAAe,CAAA,CAAE,IAAA;AAAA,MACjB,cAAA,EAAgB,EAAE,KAAA,IAAS,IAAA;AAAA,MAC3B,iBAAA,EAAmB,EAAE,QAAA,IAAY,IAAA;AAAA,MACjC,QAAA;AAAA,MACA,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB;AAAA,KACF;AACA,IAAA,OAAO,EAAE,GAAA,EAAK,SAAA,EAAW,KAAA,CAAM,SAAA,EAAW,WAAW,CAAA,EAAE;AAAA,EACzD,CAAC,CAAA;AAED,EAAA,MAAM,WAAA,CAAY,eAAe,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAG,CAAC,CAAA;AAE3D,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACtC,EAAA,MAAM,MAAA,GAAS,IAAI,WAAA,EAAY;AAC/B,EAAA,IAAI,IAAA,GAAO,CAAA;AAEX,EAAA,KAAA,MAAW,EAAE,GAAA,EAAK,SAAA,EAAW,SAAA,MAAe,QAAA,EAAU;AACpD,IAAA,IAAI,OAAO,MAAM,WAAA,CAAY,WAAA,EAAa,GAAA,CAAI,IAAI,IAAA,EAAM;AAAA,MACtD,IAAA,EAAM,SAAA;AAAA,MACN,OAAA,EAAS;AAAA,QACP,aAAa,GAAA,CAAI,WAAA;AAAA,QACjB,WAAW,GAAA,CAAI,SAAA;AAAA,QACf,EAAA,EAAI,KAAK,WAAA,IAAe;AAAA,OAC1B;AAAA,MACA,UAAA,EAAY;AAAA,KACb,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,CAAA,EAAG,IAAI,CAAA,MAAA,EAAS,SAAS,CAAA,CAAA;AAC3C,IAAA,MAAM,IAAI,OAAA,CAAQ;AAAA,MAChB,eAAe,QAAA,CAAS,KAAA;AAAA,MACxB,IAAA,EAAM,KAAK,IAAA,IAAQ,IAAA;AAAA,MACnB,eAAe,SAAA,CAAU;AAAA,KAC1B,CAAA;AAED,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,MAAM,OAAA,GAAU,UAAA,CAAW,SAAA,EAAW,OAAO,CAAA;AAC7C,MAAA,IAAI,CAAC,OAAA,EAAS;AACd,MAAA,IAAIE,GAAAA,GAAK,KAAA;AACT,MAAA,IAAI,KAAA,GAAuB,IAAA;AAC3B,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,IAAA,CAAK;AAAA,UACjC,OAAA;AAAA,UACA,SAAA,EAAW,OAAA;AAAA,UACX,SAAS,CAAA,CAAE,OAAA;AAAA,UACX,MAAM,CAAA,CAAE,IAAA;AAAA,UACR,SAAA;AAAA,UACA,gBAAgB,GAAA,CAAI;AAAA,SACrB,CAAA;AACD,QAAAA,MAAK,MAAA,CAAO,EAAA;AACZ,QAAA,KAAA,GAAQ,OAAO,KAAA,IAAS,IAAA;AAAA,MAC1B,SAAS,GAAA,EAAK;AACZ,QAAAA,GAAAA,GAAK,KAAA;AACL,QAAA,KAAA,GAAQ,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAAA,MACzD;AACA,MAAA,IAAA,GAAO,MAAM,WAAA,CAAY,WAAA,EAAa,GAAA,CAAI,IAAI,IAAA,EAAM;AAAA,QAClD,IAAA,EAAM,UAAA;AAAA,QACN,OAAA,EAAS,EAAE,OAAA,EAAS,EAAA,EAAAA,KAAI,KAAA,EAAM;AAAA,QAC9B,UAAA,EAAY;AAAA,OACb,CAAA;AAAA,IACH;AACA,IAAA,IAAA,EAAA;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,UAAA,EAAY,QAAA,CAAS,EAAA,EAAI,MAAM,OAAA,EAAQ;AAClD;;;AC5PA,eAAsB,gBAAA,CACpB,MACA,UAAA,EACyB;AACzB,EAAA,MAAM,EAAE,WAAA,EAAa,QAAA,EAAS,GAAI,IAAA;AAClC,EAAA,MAAM,GAAA,GAAM,MAAM,WAAA,CAAY,WAAA,CAAY,UAAU,CAAA;AACpD,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,UAAA,CAAW,aAAa,qBAAqB,CAAA;AAEjE,EAAA,MAAM,SAAA,GAAY,MAAM,WAAA,CAAY,uBAAA,CAAwB,UAAU,CAAA;AACtE,EAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,SAAA,CAAU,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAE5D,EAAA,IAAI,aAAA,GAAgB,CAAA;AACpB,EAAA,IAAI,IAAI,gBAAA,EAAkB;AACxB,IAAA,MAAM,CAAA,GAAI,MAAM,WAAA,CAAY,UAAA,CAAW,IAAI,gBAAgB,CAAA;AAC3D,IAAA,aAAA,GAAgB,GAAG,OAAA,IAAW,CAAA;AAAA,EAChC;AAEA,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AACzB,IAAA,IAAI,CAAA,CAAE,WAAW,QAAA,EAAU;AACzB,MAAA,IAAI,CAAA,CAAE,WAAW,aAAA,EAAe,MAAA,EAAA;AAAA,WAC3B,WAAA,EAAA;AAAA,IACP,WAAW,CAAA,CAAE,MAAA,KAAW,SAAA,IAAa,CAAA,CAAE,WAAW,QAAA,EAAU;AAC1D,MAAA,WAAA,EAAA;AAAA,IACF;AAAA,EACF;AAGA,EAAA,IAAI,OAAyB,EAAC;AAC9B,EAAA,IAAI,IAAI,QAAA,EAAU;AAChB,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,SAAS,IAAI,CAAA;AACjD,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,CAAW,YAAA,CAAa;AAAA,QACzC,SAAS,GAAA,CAAI,OAAA;AAAA,QACb,OAAO,GAAA,CAAI,QAAA,CAAS,SAAS,KAAA,GAAQ,GAAA,CAAI,SAAS,KAAA,GAAQ,MAAA;AAAA,QAC1D,QAAQ,GAAA,CAAI,QAAA,CAAS,SAAS,KAAA,GAAQ,GAAA,CAAI,SAAS,MAAA,GAAS,MAAA;AAAA,QAC5D,KAAA,EAAO;AAAA,OACR,CAAA;AACD,MAAA,IAAA,GAAO,IAAA,CAAK,QAAA;AAAA,IACd;AAAA,EACF;AACA,EAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAEpD,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,SAAS,CAAC,CAAA;AACjE,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,QAAA,GACjB,SAAA,CACG,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,SAAS,CAAC,CAAA,CACvC,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,WAAA,EAAa,GAAA,CAAI,QAAA,CAAU,IAAA,EAAM,SAAA,EAAW,CAAA,CAAE,SAAA,EAAU,CAAE,CAAA,GAC3E,EAAC;AAEL,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,UAAU,IAAA,CAAK,MAAA;AAAA,IACf,MAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF;;;ACrCA,eAAsB,cAAA,CACpB,MACA,KAAA,EAC+B;AAC/B,EAAA,MAAM,IAAA,GAAmB,MAAM,IAAA,IAAQ,MAAA;AACvC,EAAA,MAAM,MAAM,MAAM,IAAA,CAAK,WAAA,CAAY,0BAAA,CAA2B,MAAM,UAAU,CAAA;AAC9E,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,QAAQ,WAAA,EAAY;AAGlD,EAAA,IAAI,IAAA,KAAS,OAAA,IAAW,GAAA,CAAI,WAAA,GAAc,CAAA,EAAG;AAC3C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,gBAAA,EAAiB;AAAA,EAC/C;AAEA,EAAA,IAAI,SAAS,OAAA,EAAS;AAIpB,IAAA,MAAM,IAAA,CAAK,WAAA,CAAY,kBAAA,CAAmB,KAAA,CAAM,UAAU,CAAA;AAC1D,IAAA,MAAM,OAAO,CAAC,GAAG,IAAI,UAAA,EAAY,GAAG,IAAI,UAAU,CAAA;AAClD,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,MAAM,KAAK,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,IACtD;AACA,IAAA,MAAM,WAAA,CAAY,IAAA,CAAK,KAAA,EAAO,GAAA,EAAK,OAAO,CAAA;AAC1C,IAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,YAAY,KAAA,CAAM,UAAA,EAAY,aAAA,EAAe,IAAA,CAAK,MAAA,EAAO;AAAA,EAC7F;AAEA,EAAA,MAAM,IAAA,CAAK,YAAY,kBAAA,CAAmB,KAAA,CAAM,YAAY,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAC5E,EAAA,MAAM,WAAA,CAAY,IAAA,CAAK,KAAA,EAAO,GAAA,EAAK,MAAM,CAAA;AACzC,EAAA,OAAO,EAAE,IAAI,IAAA,EAAM,IAAA,EAAM,QAAQ,UAAA,EAAY,KAAA,CAAM,UAAA,EAAY,aAAA,EAAe,CAAA,EAAE;AAClF;AAEA,eAAe,WAAA,CACb,KAAA,EACA,GAAA,EACA,IAAA,EACe;AACf,EAAA,IAAI,CAAC,OAAO,iBAAA,EAAmB;AAC/B,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,iBAAA,CAAkB;AAAA,MAC5B,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,cAAc,GAAA,CAAI,YAAA;AAAA,MAClB,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,IAAA;AAAA,MACA,kBAAkB,GAAA,CAAI;AAAA,KACvB,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AClEA,eAAsB,cAAA,CACpB,aACA,KAAA,EAC6B;AAC7B,EAAA,IAAI,CAAC,KAAA,CAAM,KAAA,CAAM,IAAA,EAAK,EAAG;AACvB,IAAA,MAAM,IAAI,UAAA,CAAW,eAAA,EAAiB,+BAA+B,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,YAAY,cAAA,CAAe;AAAA,IAChC,OAAA,EAAS,MAAM,OAAA,IAAW,IAAA;AAAA,IAC1B,YAAA,EAAc,MAAM,YAAA,IAAgB,IAAA;AAAA,IACpC,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,QAAA,EAAU,MAAM,QAAA,IAAY,IAAA;AAAA,IAC5B,WAAA,EAAa,MAAM,WAAA,IAAe;AAAA,GACnC,CAAA;AACH;AAgBA,eAAe,kBAAkB,KAAA,EAAkC;AACjE,EAAA,IAAI;AACF,IAAA,MAAMC,kBAAA,CAAY,KAAK,KAAK,CAAA;AAAA,EAC9B,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,eAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACF;AAOA,eAAsB,UAAA,CACpB,MACA,KAAA,EACoC;AACpC,EAAA,MAAM,EAAE,WAAA,EAAa,OAAA,EAAQ,GAAI,IAAA;AAEjC,EAAA,IAAI,eAAA;AACJ,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,WAAA,IAAe,MAAM,MAAA,EAAQ;AAC/B,IAAA,eAAA,GAAkB,MAAM,MAAA,CAAO,SAAA;AAC/B,IAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA;AACjD,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,MAAM,IAAI,UAAA,CAAW,eAAA,EAAiB,wCAAwC,CAAA;AAAA,IAChF;AACA,IAAA,KAAA,GAAQ,OAAA,CAAQ,KAAA;AAAA,EAClB,CAAA,MAAO;AACL,IAAA,KAAA,GAAQ,MAAM,MAAA,CAAO,QAAA;AACrB,IAAA,eAAA,GAAkB,QAAQ,QAAA,CAAS;AAAA,MACjC,OAAA,EAAS,KAAA,CAAM,MAAA,CAAO,OAAA,IAAW,IAAA;AAAA,MACjC,YAAY,KAAA,CAAM,UAAA;AAAA,MAClB,WAAA,EAAa;AAAA,KACd,CAAA;AACD,IAAA,MAAM,QAAQ,GAAA,CAAI;AAAA,MAChB,SAAA,EAAW,eAAA;AAAA,MACX,KAAA;AAAA,MACA,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,kBAAkB,KAAK,CAAA;AAE7B,EAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,aAAA,CAAc,MAAM,UAAU,CAAA;AAC/D,EAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,aAAA,CAAc;AAAA,IAC9C,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,OAAA,EAAA,CAAU,MAAA,EAAQ,OAAA,IAAW,CAAA,IAAK,CAAA;AAAA,IAClC,eAAA;AAAA,IACA,YAAA,EAAc,UAAU,KAAK,CAAA;AAAA,IAC7B,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,UAAA,EAAY,MAAM,UAAA,IAAc,IAAA;AAAA,IAChC,WAAA,EAAa,MAAM,WAAA,IAAe;AAAA,GACnC,CAAA;AAED,EAAA,MAAM,WAAA,CAAY,cAAA,CAAe,KAAA,CAAM,UAAA,EAAY;AAAA,IACjD,kBAAkB,OAAA,CAAQ;AAAA,GAC3B,CAAA;AAED,EAAA,OAAO,OAAA;AACT;;;ACtEO,SAAS,YACd,OAAA,EACA;AACA,EAAA,OAAO,OAAO,KAAc,GAAA,KAAgC;AAC1D,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,OAAA,CAAQ,GAAA,EAAK,GAAG,CAAA;AAAA,IAC/B,SAAS,GAAA,EAAK;AACZ,MAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,IAC5B;AAAA,EACF,CAAA;AACF;AAEA,eAAsB,SAAA,CAAa,KAAc,MAAA,EAAgC;AAC/E,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAI,IAAA,EAAK;AAAA,EACvB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,UAAA,CAAW,eAAA,EAAiB,kCAAkC,CAAA;AAAA,EAC1E;AACA,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA;AACnC,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,MAAM,IAAI,UAAA,CAAW,eAAA,EAAiB,sBAAsB,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA;AAAA,EACpF;AACA,EAAA,OAAO,MAAA,CAAO,IAAA;AAChB;AAEO,SAAS,EAAA,CAAG,MAAe,IAAA,EAA+B;AAC/D,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AACjC;AAGO,SAAS,SAAS,GAAA,EAA6B;AACpD,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,iBAAiB,CAAA;AAC7C,EAAA,IAAI,GAAA,SAAY,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAG,IAAA,EAAK,IAAK,IAAA;AAC7C,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA;AACpC;;;AC/DO,IAAM,cAAA,GAAyC;AAAA,EACpD,SAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF;AAGO,IAAM,eAAA,GAA0C,CAAC,SAAA,EAAW,QAAQ;AAGpE,IAAM,iBAAA,GAA4C;AAAA,EACvD,QAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF;AAEA,IAAM,WAAA,GAA2D;AAAA,EAC/D,SAAS,CAAC,QAAA,EAAU,QAAA,EAAU,UAAA,EAAY,WAAW,SAAS,CAAA;AAAA,EAC9D,MAAA,EAAQ,CAAC,QAAA,EAAU,UAAA,EAAY,WAAW,SAAS,CAAA;AAAA,EACnD,QAAQ,EAAC;AAAA,EACT,UAAU,EAAC;AAAA,EACX,SAAS,EAAC;AAAA,EACV,SAAS;AACX,CAAA;AAEO,SAAS,SAAS,MAAA,EAA8B;AACrD,EAAA,OAAO,eAAA,CAAgB,SAAS,MAAM,CAAA;AACxC;AAEO,SAAS,WAAW,MAAA,EAA8B;AACvD,EAAA,OAAO,iBAAA,CAAkB,SAAS,MAAM,CAAA;AAC1C;AAGO,SAAS,aAAA,CAAc,MAAmB,EAAA,EAA0B;AACzE,EAAA,IAAI,IAAA,KAAS,IAAI,OAAO,IAAA;AACxB,EAAA,OAAO,WAAA,CAAY,IAAI,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA;AACtC;AAGO,SAAS,gBAAA,CAAiB,MAAmB,EAAA,EAAuB;AACzE,EAAA,IAAI,CAAC,aAAA,CAAc,IAAA,EAAM,EAAE,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,UAAA;AAAA,MACA,CAAA,oCAAA,EAAuC,IAAI,CAAA,QAAA,EAAM,EAAE,CAAA,CAAA;AAAA,KACrD;AAAA,EACF;AACF;AC3CA,IAAM,EAAA,GAAuB,CAAC,MAAA,EAAQ,MAAM,CAAA;AAC5C,IAAM,MAAA,GAAS,EAAA;AACf,IAAM,GAAA,GAAMC,UAAA,CAAI,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAChC,IAAM,KAAA,GAAQA,UAAA,CAAI,GAAA,EAAK,IAAA,EAAM,IAAI,CAAA;AAEjC,eAAsB,0BAAA,CACpB,KACA,IAAA,EACe;AACf,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA;AAC3B,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,SAAA,CAAUC,qBAAc,SAAS,CAAA;AACxD,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,SAAA,CAAUA,qBAAc,aAAa,CAAA;AAC5D,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,SAAA,CAAUA,qBAAc,OAAO,CAAA;AACtD,EAAA,MAAM,CAAC,KAAA,EAAO,KAAK,CAAA,GAAI,EAAA;AAEvB,EAAA,IAAI,IAAI,KAAA,GAAQ,MAAA;AAChB,EAAA,MAAM,IAAA,GAAO,CACX,IAAA,EACA,IAAA,GAA0E,EAAC,KACxE;AACH,IAAA,IAAA,CAAK,SAAS,IAAA,EAAM;AAAA,MAClB,CAAA,EAAG,KAAK,CAAA,IAAK,MAAA;AAAA,MACb,CAAA;AAAA,MACA,IAAA,EAAM,KAAK,IAAA,IAAQ,EAAA;AAAA,MACnB,IAAA,EAAM,KAAK,IAAA,IAAQ,IAAA;AAAA,MACnB,KAAA,EAAO,KAAK,KAAA,IAAS;AAAA,KACtB,CAAA;AAAA,EACH,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,CAAC,EAAA,KAAe;AAC9B,IAAA,CAAA,IAAK,EAAA;AAAA,EACP,CAAA;AAEA,EAAA,IAAA,CAAK,yBAAyB,EAAE,IAAA,EAAM,EAAA,EAAI,IAAA,EAAM,MAAM,CAAA;AACtD,EAAA,OAAA,CAAQ,EAAE,CAAA;AACV,EAAA,IAAA,CAAK,0EAAA,EAA4E;AAAA,IAC/E,IAAA,EAAM,CAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACR,CAAA;AACD,EAAA,OAAA,CAAQ,EAAE,CAAA;AAEV,EAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,EAAe,KAAA,EAAe,YAAqB,IAAA,KAAS;AACzE,IAAA,IAAA,CAAK,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,EAAG,MAAM,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA;AACjD,IAAA,OAAA,CAAQ,EAAE,CAAA;AACV,IAAA,IAAA,CAAK,OAAO,EAAE,IAAA,EAAM,EAAA,EAAI,IAAA,EAAM,WAAW,CAAA;AACzC,IAAA,OAAA,CAAQ,EAAE,CAAA;AAAA,EACZ,CAAA;AAEA,EAAA,KAAA,CAAM,UAAA,EAAY,KAAK,aAAa,CAAA;AACpC,EAAA,KAAA,CAAM,WAAA,EAAa,KAAK,UAAU,CAAA;AAClC,EAAA,KAAA,CAAM,WAAA,EAAa,KAAK,QAAQ,CAAA;AAChC,EAAA,KAAA,CAAM,WAAA,EAAa,IAAA,CAAK,QAAA,IAAY,QAAG,CAAA;AACvC,EAAA,KAAA,CAAM,YAAA,EAAc,IAAA,CAAK,SAAA,EAAW,IAAI,CAAA;AACxC,EAAA,KAAA,CAAM,kBAAA,EAAoB,IAAA,CAAK,cAAA,EAAgB,IAAI,CAAA;AACnD,EAAA,KAAA,CAAM,iBAAA,EAAmB,IAAA,CAAK,SAAA,EAAW,IAAI,CAAA;AAE7C,EAAA,OAAA,CAAQ,CAAC,CAAA;AACT,EAAA,IAAA,CAAK,aAAA,EAAe,EAAE,IAAA,EAAM,CAAA,EAAG,MAAM,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA;AACzD,EAAA,OAAA,CAAQ,EAAE,CAAA;AAGV,EAAA,IAAA,CAAK,GAAA,EAAK,EAAE,CAAA,EAAG,MAAA,EAAQ,IAAA,EAAM,GAAG,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,KAAA,EAAO,CAAA;AAC1D,EAAA,IAAA,CAAK,OAAA,EAAS,EAAE,CAAA,EAAG,MAAA,GAAS,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,KAAA,EAAO,CAAA;AACnE,EAAA,IAAA,CAAK,MAAA,EAAQ,EAAE,CAAA,EAAG,MAAA,GAAS,GAAA,EAAK,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,KAAA,EAAO,CAAA;AACnE,EAAA,IAAA,CAAK,MAAA,EAAQ,EAAE,CAAA,EAAG,MAAA,GAAS,GAAA,EAAK,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,KAAA,EAAO,CAAA;AACnE,EAAA,OAAA,CAAQ,CAAC,CAAA;AACT,EAAA,IAAA,CAAK,QAAA,CAAS;AAAA,IACZ,KAAA,EAAO,EAAE,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAE;AAAA,IACtB,GAAA,EAAK,EAAE,CAAA,EAAG,KAAA,GAAQ,QAAQ,CAAA,EAAE;AAAA,IAC5B,SAAA,EAAW,GAAA;AAAA,IACX,KAAA,EAAO;AAAA,GACR,CAAA;AACD,EAAA,OAAA,CAAQ,EAAE,CAAA;AAEV,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAK,KAAA,EAAO;AAC7B,IAAA,IAAI,CAAA,GAAI,SAAS,EAAA,EAAI;AACrB,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,GAAG,CAAA,EAAG,EAAE,CAAA,EAAG,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAG,CAAA;AAC7C,IAAA,IAAA,CAAK,IAAA,CAAK,MAAM,EAAE,CAAA,EAAG,SAAS,EAAA,EAAI,IAAA,EAAM,GAAG,CAAA;AAC3C,IAAA,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,EAAE,CAAA,EAAG,MAAA,GAAS,KAAK,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,KAAA,EAAO,CAAA;AAChE,IAAA,IAAA,CAAK,GAAG,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,MAAA,CAAA,EAAK,EAAE,CAAA,EAAG,SAAS,GAAA,EAAK,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,MAAM,CAAA;AAC3E,IAAA,OAAA,CAAQ,EAAE,CAAA;AAAA,EACZ;AACF;;;AC1DA,eAAsB,QAAQ,KAAA,EAAuC;AACnE,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAMF,kBAAAA,CAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,eAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AACpC,EAAA,GAAA,CAAI,gBAAgB,IAAI,CAAA;AACxB,EAAA,GAAA,CAAI,oBAAoB,IAAI,CAAA;AAC5B,EAAA,GAAA,CAAI,YAAY,qBAAqB,CAAA;AACrC,EAAA,GAAA,CAAI,WAAW,qBAAqB,CAAA;AAEpC,EAAA,MAAM,KAAA,GAAQ,IAAI,QAAA,EAAS;AAC3B,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,QAAA,CAAS,MAAM,YAAY,CAAA;AACjD,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,SAAA,CAAUE,qBAAc,SAAS,CAAA;AACxD,EAAA,MAAM,OAAA,GAAU,CAAA,UAAA,EAAa,KAAA,CAAM,UAAU,SAAM,KAAA,CAAM,QAAQ,CAAA,EAC/D,KAAA,CAAM,QAAA,GAAW,CAAA,SAAA,EAAS,KAAA,CAAM,QAAQ,KAAK,EAC/C,CAAA,CAAA;AAIA,EAAA,IAAI,YAAA,GAAe,KAAA;AACnB,EAAA,KAAA,CAAM,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC9B,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,IAAA,GAAO,CAAA,EAAG,CAAC,CAAA,EAAG,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AACxE,IAAA,MAAM,IAAA,GAAO,MAAM,SAAS,CAAA;AAC5B,IAAA,MAAM,KAAA,GAAQ,KAAK,QAAA,EAAS;AAC5B,IAAA,MAAM,KAAA,GAAQ,KAAK,SAAA,EAAU;AAE7B,IAAA,MAAM,IAAA,GAAO,MAAM,CAAA,GAAI,KAAA;AACvB,IAAA,MAAM,IAAA,GAAO,MAAM,CAAA,GAAI,KAAA;AACvB,IAAA,MAAM,IAAA,GAAO,MAAM,CAAA,GAAI,KAAA;AACvB,IAAA,MAAM,UAAA,GAAa,KAAA,IAAS,CAAA,GAAI,KAAA,CAAM,IAAI,KAAA,CAAM,CAAA,CAAA;AAEhD,IAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAQ;AACzB,MAAA,MAAM,GAAA,GAAM,KAAA,CAAM,UAAA,CAAW,KAAA,CAAM,EAAE,CAAA;AACrC,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,GAAA,EAAK,KAAA,CAAM,cAAc,mBAAmB,CAAA;AAC1E,MAAA,IAAI,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,GAAO,MAAM,EAAE,CAAA;AACnC,MAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,iBAAA,CAAkB,IAAA,EAAM,IAAI,CAAA;AAC7C,MAAA,IAAI,KAAA,GAAQ,IAAA,IAAQ,KAAA,GAAQ,CAAA,EAAG;AAC7B,QAAA,IAAA,IAAQ,IAAA,GAAO,KAAA;AACf,QAAA,KAAA,GAAQ,IAAA,CAAK,iBAAA,CAAkB,IAAA,EAAM,IAAI,CAAA;AAAA,MAC3C;AACA,MAAA,IAAA,CAAK,SAAS,IAAA,EAAM;AAAA,QAClB,GAAG,IAAA,GAAO,IAAA,CAAK,IAAI,CAAA,EAAA,CAAI,IAAA,GAAO,SAAS,CAAC,CAAA;AAAA,QACxC,CAAA,EAAG,UAAA,GAAA,CAAc,IAAA,GAAO,IAAA,IAAQ,IAAI,IAAA,GAAO,IAAA;AAAA,QAC3C,IAAA;AAAA,QACA,IAAA;AAAA,QACA,KAAA,EAAOD,UAAAA,CAAI,GAAA,EAAK,GAAA,EAAK,IAAI;AAAA,OAC1B,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,IAAA,GAAO,IAAI,KAAA,EAAO,IAAA,GAAO,IAAI,MAAM,CAAA;AAC1D,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,GAAQ,KAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,GAAS,KAAA;AAC3B,IAAA,IAAA,CAAK,UAAU,GAAA,EAAK;AAAA,MAClB,CAAA,EAAG,IAAA,GAAA,CAAQ,IAAA,GAAO,KAAA,IAAS,CAAA;AAAA,MAC3B,CAAA,EAAG,UAAA,GAAA,CAAc,IAAA,GAAO,KAAA,IAAS,CAAA;AAAA,MACjC,KAAA,EAAO,KAAA;AAAA,MACP,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,YAAA,GAAe,IAAA;AACf,MAAA,IAAA,CAAK,SAAS,OAAA,EAAS;AAAA,QACrB,CAAA,EAAG,IAAA;AAAA,QACH,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,UAAA,GAAa,IAAI,CAAC,CAAA;AAAA,QAC9B,IAAA,EAAM,CAAA;AAAA,QACN,IAAA;AAAA,QACA,KAAA,EAAOA,UAAAA,CAAI,IAAA,EAAM,IAAA,EAAM,GAAG;AAAA,OAC3B,CAAA;AAAA,IACH;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,MAAM,eAAe,MAAM,GAAA,CAAI,KAAK,EAAE,gBAAA,EAAkB,OAAO,CAAA;AAC/D,EAAA,MAAM,cAAA,GAAiB,UAAU,YAAY,CAAA;AAE7C,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,EAAA,CAAG,EAAE,CAAA,IAAK,IAAA;AACxC,EAAA,MAAM,MAAA,GAAS,YAAY,IAAA,EAAM;AAAA,IAC/B,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EAAS;AAAA,MACP,YAAY,KAAA,CAAM,UAAA;AAAA,MAClB,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,UAAU,KAAA,CAAM;AAAA,KAClB;AAAA,IACA,YAAY,KAAA,CAAM;AAAA,GACnB,CAAA;AACD,EAAA,MAAM,MAAA,GAAS,YAAY,MAAA,EAAQ;AAAA,IACjC,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EAAS,EAAE,cAAA,EAAe;AAAA,IAC1B,YAAY,KAAA,CAAM;AAAA,GACnB,CAAA;AACD,EAAA,MAAM,YAAY,MAAA,CAAO,IAAA;AAEzB,EAAA,MAAM,2BAA2B,GAAA,EAAK;AAAA,IACpC,eAAe,KAAA,CAAM,aAAA;AAAA,IACrB,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,cAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAO,CAAC,GAAG,KAAA,CAAM,UAAA,EAAY,QAAQ,MAAM;AAAA,GAC5C,CAAA;AAED,EAAA,MAAM,YAAY,MAAM,GAAA,CAAI,KAAK,EAAE,gBAAA,EAAkB,OAAO,CAAA;AAC5D,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,YAAA,EAAc,UAAU,SAAS,CAAA;AAAA,IACjC,cAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA,EAAU,CAAC,MAAA,EAAQ,MAAM;AAAA,GAC3B;AACF;;;AC9IA,IAAM,MAAA,GAAS,CAAC,CAAA,MAAwC;AAAA,EACtD,KAAK,CAAA,CAAE,GAAA;AAAA,EACP,MAAM,CAAA,CAAE,IAAA;AAAA,EACR,OAAA,EAAU,CAAA,CAAE,OAAA,IAAuC,EAAC;AAAA,EACpD,UAAU,CAAA,CAAE,QAAA;AAAA,EACZ,MAAM,CAAA,CAAE,IAAA;AAAA,EACR,YAAY,CAAA,CAAE;AAChB,CAAA,CAAA;AAGA,eAAe,OAAA,CACb,aACA,KAAA,EACmC;AACnC,EAAA,OAAO,WAAA,CAAY,sBAAA,CAAuB,SAAA,CAAU,KAAK,CAAC,CAAA;AAC5D;AAcA,eAAsB,cAAA,CACpB,MACA,KAAA,EAC6B;AAC7B,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,IAAA,CAAK,aAAa,KAAK,CAAA;AACrD,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,IAAI,CAAC,QAAA,CAAS,OAAA,CAAQ,MAAM,GAAG,OAAO,IAAA;AACtC,EAAA,IAAI,OAAA,CAAQ,WAAW,OAAO,IAAA;AAC9B,EAAA,IAAI,IAAI,KAAK,OAAA,CAAQ,SAAS,IAAI,IAAA,CAAK,KAAA,CAAM,GAAA,EAAI,EAAG,OAAO,IAAA;AAE3D,EAAA,MAAM,UAAU,MAAM,IAAA,CAAK,WAAA,CAAY,UAAA,CAAW,QAAQ,iBAAiB,CAAA;AAC3E,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,MAAM,WAAW,MAAM,IAAA,CAAK,WAAA,CAAY,WAAA,CAAY,QAAQ,UAAU,CAAA;AACtE,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,iBAAiB,OAAA,CAAQ,eAAA;AAAA,IACzB,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,aAAA,EAAe,UAAU,KAAA,IAAS;AAAA,GACpC;AACF;AAGA,eAAsB,UAAA,CACpB,MACA,KAAA,EACe;AACf,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,IAAA,CAAK,aAAa,KAAK,CAAA;AACrD,EAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,SAAA,EAAW;AAC9C,EAAA,MAAM,QAAA,GAAA,CAAY,MAAM,IAAA,CAAK,WAAA,CAAY,gBAAgB,OAAA,CAAQ,EAAE,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA;AAChF,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAA,EAAI;AAC3B,EAAA,MAAM,WAAA,CAAY,KAAK,WAAA,EAAa,OAAA,CAAQ,IAAI,QAAA,CAAS,EAAA,CAAG,EAAE,CAAA,IAAK,IAAA,EAAM;AAAA,IACvE,IAAA,EAAM,QAAA;AAAA,IACN,SAAS,EAAC;AAAA,IACV,UAAA,EAAY,IAAI,WAAA;AAAY,GAC7B,CAAA;AACD,EAAA,MAAM,UAAU,MAAM,IAAA,CAAK,WAAA,CAAY,aAAA,CAAc,QAAQ,EAAA,EAAI;AAAA,IAC/D,MAAA,EAAQ,QAAA;AAAA,IACR,QAAA,EAAU;AAAA,GACX,CAAA;AACD,EAAA,IAAI,KAAK,KAAA,EAAO,eAAA,QAAuB,IAAA,CAAK,KAAA,CAAM,gBAAgB,OAAO,CAAA;AAC3E;AAuBA,eAAsB,eAAA,CACpB,MACA,KAAA,EACuB;AACvB,EAAA,MAAM,EAAE,WAAA,EAAa,OAAA,EAAS,KAAA,EAAO,QAAA,EAAU,OAAM,GAAI,IAAA;AACzD,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,WAAA,EAAa,MAAM,KAAK,CAAA;AACtD,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,UAAA,CAAW,aAAa,iCAAiC,CAAA;AAEjF,EAAA,IAAI,OAAA,CAAQ,WAAW,QAAA,EAAU;AAC/B,IAAA,OAAO;AAAA,MACL,WAAW,OAAA,CAAQ,EAAA;AAAA,MACnB,eAAA,EAAiB,QAAQ,eAAA,IAAmB,EAAA;AAAA,MAC5C,aAAA,EAAe;AAAA,KACjB;AAAA,EACF;AACA,EAAA,IAAI,CAAC,QAAA,CAAS,OAAA,CAAQ,MAAM,CAAA,IAAK,QAAQ,SAAA,EAAW;AAClD,IAAA,MAAM,IAAI,UAAA,CAAW,MAAA,EAAQ,2CAA2C,CAAA;AAAA,EAC1E;AACA,EAAA,MAAM,GAAA,GAAM,MAAM,GAAA,EAAI;AACtB,EAAA,IAAI,IAAI,IAAA,CAAK,OAAA,CAAQ,SAAS,IAAI,GAAA,EAAK;AACrC,IAAA,MAAM,YAAY,aAAA,CAAc,OAAA,CAAQ,IAAI,EAAE,MAAA,EAAQ,WAAW,CAAA;AACjE,IAAA,MAAM,IAAI,UAAA,CAAW,MAAA,EAAQ,gCAAgC,CAAA;AAAA,EAC/D;AAEA,EAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,UAAA,CAAW,QAAQ,iBAAiB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,UAAA,CAAW,YAAY,2BAA2B,CAAA;AAC1E,EAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,GAAA,CAAI,QAAQ,eAAe,CAAA;AACrD,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,UAAA,CAAW,YAAY,0BAA0B,CAAA;AACrE,EAAA,MAAM,QAAA,GAAW,MAAM,WAAA,CAAY,WAAA,CAAY,QAAQ,UAAU,CAAA;AAIjE,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,UAAA,IAAc,EAAC;AACxC,EAAA,MAAM,YAAA,GAAe,UAAU,SAAA,GAAY,QAAA,CAAS,UAAU,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GAAI,IAAA;AAC7E,EAAA,KAAA,MAAW,KAAA,IAAS,QAAQ,UAAA,EAAY;AACtC,IAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAQ;AAC3B,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,KAAA,CAAM,EAAE,CAAA;AACjC,IAAA,MAAM,IAAA,GAAO,MAAM,KAAA,IAAS,MAAA;AAC5B,IAAA,IAAI,CAAC,OAAO,MAAM,IAAI,WAAW,eAAA,EAAiB,CAAA,oBAAA,EAAuB,IAAI,CAAA,OAAA,CAAS,CAAA;AACtF,IAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,IAAW,YAAA;AAC/B,IAAA,IAAI,KAAA,IAAS,QAAQ,KAAA,EAAO;AAC1B,MAAA,MAAM,IAAI,UAAA,CAAW,eAAA,EAAiB,QAAQ,IAAI,CAAA,uBAAA,EAA0B,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,IACtF;AAAA,EACF;AAEA,EAAA,MAAM,QAAA,GAAA,CAAY,MAAM,WAAA,CAAY,eAAA,CAAgB,QAAQ,EAAE,CAAA,EAAG,IAAI,MAAM,CAAA;AAC3E,EAAA,MAAM,MAAA,GAAS,IAAI,WAAA,EAAY;AAC/B,EAAA,MAAM,SAAA,GAAY,MAAM,WAAA,CAAY,WAAA,EAAa,OAAA,CAAQ,IAAI,QAAA,CAAS,EAAA,CAAG,EAAE,CAAA,IAAK,IAAA,EAAM;AAAA,IACpF,IAAA,EAAM,WAAA;AAAA,IACN,OAAA,EAAS;AAAA,MACP,YAAY,KAAA,CAAM,UAAA;AAAA,MAClB,IAAI,KAAA,CAAM,EAAA;AAAA,MACV,WAAW,KAAA,CAAM;AAAA,KACnB;AAAA,IACA,UAAA,EAAY;AAAA,GACb,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ;AAAA,IACzB,WAAW,GAAA,CAAI,KAAA;AAAA,IACf,cAAc,KAAA,CAAM,YAAA;AAAA,IACpB,QAAQ,OAAA,CAAQ,UAAA;AAAA,IAChB,UAAA;AAAA,IACA,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,QAAA,EAAU,MAAA;AAAA,IACV,UAAU,KAAA,CAAM,EAAA;AAAA,IAChB,aAAA,EAAe,UAAU,KAAA,IAAS,UAAA;AAAA,IAClC,WAAW,OAAA,CAAQ,EAAA;AAAA,IACnB,UAAA,EAAY,CAAC,GAAG,QAAA,EAAU,SAAS;AAAA,GACpC,CAAA;AAED,EAAA,MAAM,eAAA,GAAkB,QAAQ,SAAA,CAAU;AAAA,IACxC,SAAS,OAAA,CAAQ,OAAA;AAAA,IACjB,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,WAAW,OAAA,CAAQ;AAAA,GACpB,CAAA;AACD,EAAA,MAAM,QAAQ,GAAA,CAAI;AAAA,IAChB,SAAA,EAAW,eAAA;AAAA,IACX,OAAO,IAAA,CAAK,SAAA;AAAA,IACZ,WAAA,EAAa;AAAA,GACd,CAAA;AAED,EAAA,MAAM,WAAA,CAAY,aAAA,CAAc,OAAA,CAAQ,EAAA,EAAI;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,QAAA,EAAU,GAAA;AAAA,IACV,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,QAAA,EAAU,MAAM,EAAA,IAAM,MAAA;AAAA,IACtB,eAAA,EAAiB,MAAM,SAAA,IAAa,MAAA;AAAA,IACpC,eAAA;AAAA,IACA,cAAc,IAAA,CAAK,YAAA;AAAA,IACnB,gBAAgB,IAAA,CAAK;AAAA,GACtB,CAAA;AAED,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAK,QAAA,EAAU;AAChC,IAAA,MAAM,YAAY,gBAAA,CAAiB;AAAA,MACjC,WAAW,OAAA,CAAQ,EAAA;AAAA,MACnB,KAAK,IAAA,CAAK,GAAA;AAAA,MACV,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,MAAM,IAAA,CAAK;AAAA,KACZ,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,OAAO,eAAA,EAAiB;AAC1B,IAAA,MAAM,MAAM,eAAA,CAAgB;AAAA,MAC1B,aAAa,OAAA,CAAQ,WAAA;AAAA,MACrB,WAAW,OAAA,CAAQ,SAAA;AAAA,MACnB,YAAY,OAAA,CAAQ,UAAA;AAAA,MACpB,YAAA,EAAc,UAAU,YAAA,IAAgB,IAAA;AAAA,MACxC,WAAW,OAAA,CAAQ,EAAA;AAAA,MACnB,eAAA;AAAA,MACA,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,QAAA,GAAW,MAAM,WAAA,CAAY,WAAA,CAAY,QAAQ,UAAU,CAAA;AACjE,EAAA,IAAI,QAAA,EAAU,YAAA,IAAgB,OAAA,CAAQ,cAAA,EAAgB;AACpD,IAAA,MAAM,KAAA,GAAQ,UAAU,KAAA,IAAS,UAAA;AACjC,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,IAAA,CAAK;AAAA,QAClB,OAAA,EAAS,OAAA;AAAA,QACT,WAAW,OAAA,CAAQ,cAAA;AAAA,QACnB,OAAA,EAAS,gBAAgB,KAAK,CAAA,CAAA;AAAA,QAC9B,IAAA,EAAM,CAAA,MAAA,EAAS,OAAA,CAAQ,aAAa,CAAA;;AAAA,iCAAA,EAAyC,KAAK,CAAA,EAAA,CAAA;AAAA,QAClF,cAAA,EAAgB,CAAA,EAAG,OAAA,CAAQ,EAAE,CAAA,QAAA,CAAA;AAAA,QAC7B,WAAA,EAAa;AAAA,UACX;AAAA,YACE,UAAU,CAAA,EAAG,KAAA,CAAM,OAAA,CAAQ,gBAAA,EAAkB,GAAG,CAAC,CAAA,IAAA,CAAA;AAAA,YACjD,SAAS,IAAA,CAAK,SAAA;AAAA,YACd,WAAA,EAAa;AAAA;AACf;AACF,OACD,CAAA;AAAA,IACH,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,SAAA,EAAW,OAAA,CAAQ,EAAA,EAAI,eAAA,EAAiB,eAAe,KAAA,EAAM;AACxE;AAQA,eAAsB,cAAA,CACpB,MACA,KAAA,EACe;AACf,EAAA,MAAM,UAAU,MAAM,OAAA,CAAQ,IAAA,CAAK,WAAA,EAAa,MAAM,KAAK,CAAA;AAC3D,EAAA,IAAI,CAAC,WAAW,CAAC,QAAA,CAAS,QAAQ,MAAM,CAAA,IAAK,QAAQ,SAAA,EAAW;AAC9D,IAAA,MAAM,IAAI,UAAA,CAAW,MAAA,EAAQ,2CAA2C,CAAA;AAAA,EAC1E;AACA,EAAA,MAAM,QAAA,GAAA,CAAY,MAAM,IAAA,CAAK,WAAA,CAAY,gBAAgB,OAAA,CAAQ,EAAE,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA;AAChF,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAA,EAAI;AAC3B,EAAA,MAAM,WAAA,CAAY,KAAK,WAAA,EAAa,OAAA,CAAQ,IAAI,QAAA,CAAS,EAAA,CAAG,EAAE,CAAA,IAAK,IAAA,EAAM;AAAA,IACvE,IAAA,EAAM,UAAA;AAAA,IACN,OAAA,EAAS,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO;AAAA,IAChC,UAAA,EAAY,IAAI,WAAA;AAAY,GAC7B,CAAA;AACD,EAAA,MAAM,UAAU,MAAM,IAAA,CAAK,WAAA,CAAY,aAAA,CAAc,QAAQ,EAAA,EAAI;AAAA,IAC/D,MAAA,EAAQ,UAAA;AAAA,IACR,UAAA,EAAY,GAAA;AAAA,IACZ,aAAA,EAAe,MAAM,MAAA,IAAU;AAAA,GAChC,CAAA;AACD,EAAA,IAAI,KAAK,KAAA,EAAO,iBAAA,QAAyB,IAAA,CAAK,KAAA,CAAM,kBAAkB,OAAO,CAAA;AAC/E;;;ACrRA,IAAM,SAAA,GAAY,CAAC,GAAA,EAAM,EAAA,EAAM,IAAM,EAAI,CAAA;AAGzC,SAAS,eAAe,OAAA,EAA6B;AACnD,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AACjC,EAAA,MAAM,MAAM,KAAA,IAAS,CAAA,GAAI,QAAQ,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,GAAI,OAAA;AACpD,EAAA,MAAM,QAAQ,IAAI,UAAA,CAAW,OAAO,IAAA,CAAK,GAAA,EAAK,QAAQ,CAAC,CAAA;AACvD,EAAA,MAAM,KAAA,GAAQ,UAAU,KAAA,CAAM,CAAC,GAAG,CAAA,KAAM,KAAA,CAAM,CAAC,CAAA,KAAM,CAAC,CAAA;AACtD,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,UAAA,CAAW,eAAA,EAAiB,gCAAgC,CAAA;AAAA,EACxE;AACA,EAAA,OAAO,KAAA;AACT;AAMO,SAAS,uBAAuB,IAAA,EAAgB;AACrD,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,WAAA,CAAsB,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC9C,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,GAAA,CAAI,MAAA;AAC5B,MAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,CAAE,YAAA,CAAa,IAAI,QAAQ,CAAA;AAEzD,MAAA,IAAI,WAAW,SAAA,EAAW;AACxB,QAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,SAAA,CAAU,KAAK,aAAa,CAAA;AACrD,QAAA,MAAM,eAAe,IAAA,EAAM,EAAE,OAAO,MAAA,EAAQ,MAAA,IAAU,MAAM,CAAA;AAC5D,QAAA,OAAO,GAAG,EAAE,EAAA,EAAI,IAAA,EAAM,QAAA,EAAU,MAAM,CAAA;AAAA,MACxC;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,GAAA,EAAK,qBAAqB,CAAA;AACvD,MAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB,IAAA,EAAM;AAAA,QACzC,KAAA;AAAA,QACA,YAAA,EAAc,cAAA,CAAe,IAAA,CAAK,YAAY,CAAA;AAAA,QAC9C,YAAY,IAAA,CAAK,UAAA;AAAA,QACjB,YAAY,IAAA,CAAK,UAAA;AAAA,QACjB,EAAA,EAAI,SAAS,GAAG,CAAA;AAAA,QAChB,SAAA,EAAW,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,YAAY;AAAA,OACxC,CAAA;AACD,MAAA,OAAO,EAAA,CAAG;AAAA,QACR,EAAA,EAAI,IAAA;AAAA,QACJ,WAAW,MAAA,CAAO,SAAA;AAAA,QAClB,eAAe,MAAA,CAAO;AAAA,OACvB,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AACF;;;ACnCO,SAAS,qBAAqB,IAAA,EAAqB;AACxD,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,WAAA,CAAsB,OAAO,IAAA,EAAM,GAAA,KAAQ;AAC9C,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,GAAA,CAAI,MAAA;AAC5B,MAAA,MAAM,IAAA,GAAO,MAAM,cAAA,CAAe,IAAA,EAAM,KAAK,CAAA;AAC7C,MAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAI,UAAA,CAAW,aAAa,gBAAgB,CAAA;AAC7D,MAAA,MAAM,MAAM,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,KAAK,eAAe,CAAA;AACvD,MAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,UAAA,CAAW,aAAa,gBAAgB,CAAA;AAC5D,MAAA,OAAO,IAAI,QAAA,CAAS,GAAA,CAAI,KAAA,EAAkC;AAAA,QACxD,MAAA,EAAQ,GAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,iBAAA;AAAA,UAChB,qBAAA,EAAuB,QAAA;AAAA,UACvB,eAAA,EAAiB,mBAAA;AAAA,UACjB,cAAA,EAAgB;AAAA;AAClB,OACD,CAAA;AAAA,IACH,CAAC;AAAA,GACH;AACF;;;ACOA,IAAM,YAAA,GAAe,YAAA;AACrB,IAAM,qBAAA,GAAwB,GAAA;AAC9B,IAAM,mBAAA,GAAsB,EAAA;AAE5B,IAAM,cAAqB,EAAE,GAAA,EAAK,sBAAM,IAAI,MAAK,EAAE;AAwD5C,SAAS,eAAkB,IAAA,EAAuC;AACvE,EAAA,MAAM,MAAA,GAAiC;AAAA,IACrC,GAAG,IAAA;AAAA,IACH,aAAA,EAAe,KAAK,aAAA,IAAiB,YAAA;AAAA,IACrC,WAAA,EAAa,KAAK,WAAA,IAAe,qBAAA;AAAA,IACjC,iBAAA,EAAmB,KAAK,iBAAA,IAAqB,mBAAA;AAAA,IAC7C,KAAA,EAAO,KAAK,KAAA,IAAS;AAAA,GACvB;AAEA,EAAA,MAAM,EAAE,aAAa,OAAA,EAAS,QAAA,EAAU,UAAU,KAAA,EAAO,KAAA,EAAO,SAAQ,GAAI,MAAA;AAC5E,EAAA,MAAM,WAAW,EAAE,WAAA,EAAa,OAAA,EAAS,KAAA,EAAO,UAAU,KAAA,EAAM;AAEhE,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,eAAA;AAAA,IAEA,cAAA,EAAgB,CAAC,KAAA,KAAU,cAAA,CAAe,aAAa,KAAK,CAAA;AAAA,IAC5D,UAAA,EAAY,CAAC,KAAA,KAAU,UAAA,CAAW,EAAE,WAAA,EAAa,OAAA,IAAW,KAAK,CAAA;AAAA,IACjE,cAAA,EAAgB,CAAC,IAAA,KACf,cAAA;AAAA,MACE;AAAA,QACE,WAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA,KAAA;AAAA,QACA,OAAA;AAAA,QACA,mBAAmB,MAAA,CAAO;AAAA,OAC5B;AAAA,MACA;AAAA,KACF;AAAA,IACF,cAAA,EAAgB,CAAC,KAAA,KAAU,cAAA,CAAe,EAAE,aAAa,OAAA,EAAS,KAAA,EAAO,KAAA,EAAM,EAAG,KAAK,CAAA;AAAA,IAEvF,cAAA,EAAgB,CAAC,KAAA,KAAU,cAAA,CAAe,EAAE,WAAA,EAAa,KAAA,IAAS,KAAK,CAAA;AAAA,IACvE,UAAA,EAAY,CAAC,KAAA,KAAU,UAAA,CAAW,EAAE,WAAA,EAAa,KAAA,EAAO,KAAA,EAAM,EAAG,KAAK,CAAA;AAAA,IACtE,eAAA,EAAiB,CAAC,KAAA,KAAU,eAAA,CAAgB,UAAU,KAAK,CAAA;AAAA,IAC3D,cAAA,EAAgB,CAAC,KAAA,KAAU,cAAA,CAAe,EAAE,WAAA,EAAa,KAAA,EAAO,KAAA,EAAM,EAAG,KAAK,CAAA;AAAA,IAE9E,oBAAA,EAAsB,CAAC,IAAA,KAAS,WAAA,CAAY,qBAAqB,IAAI,CAAA;AAAA,IACrE,gBAAA,EAAkB,CAAC,UAAA,KAAe,gBAAA,CAAiB,EAAE,WAAA,EAAa,QAAA,IAAY,UAAU,CAAA;AAAA,IACxF,aAAA,EAAe,CAAC,UAAA,KAAe,WAAA,CAAY,cAAc,UAAU,CAAA;AAAA,IACnE,aAAA,EAAe,CAAC,UAAA,KAAe,WAAA,CAAY,cAAc,UAAU,CAAA;AAAA,IACnE,YAAY,CAAC,OAAA,EAAS,UAAU,WAAA,CAAY,UAAA,CAAW,SAAS,KAAK,CAAA;AAAA,IACrE,mBAAA,EAAqB,CAAC,MAAA,KAAW,WAAA,CAAY,oBAAoB,MAAM,CAAA;AAAA,IAEvE,MAAA,EAAQ;AAAA,MACN,WAAW,oBAAA,CAAqB,EAAE,WAAA,EAAa,OAAA,EAAS,OAAO,CAAA;AAAA,MAC/D,WAAA,EAAa,uBAAuB,QAAQ;AAAA;AAC9C,GACF;AACF;;;ACjJO,SAAS,qBAAqB,KAAA,EAA8C;AACjF,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,IAAA,EAAM,CAAC,CAAC,CAAC,CAAA;AACjD,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,GAAA,EAAK,CAAC,IAAA,KAAiB,GAAA,CAAI,IAAI,IAAI;AAAA,GACrC;AACF","file":"index.cjs","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\n\n/**\n * No-login signer token. We follow the share-link convention from the host\n * apps: generate a random token, return the cleartext exactly once (it goes\n * only into the `/sign/<token>` URL), and persist nothing but its sha256. A\n * leaked database never yields a usable link.\n */\nexport interface SigningToken {\n /** Goes into the signer URL only — never stored. */\n cleartext: string;\n /** sha256(cleartext) — the value stored in `SigningRequest.tokenHash`. */\n tokenHash: string;\n}\n\n/** sha256 of a string or bytes, lowercase hex (64 chars). */\nexport function sha256Hex(input: string | Uint8Array): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\n/** A fresh signing token. `bytes` of entropy, base64url-encoded cleartext. */\nexport function newSigningToken(bytes = 32): SigningToken {\n const cleartext = randomBytes(bytes).toString(\"base64url\");\n return { cleartext, tokenHash: sha256Hex(cleartext) };\n}\n","import { sha256Hex } from \"./tokens\";\n\n/**\n * Tamper-evident audit log (Level-1 seal). Every signing request accumulates an\n * append-only chain of events (CREATED → NOTIFIED → VIEWED → CONSENTED → SIGNED\n * → SEALED). Each link's `hash` covers the previous hash plus this link's\n * contents, so altering any earlier event invalidates every hash after it. The\n * chain is rendered onto the sealed PDF's certificate page and re-checkable with\n * `verifyChain`.\n */\n\nexport interface AuditEventInput {\n type: string;\n payload: Record<string, unknown>;\n /** ISO instant; passed in (never `Date.now()`) so seals are reproducible. */\n occurredAt: string;\n}\n\nexport interface AuditLink extends AuditEventInput {\n seq: number;\n prevHash: string | null;\n hash: string;\n}\n\n/** Deterministic JSON: object keys sorted, `undefined` normalized to null. */\nexport function canonicalize(value: unknown): string {\n if (value === undefined) return \"null\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalize).join(\",\")}]`;\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`).join(\",\")}}`;\n}\n\n/** The hash bound into a link: sha256(prevHash | seq | type | occurredAt | payload). */\nexport function linkHash(\n prevHash: string | null,\n seq: number,\n type: string,\n occurredAt: string,\n payload: unknown,\n): string {\n return sha256Hex(\n `${prevHash ?? \"\"}|${seq}|${type}|${occurredAt}|${canonicalize(payload)}`,\n );\n}\n\n/** Append one event to a chain (or start it when `prev` is null). */\nexport function appendEvent(\n prev: AuditLink | null,\n input: AuditEventInput,\n): AuditLink {\n const seq = prev ? prev.seq + 1 : 0;\n const prevHash = prev ? prev.hash : null;\n const hash = linkHash(prevHash, seq, input.type, input.occurredAt, input.payload);\n return { ...input, seq, prevHash, hash };\n}\n\n/** Fold a list of events into a verified chain. */\nexport function buildChain(inputs: AuditEventInput[]): AuditLink[] {\n const out: AuditLink[] = [];\n let prev: AuditLink | null = null;\n for (const input of inputs) {\n prev = appendEvent(prev, input);\n out.push(prev);\n }\n return out;\n}\n\n/** Recompute every hash; `brokenAt` is the seq of the first bad link, else null. */\nexport function verifyChain(links: AuditLink[]): {\n ok: boolean;\n brokenAt: number | null;\n} {\n let prev: AuditLink | null = null;\n for (const link of links) {\n const expectedSeq = prev ? prev.seq + 1 : 0;\n const expectedPrev = prev ? prev.hash : null;\n const expectedHash = linkHash(\n expectedPrev,\n link.seq,\n link.type,\n link.occurredAt,\n link.payload,\n );\n if (\n link.seq !== expectedSeq ||\n link.prevHash !== expectedPrev ||\n link.hash !== expectedHash\n ) {\n return { ok: false, brokenAt: link.seq };\n }\n prev = link;\n }\n return { ok: true, brokenAt: null };\n}\n","export type EsignErrorCode =\n | \"UNAUTHENTICATED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"INVALID_INPUT\"\n | \"CONFLICT\"\n | \"GONE\"\n | \"RATE_LIMITED\"\n | \"PAYLOAD_TOO_LARGE\"\n | \"STORAGE_ERROR\"\n | \"INTERNAL\";\n\nexport class EsignError extends Error {\n readonly code: EsignErrorCode;\n readonly details?: unknown;\n readonly status: number;\n\n constructor(code: EsignErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = \"EsignError\";\n this.code = code;\n this.details = details;\n this.status = statusFor(code);\n }\n}\n\nfunction statusFor(code: EsignErrorCode): number {\n switch (code) {\n case \"UNAUTHENTICATED\":\n return 401;\n case \"FORBIDDEN\":\n return 403;\n case \"NOT_FOUND\":\n return 404;\n case \"INVALID_INPUT\":\n return 422;\n case \"CONFLICT\":\n return 409;\n case \"GONE\":\n return 410;\n case \"RATE_LIMITED\":\n return 429;\n case \"PAYLOAD_TOO_LARGE\":\n return 413;\n case \"STORAGE_ERROR\":\n return 502;\n case \"INTERNAL\":\n default:\n return 500;\n }\n}\n\nexport function toErrorResponse(err: unknown): Response {\n if (err instanceof EsignError) {\n return Response.json(\n { error: { code: err.code, message: err.message, details: err.details } },\n { status: err.status },\n );\n }\n console.error(\"[esign] unexpected error\", err);\n return Response.json(\n { error: { code: \"INTERNAL\", message: \"Unexpected error.\" } },\n { status: 500 },\n );\n}\n","// Field-type + date-format primitives shared by the server (schema, seal) and\n// the UI (designer, signer, viewer). Pure — no deps — so importing it into the\n// browser `/ui` bundle pulls in nothing else.\n\n/** What a placed field captures: a drawn signature or a picked date. */\nexport type FieldType = \"signature\" | \"date\";\n\n/**\n * How a filled date renders into the sealed PDF — the creator picks one per date\n * field. Pure string formats (no locale/timezone surprises).\n */\nexport type DateFormat =\n | \"DD/MM/YYYY\" // 02/10/2026\n | \"MM/DD/YYYY\" // 10/02/2026\n | \"YYYY-MM-DD\" // 2026-10-02\n | \"D MMM YYYY\" // 2 Oct 2026\n | \"Do MMM YYYY\" // 2nd Oct 2026\n | \"Do MMMM YYYY\" // 2nd October 2026\n | \"MMMM D, YYYY\"; // October 2, 2026\n\nexport const DATE_FORMATS: readonly DateFormat[] = [\n \"DD/MM/YYYY\",\n \"MM/DD/YYYY\",\n \"YYYY-MM-DD\",\n \"D MMM YYYY\",\n \"Do MMM YYYY\",\n \"Do MMMM YYYY\",\n \"MMMM D, YYYY\",\n];\nexport const DEFAULT_DATE_FORMAT: DateFormat = \"Do MMMM YYYY\";\n\nconst MONTHS_SHORT = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\nconst MONTHS_LONG = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\nfunction ordinal(n: number): string {\n const s = [\"th\", \"st\", \"nd\", \"rd\"];\n const v = n % 100;\n return `${n}${s[(v - 20) % 10] ?? s[v] ?? s[0]}`;\n}\n\n/** Render an ISO `yyyy-mm-dd` date in the chosen format. Parses the parts directly. */\nexport function formatPickedDate(iso: string, format: DateFormat): string {\n const [y, m, d] = iso.split(\"-\").map(Number);\n if (!y || !m || !d) return iso;\n const dd = String(d).padStart(2, \"0\");\n const mm = String(m).padStart(2, \"0\");\n switch (format) {\n case \"DD/MM/YYYY\":\n return `${dd}/${mm}/${y}`;\n case \"MM/DD/YYYY\":\n return `${mm}/${dd}/${y}`;\n case \"YYYY-MM-DD\":\n return `${y}-${mm}-${dd}`;\n case \"D MMM YYYY\":\n return `${d} ${MONTHS_SHORT[m - 1]} ${y}`;\n case \"Do MMM YYYY\":\n return `${ordinal(d)} ${MONTHS_SHORT[m - 1]} ${y}`;\n case \"Do MMMM YYYY\":\n return `${ordinal(d)} ${MONTHS_LONG[m - 1]} ${y}`;\n case \"MMMM D, YYYY\":\n return `${MONTHS_LONG[m - 1]} ${d}, ${y}`;\n }\n}\n\n/** A human label for each format, for pickers. */\nexport const DATE_FORMAT_LABELS: Record<DateFormat, string> = {\n \"DD/MM/YYYY\": \"02/10/2026\",\n \"MM/DD/YYYY\": \"10/02/2026\",\n \"YYYY-MM-DD\": \"2026-10-02\",\n \"D MMM YYYY\": \"2 Oct 2026\",\n \"Do MMM YYYY\": \"2nd Oct 2026\",\n \"Do MMMM YYYY\": \"2nd October 2026\",\n \"MMMM D, YYYY\": \"October 2, 2026\",\n};\n","import { z } from \"zod\";\n\nimport {\n DATE_FORMATS,\n DATE_FORMAT_LABELS,\n DEFAULT_DATE_FORMAT,\n formatPickedDate,\n type DateFormat,\n type FieldType,\n} from \"../shared/fields\";\nimport type { EsignStatus } from \"./flow\";\n\n// ---------------------------------------------------------------------------\n// Channels\n// ---------------------------------------------------------------------------\n\n// Mirrors the host Channel enum (dhm-estates: EMAIL/TELEGRAM/SMS/WHATSAPP). A\n// host only offers the channels its NotifierPort.configuredChannels() reports,\n// so listing all four here costs nothing when some aren't wired yet.\nexport type EsignChannel = \"EMAIL\" | \"TELEGRAM\" | \"SMS\" | \"WHATSAPP\";\nexport const ESIGN_CHANNELS: readonly EsignChannel[] = [\n \"EMAIL\",\n \"TELEGRAM\",\n \"SMS\",\n \"WHATSAPP\",\n];\nexport const esignChannelSchema = z.enum([\"EMAIL\", \"TELEGRAM\", \"SMS\", \"WHATSAPP\"]);\n\n// ---------------------------------------------------------------------------\n// Signature placement — normalized 0..1 fractions of the target page, origin\n// top-left (the designer's coordinate space). Converted to pdf-lib's\n// bottom-left space at seal time using the page's real width/height.\n// ---------------------------------------------------------------------------\n\nexport interface Placement {\n page: number; // 1-based\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nconst unit = z.number().min(0).max(1);\nexport const placementSchema = z\n .object({\n page: z.number().int().min(1),\n x: unit,\n y: unit,\n w: z.number().min(0.01).max(1),\n h: z.number().min(0.01).max(1),\n })\n .strict();\n\nexport { DATE_FORMATS, DATE_FORMAT_LABELS, DEFAULT_DATE_FORMAT, formatPickedDate };\nexport type { DateFormat, FieldType };\n\n/**\n * A named placed field — a placement with an id, label and type. A signature\n * field is stamped with the signer's signature; a date field is stamped with the\n * date the signer picks, rendered in `dateFormat` and bounded below by `minDate`\n * (default: the document's creation date). The signer sees \"Sign here\" / a date\n * picker; labels organize the fields in the designer.\n */\nexport interface DocumentField extends Placement {\n id: string;\n label: string;\n type: FieldType;\n /** Date fields only: how the picked date renders into the PDF. */\n dateFormat?: DateFormat;\n /** Date fields only: earliest selectable date (ISO `yyyy-mm-dd`); null = no floor. */\n minDate?: string | null;\n}\n\n/** @deprecated use {@link DocumentField}; kept as an alias for back-compat. */\nexport type SignatureField = DocumentField;\n\nconst isoDate = z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/);\nexport const documentFieldSchema = placementSchema\n .extend({\n id: z.string().min(1).max(64),\n label: z.string().trim().max(80),\n type: z.enum([\"signature\", \"date\"]).default(\"signature\"),\n dateFormat: z.enum(DATE_FORMATS as [DateFormat, ...DateFormat[]]).optional(),\n minDate: isoDate.nullable().optional(),\n })\n .strict();\n/** @deprecated use {@link documentFieldSchema}. */\nexport const signatureFieldSchema = documentFieldSchema;\nexport const placementsSchema = z\n .array(documentFieldSchema)\n .min(1)\n .max(20)\n .refine((fields) => fields.some((f) => f.type === \"signature\"), {\n message: \"A document needs at least one signature field.\",\n });\n\n// ---------------------------------------------------------------------------\n// Subjects + targeting\n// ---------------------------------------------------------------------------\n\n/** A resolved recipient — the only thing the fan-out needs. subjectId = the host's profileId. */\nexport interface Recipient {\n name: string;\n email?: string | null;\n /** Phone for SMS (and WhatsApp when `whatsapp` is absent). */\n phone?: string | null;\n whatsapp?: string | null;\n subjectType: string;\n subjectId: string;\n /** Snapshot of the targeted classification, persisted as SigningRequest.subjectGroup. */\n group?: string | null;\n}\n\n/** Resolve the address to use for a channel from a recipient's contacts. */\nexport function addressFor(\n recipient: Recipient,\n channel: EsignChannel,\n): string | null {\n switch (channel) {\n case \"EMAIL\":\n return recipient.email ?? null;\n case \"SMS\":\n return recipient.phone ?? null;\n case \"WHATSAPP\":\n return recipient.whatsapp ?? recipient.phone ?? null;\n case \"TELEGRAM\":\n return null; // host wires a Telegram address resolver when that channel lands\n }\n}\n\n/** A subject row rendered by the targeting picker. */\nexport interface SubjectSummary {\n subjectType: string;\n subjectId: string;\n label: string;\n sublabel?: string;\n group?: string | null;\n groupLabel?: string | null;\n eligible: boolean;\n ineligibleReason?: string;\n}\n\n/** A subject that could not be sent to at resolve time. */\nexport interface SkippedSubject {\n subjectType: string;\n subjectId: string;\n label: string;\n reason: string;\n}\n\n/** A declarative filter facet the picker renders as a control. */\nexport interface SubjectFilterField {\n key: string;\n label: string;\n kind: \"enum\" | \"boolean\" | \"text\" | \"scope\";\n options?: { value: string; label: string }[];\n}\n\nexport type SubjectFilter = Record<\n string,\n string | boolean | string[] | undefined\n>;\n\n/**\n * How a target is expressed. \"all\" sends to the whole group (optionally a\n * classification + filters); \"ids\" sends to an explicit subset.\n */\nexport type SubjectSelection =\n | { mode: \"all\"; type: string; group?: string; filter?: SubjectFilter }\n | { mode: \"ids\"; type: string; subjectIds: string[] };\n\nexport const subjectSelectionSchema: z.ZodType<SubjectSelection> = z.union([\n z\n .object({\n mode: z.literal(\"all\"),\n type: z.string().min(1),\n group: z.string().min(1).optional(),\n filter: z.record(z.unknown()).optional() as z.ZodType<\n SubjectFilter | undefined\n >,\n })\n .strict(),\n z\n .object({\n mode: z.literal(\"ids\"),\n type: z.string().min(1),\n subjectIds: z.array(z.string().min(1)).min(1),\n })\n .strict(),\n]);\n\n/** Restrict a resend to a subset of the live group, diffed against existing requests. */\nexport type ResendPolicy = \"all\" | \"outstanding\" | \"olderVersion\" | \"uncovered\";\n\n/** Whether a green-check requires the current version or any version. */\nexport type VersionPolicy = \"current\" | \"any\";\n\n// ---------------------------------------------------------------------------\n// Read DTOs\n// ---------------------------------------------------------------------------\n\nexport interface SigningDocumentDTO {\n id: string;\n scopeId: string | null;\n documentType: string | null;\n title: string;\n audience: SubjectSelection | null;\n currentVersionId: string | null;\n createdById: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SigningDocumentVersionDTO {\n id: string;\n documentId: string;\n version: number;\n sourceObjectKey: string;\n sourceSha256: string;\n placements: SignatureField[];\n changeNote: string | null;\n createdById: string | null;\n createdAt: string;\n}\n\nexport interface SigningCampaignDTO {\n id: string;\n documentId: string;\n documentVersionId: string;\n scopeId: string | null;\n note: string | null;\n emailReceipt: boolean;\n targeting: SubjectSelection;\n expiresAt: string;\n createdById: string | null;\n createdAt: string;\n}\n\nexport interface SigningRequestDTO {\n id: string;\n campaignId: string;\n documentId: string;\n documentVersionId: string;\n scopeId: string | null;\n subjectType: string;\n subjectId: string;\n subjectGroup: string | null;\n recipientName: string;\n recipientEmail: string | null;\n recipientWhatsapp: string | null;\n channels: EsignChannel[];\n status: EsignStatus;\n viewedAt: string | null;\n signedAt: string | null;\n declinedAt: string | null;\n expiresAt: string;\n revokedAt: string | null;\n sealedObjectKey: string | null;\n sealedSha256: string | null;\n createdAt: string;\n}\n\nexport interface SigningAuditEventDTO {\n id: string;\n requestId: string;\n seq: number;\n type: string;\n payload: unknown;\n prevHash: string | null;\n hash: string;\n occurredAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Green-check + stats result shapes\n// ---------------------------------------------------------------------------\n\nexport type SubjectSigningState =\n | \"NONE\"\n | \"PENDING\"\n | \"VIEWED\"\n | \"SIGNED\"\n | \"DECLINED\"\n | \"NEEDS_RESIGN\";\n\nexport interface SubjectSigningStatus {\n state: SubjectSigningState;\n signedAt: string | null;\n signedVersion: number | null;\n requestId: string | null;\n sealedObjectKey: string | null;\n}\n\nexport type StatusCountMap = Record<EsignStatus, number>;\n\nexport interface OutstandingRequest {\n id: string;\n campaignId: string;\n documentId: string;\n subjectType: string;\n subjectId: string;\n recipientName: string;\n channels: EsignChannel[];\n status: Extract<EsignStatus, \"PENDING\" | \"VIEWED\">;\n viewedAt: string | null;\n createdAt: string;\n expiresAt: string;\n}\n\nexport interface GroupBreakdown {\n group: string | null;\n counts: StatusCountMap;\n total: number;\n}\n\nexport interface CampaignStatsRow {\n campaignId: string;\n counts: StatusCountMap;\n total: number;\n viewedNotSigned: number;\n completionRate: number;\n avgTimeToSignMs: number | null;\n byGroup: GroupBreakdown[];\n outstanding: OutstandingRequest[];\n}\n\nexport interface DocumentStatsRow {\n documentId: string;\n counts: StatusCountMap;\n total: number;\n completionRate: number;\n byGroup: GroupBreakdown[];\n bySubjectType: { subjectType: string; counts: StatusCountMap; total: number }[];\n}\n\nexport interface ScopeStatsRow {\n campaignsSent: number;\n requestsSent: number;\n counts: StatusCountMap;\n completionRate: number;\n bySubjectType: { subjectType: string; counts: StatusCountMap; total: number }[];\n oldestOutstanding: OutstandingRequest[];\n}\n\nexport interface StatsRange {\n from?: Date;\n to?: Date;\n}\n\n/** documentCoverage() result — re-derived from the live group every call. */\nexport interface CoverageReport {\n documentId: string;\n totalNow: number;\n signed: number;\n outstanding: number;\n needsResign: number;\n uncovered: SubjectSummary[];\n departed: { subjectType: string; subjectId: string }[];\n}\n\n// ---------------------------------------------------------------------------\n// Signer-side request bodies\n// ---------------------------------------------------------------------------\n\n/**\n * The signer submit: a drawn/typed signature PNG + the picked date for each date\n * field, keyed by field id (ISO `yyyy-mm-dd`).\n */\nexport const submitSignatureSchema = z\n .object({\n signaturePng: z.string().min(1).max(1_500_000), // ~1MB cap on the data URL\n signerName: z.string().trim().min(1).max(200),\n consent: z.literal(true),\n dateValues: z.record(z.string().min(1).max(64), isoDate).optional(),\n })\n .strict();\nexport type SubmitSignatureInput = z.infer<typeof submitSignatureSchema>;\n\nexport const declineSchema = z\n .object({ reason: z.string().trim().max(500).optional() })\n .strict();\nexport type DeclineInput = z.infer<typeof declineSchema>;\n","import { randomBytes } from \"node:crypto\";\n\n// 62-char URL-safe alphabet. 16 chars ≈ 95 bits of entropy — ample for row ids.\nconst ALPHABET =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\n/**\n * A 16-char unique id, matching the host `@db.VarChar(16)` convention. The\n * package generates ids in code (the Prisma fragment carries no `@default`), so\n * every esign-owned row gets a uid the same way across dhm-estates / flc-missions\n * / flc-hr. Rejection sampling keeps the distribution uniform (no modulo bias).\n */\nexport function uid(size = 16): string {\n let out = \"\";\n while (out.length < size) {\n for (const byte of randomBytes(size)) {\n if (byte < 248) {\n // 248 = floor(256 / 62) * 62 — discard the biased tail.\n out += ALPHABET[byte % 62];\n if (out.length === size) break;\n }\n }\n }\n return out;\n}\n","import { appendEvent, type AuditEventInput, type AuditLink } from \"./audit-chain\";\nimport { EsignError } from \"./errors\";\nimport type {\n Clock,\n NewRequestRow,\n NotifierPort,\n PersistencePort,\n SubjectsPort,\n} from \"./ports\";\nimport { newSigningToken } from \"./tokens\";\nimport {\n addressFor,\n type EsignChannel,\n type ResendPolicy,\n type SkippedSubject,\n type SubjectSelection,\n} from \"./types\";\nimport { uid } from \"./uid\";\n\n/**\n * Persist one audit link and return it, so the caller can thread the chain tip\n * into the next event. Shared by the fan-out here and the signer submit handler.\n */\nexport async function recordEvent(\n persistence: PersistencePort,\n requestId: string,\n prev: AuditLink | null,\n input: AuditEventInput,\n): Promise<AuditLink> {\n const link = appendEvent(prev, input);\n await persistence.appendAuditEvent({\n requestId,\n seq: link.seq,\n type: link.type,\n payload: link.payload,\n prevHash: link.prevHash,\n hash: link.hash,\n });\n return link;\n}\n\nexport interface ChannelContent {\n subject: string;\n body: string;\n}\n\nexport type CampaignContentBuilder = (ctx: {\n documentTitle: string;\n note: string | null;\n recipientName: string;\n}) => ChannelContent;\n\nconst defaultContent: CampaignContentBuilder = ({\n documentTitle,\n note,\n recipientName,\n}) => ({\n subject: `Please sign: ${documentTitle}`,\n body: [\n `Hello ${recipientName},`,\n note ?? `You have a document to review and sign: ${documentTitle}.`,\n \"Open the secure link to sign — no account or login needed.\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n});\n\nexport interface CreateCampaignDeps {\n persistence: PersistencePort;\n subjects: SubjectsPort;\n notifier: NotifierPort;\n clock: Clock;\n baseUrl: string;\n defaultExpiryDays: number;\n content?: CampaignContentBuilder;\n}\n\nexport interface CreateCampaignArgs {\n /** Opaque host scope (estate id / country id / null) — already authorized by the route. */\n scopeId?: string | null;\n documentVersionId: string;\n selection: SubjectSelection;\n channels: EsignChannel[];\n note?: string | null;\n emailReceipt?: boolean;\n expiresInDays?: number;\n resendPolicy?: ResendPolicy;\n createdById?: string | null;\n}\n\nexport interface CreateCampaignResult {\n /** null when the (filtered) target group resolved to nobody — e.g. \"uncovered\" with no new subjects. */\n campaignId: string | null;\n sent: number;\n skipped: SkippedSubject[];\n}\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Send a version to a target group. Resolves recipients server-side via the\n * SubjectsPort, applies the resend policy by diffing against existing requests,\n * mints no-login tokens, creates the request rows, and fans out one notification\n * per recipient × channel — recording a CREATED + per-send NOTIFIED audit chain.\n */\nexport async function createCampaign(\n deps: CreateCampaignDeps,\n args: CreateCampaignArgs,\n): Promise<CreateCampaignResult> {\n const { persistence, subjects, notifier, clock, baseUrl, defaultExpiryDays } = deps;\n const content = deps.content ?? defaultContent;\n\n if (args.channels.length === 0) {\n throw new EsignError(\"INVALID_INPUT\", \"Choose at least one channel.\");\n }\n\n const version = await persistence.getVersion(args.documentVersionId);\n if (!version) throw new EsignError(\"NOT_FOUND\", \"Document version not found.\");\n const document = await persistence.getDocument(version.documentId);\n if (!document) throw new EsignError(\"NOT_FOUND\", \"Document not found.\");\n\n const descriptor = subjects.get(args.selection.type);\n if (!descriptor) {\n throw new EsignError(\n \"INVALID_INPUT\",\n `Unknown subject type: ${args.selection.type}.`,\n );\n }\n\n const configured = new Set(notifier.configuredChannels());\n const channels = args.channels.filter((c) => configured.has(c));\n if (channels.length === 0) {\n throw new EsignError(\n \"INVALID_INPUT\",\n \"None of the chosen channels are configured.\",\n );\n }\n\n const scopeId = args.scopeId ?? document.scopeId;\n const resolved = await descriptor.resolveRecipients({\n scopeId,\n selection: args.selection,\n channels,\n });\n const skipped = resolved.skipped;\n let recipients = resolved.recipients;\n\n // Resend policy: keep only the slice the policy targets, diffed against the\n // document's existing requests.\n if (args.resendPolicy && args.resendPolicy !== \"all\") {\n const summaries = await persistence.requestSummaryBySubject(version.documentId);\n const byId = new Map(summaries.map((s) => [s.subjectId, s]));\n const vNum = version.version;\n recipients = recipients.filter((r) => {\n const s = byId.get(r.subjectId);\n switch (args.resendPolicy) {\n case \"uncovered\":\n return !s;\n case \"outstanding\":\n return !(s && s.status === \"SIGNED\" && s.version >= vNum);\n case \"olderVersion\":\n return Boolean(s && s.status === \"SIGNED\" && s.version < vNum);\n default:\n return true;\n }\n });\n }\n\n if (recipients.length === 0) return { campaignId: null, sent: 0, skipped };\n\n const now = clock.now();\n const expiresAt = new Date(\n now.getTime() + (args.expiresInDays ?? defaultExpiryDays) * DAY_MS,\n );\n\n const campaign = await persistence.createCampaign({\n documentId: version.documentId,\n documentVersionId: version.id,\n scopeId,\n note: args.note ?? null,\n emailReceipt: args.emailReceipt ?? false,\n targeting: args.selection,\n expiresAt,\n createdById: args.createdById ?? null,\n });\n\n const targetedGroup =\n args.selection.mode === \"all\" ? (args.selection.group ?? null) : null;\n\n // Engine mints request ids (createRequests returns void), keeping the cleartext\n // token + recipient alongside each row for the fan-out.\n const prepared = recipients.map((r) => {\n const token = newSigningToken();\n const row: NewRequestRow = {\n id: uid(),\n campaignId: campaign.id,\n documentId: version.documentId,\n documentVersionId: version.id,\n scopeId,\n subjectType: r.subjectType,\n subjectId: r.subjectId,\n subjectGroup: targetedGroup ?? r.group ?? null,\n recipientName: r.name,\n recipientEmail: r.email ?? null,\n recipientWhatsapp: r.whatsapp ?? null,\n channels,\n tokenHash: token.tokenHash,\n expiresAt,\n };\n return { row, cleartext: token.cleartext, recipient: r };\n });\n\n await persistence.createRequests(prepared.map((p) => p.row));\n\n const base = baseUrl.replace(/\\/$/, \"\");\n const nowIso = now.toISOString();\n let sent = 0;\n\n for (const { row, cleartext, recipient } of prepared) {\n let prev = await recordEvent(persistence, row.id, null, {\n type: \"CREATED\",\n payload: {\n subjectType: row.subjectType,\n subjectId: row.subjectId,\n by: args.createdById ?? null,\n },\n occurredAt: nowIso,\n });\n\n const actionUrl = `${base}/sign/${cleartext}`;\n const c = content({\n documentTitle: document.title,\n note: args.note ?? null,\n recipientName: recipient.name,\n });\n\n for (const channel of channels) {\n const address = addressFor(recipient, channel);\n if (!address) continue;\n let ok = false;\n let error: string | null = null;\n try {\n const result = await notifier.send({\n channel,\n recipient: address,\n subject: c.subject,\n body: c.body,\n actionUrl,\n idempotencyKey: row.id,\n });\n ok = result.ok;\n error = result.error ?? null;\n } catch (err) {\n ok = false;\n error = err instanceof Error ? err.message : String(err);\n }\n prev = await recordEvent(persistence, row.id, prev, {\n type: \"NOTIFIED\",\n payload: { channel, ok, error },\n occurredAt: nowIso,\n });\n }\n sent++;\n }\n\n return { campaignId: campaign.id, sent, skipped };\n}\n","import { EsignError } from \"./errors\";\nimport type { PersistencePort, SubjectsPort } from \"./ports\";\nimport type { CoverageReport, SubjectSummary } from \"./types\";\n\nexport interface CoverageDeps {\n persistence: PersistencePort;\n subjects: SubjectsPort;\n}\n\n/**\n * Re-derive a document's coverage from the LIVE group (via the stored audience\n * selection) so subjects added after a send are detected. Buckets every subject\n * into signed / outstanding / needs-resign / uncovered / departed.\n */\nexport async function documentCoverage(\n deps: CoverageDeps,\n documentId: string,\n): Promise<CoverageReport> {\n const { persistence, subjects } = deps;\n const doc = await persistence.getDocument(documentId);\n if (!doc) throw new EsignError(\"NOT_FOUND\", \"Document not found.\");\n\n const summaries = await persistence.requestSummaryBySubject(documentId);\n const summaryIds = new Set(summaries.map((s) => s.subjectId));\n\n let currentNumber = 0;\n if (doc.currentVersionId) {\n const v = await persistence.getVersion(doc.currentVersionId);\n currentNumber = v?.version ?? 0;\n }\n\n let signed = 0;\n let outstanding = 0;\n let needsResign = 0;\n for (const s of summaries) {\n if (s.status === \"SIGNED\") {\n if (s.version >= currentNumber) signed++;\n else needsResign++;\n } else if (s.status === \"PENDING\" || s.status === \"VIEWED\") {\n outstanding++;\n }\n }\n\n // Live group (labelled) from the audience selection.\n let live: SubjectSummary[] = [];\n if (doc.audience) {\n const descriptor = subjects.get(doc.audience.type);\n if (descriptor) {\n const page = await descriptor.listSubjects({\n scopeId: doc.scopeId,\n group: doc.audience.mode === \"all\" ? doc.audience.group : undefined,\n filter: doc.audience.mode === \"all\" ? doc.audience.filter : undefined,\n limit: 1000,\n });\n live = page.subjects;\n }\n }\n const liveIds = new Set(live.map((s) => s.subjectId));\n\n const uncovered = live.filter((s) => !summaryIds.has(s.subjectId));\n const departed = doc.audience\n ? summaries\n .filter((s) => !liveIds.has(s.subjectId))\n .map((s) => ({ subjectType: doc.audience!.type, subjectId: s.subjectId }))\n : [];\n\n return {\n documentId,\n totalNow: live.length,\n signed,\n outstanding,\n needsResign,\n uncovered,\n departed,\n };\n}\n","import type {\n Clock,\n DocumentDeletionContext,\n HooksPort,\n PersistencePort,\n StoragePort,\n} from \"./ports\";\n\nexport type DeleteMode = \"soft\" | \"purge\";\n\nexport interface DeleteDocumentInput {\n documentId: string;\n /**\n * \"soft\" (default) archives reversibly — hides the document + campaigns, revokes\n * live links, keeps the sealed PDFs + audit trail. \"purge\" permanently removes\n * all rows and the source/sealed objects, and is refused once anything is signed.\n */\n mode?: DeleteMode;\n}\n\nexport type DeleteDocumentResult =\n | { ok: true; mode: DeleteMode; documentId: string; objectsPurged: number }\n | { ok: false; reason: \"not_found\" | \"has_signatures\" };\n\nexport interface DeleteDocumentDeps {\n persistence: PersistencePort;\n storage: StoragePort;\n clock: Clock;\n hooks?: HooksPort;\n}\n\n/**\n * Delete a logical document and everything under it. Soft by default (reversible,\n * preserves signed evidence); purge permanently removes rows + storage objects but\n * is refused when any request is SIGNED. Either way the affected subjects are\n * reported through {@link HooksPort.onDocumentDeleted} so the host can react\n * (milestone-grid retraction lives in the host, never in this package).\n */\nexport async function deleteDocument(\n deps: DeleteDocumentDeps,\n input: DeleteDocumentInput,\n): Promise<DeleteDocumentResult> {\n const mode: DeleteMode = input.mode ?? \"soft\";\n const ctx = await deps.persistence.getDocumentDeletionContext(input.documentId);\n if (!ctx) return { ok: false, reason: \"not_found\" };\n\n // A signed document is legal evidence — never hard-delete it.\n if (mode === \"purge\" && ctx.signedCount > 0) {\n return { ok: false, reason: \"has_signatures\" };\n }\n\n if (mode === \"purge\") {\n // DB first (transactional source of truth); storage cleanup is best-effort\n // after. An orphaned object is harmless and sweepable; a row pointing at a\n // deleted object is not — so we never delete objects before the rows.\n await deps.persistence.hardDeleteDocument(input.documentId);\n const keys = [...ctx.sourceKeys, ...ctx.sealedKeys];\n for (const key of keys) {\n await deps.storage.delete(key).catch(() => undefined);\n }\n await emitDeleted(deps.hooks, ctx, \"purge\");\n return { ok: true, mode: \"purge\", documentId: input.documentId, objectsPurged: keys.length };\n }\n\n await deps.persistence.softDeleteDocument(input.documentId, deps.clock.now());\n await emitDeleted(deps.hooks, ctx, \"soft\");\n return { ok: true, mode: \"soft\", documentId: input.documentId, objectsPurged: 0 };\n}\n\nasync function emitDeleted(\n hooks: HooksPort | undefined,\n ctx: DocumentDeletionContext,\n mode: DeleteMode,\n): Promise<void> {\n if (!hooks?.onDocumentDeleted) return;\n try {\n await hooks.onDocumentDeleted({\n documentId: ctx.documentId,\n documentType: ctx.documentType,\n scopeId: ctx.scopeId,\n mode,\n affectedSubjects: ctx.affectedSubjects,\n });\n } catch {\n // A host hook failure must never block the delete it's reacting to.\n }\n}\n","import { PDFDocument } from \"pdf-lib\";\n\nimport { EsignError } from \"./errors\";\nimport type { PersistencePort, StoragePort } from \"./ports\";\nimport { sha256Hex } from \"./tokens\";\nimport type {\n SignatureField,\n SigningDocumentDTO,\n SigningDocumentVersionDTO,\n SubjectSelection,\n} from \"./types\";\n\nexport interface CreateDocumentInput {\n scopeId?: string | null;\n documentType?: string | null;\n title: string;\n audience?: SubjectSelection | null;\n createdById?: string | null;\n}\n\nexport async function createDocument(\n persistence: PersistencePort,\n input: CreateDocumentInput,\n): Promise<SigningDocumentDTO> {\n if (!input.title.trim()) {\n throw new EsignError(\"INVALID_INPUT\", \"A document title is required.\");\n }\n return persistence.createDocument({\n scopeId: input.scopeId ?? null,\n documentType: input.documentType ?? null,\n title: input.title,\n audience: input.audience ?? null,\n createdById: input.createdById ?? null,\n });\n}\n\n/** A new version supplies its PDF either by an already-uploaded key or raw bytes. */\nexport type VersionSource =\n | { objectKey: string }\n | { pdfBytes: Uint8Array; scopeId?: string | null };\n\nexport interface AddVersionInput {\n documentId: string;\n placements: SignatureField[];\n source: VersionSource;\n changeNote?: string | null;\n createdById?: string | null;\n}\n\n/** Fail fast on a non-PDF / encrypted upload so it can't reach the seal step. */\nasync function assertReadablePdf(bytes: Uint8Array): Promise<void> {\n try {\n await PDFDocument.load(bytes);\n } catch {\n throw new EsignError(\n \"INVALID_INPUT\",\n \"The upload is not a readable PDF (it may be encrypted or corrupt).\",\n );\n }\n}\n\n/**\n * Add an immutable version to a document: validate + hash the source PDF, store\n * it (when bytes were passed), persist the next-numbered version, and point the\n * document at it as current.\n */\nexport async function addVersion(\n deps: { persistence: PersistencePort; storage: StoragePort },\n input: AddVersionInput,\n): Promise<SigningDocumentVersionDTO> {\n const { persistence, storage } = deps;\n\n let sourceObjectKey: string;\n let bytes: Uint8Array;\n if (\"objectKey\" in input.source) {\n sourceObjectKey = input.source.objectKey;\n const fetched = await storage.get(sourceObjectKey);\n if (!fetched) {\n throw new EsignError(\"INVALID_INPUT\", \"Uploaded PDF was not found in storage.\");\n }\n bytes = fetched.bytes;\n } else {\n bytes = input.source.pdfBytes;\n sourceObjectKey = storage.stampKey({\n scopeId: input.source.scopeId ?? null,\n documentId: input.documentId,\n contentType: \"application/pdf\",\n });\n await storage.put({\n objectKey: sourceObjectKey,\n bytes,\n contentType: \"application/pdf\",\n });\n }\n\n await assertReadablePdf(bytes);\n\n const latest = await persistence.latestVersion(input.documentId);\n const version = await persistence.createVersion({\n documentId: input.documentId,\n version: (latest?.version ?? 0) + 1,\n sourceObjectKey,\n sourceSha256: sha256Hex(bytes),\n placements: input.placements,\n changeNote: input.changeNote ?? null,\n createdById: input.createdById ?? null,\n });\n\n await persistence.updateDocument(input.documentId, {\n currentVersionId: version.id,\n });\n\n return version;\n}\n","import type { ZodType } from \"zod\";\n\nimport { EsignError, toErrorResponse } from \"./errors\";\nimport type { AuthPort } from \"./ports\";\n\nexport interface RouteEnv<S> {\n auth: AuthPort<S>;\n}\n\n/** Auth + admin-check + JSON-error envelope around a Next-style handler. */\nexport function adminRoute<S, Ctx = unknown>(\n env: RouteEnv<S>,\n handler: (req: Request, ctx: Ctx, scope: S) => Promise<Response>,\n) {\n return async (req: Request, ctx: Ctx): Promise<Response> => {\n try {\n const scope = await env.auth.requireAuth(req);\n if (!env.auth.isAdmin(scope)) {\n throw new EsignError(\"FORBIDDEN\", \"Admin role required.\");\n }\n return await handler(req, ctx, scope);\n } catch (err) {\n return toErrorResponse(err);\n }\n };\n}\n\n/** Authenticated (non-admin) handler with the JSON-error envelope. */\nexport function authedRoute<S, Ctx = unknown>(\n env: RouteEnv<S>,\n handler: (req: Request, ctx: Ctx, scope: S) => Promise<Response>,\n) {\n return async (req: Request, ctx: Ctx): Promise<Response> => {\n try {\n const scope = await env.auth.requireAuth(req);\n return await handler(req, ctx, scope);\n } catch (err) {\n return toErrorResponse(err);\n }\n };\n}\n\n/** Public (no-auth) handler — the token-gated signer surface. */\nexport function publicRoute<Ctx = unknown>(\n handler: (req: Request, ctx: Ctx) => Promise<Response>,\n) {\n return async (req: Request, ctx: Ctx): Promise<Response> => {\n try {\n return await handler(req, ctx);\n } catch (err) {\n return toErrorResponse(err);\n }\n };\n}\n\nexport async function parseBody<T>(req: Request, schema: ZodType<T>): Promise<T> {\n let raw: unknown;\n try {\n raw = await req.json();\n } catch {\n throw new EsignError(\"INVALID_INPUT\", \"Request body must be valid JSON.\");\n }\n const parsed = schema.safeParse(raw);\n if (!parsed.success) {\n throw new EsignError(\"INVALID_INPUT\", \"Validation failed.\", parsed.error.flatten());\n }\n return parsed.data;\n}\n\nexport function ok(data: unknown, init?: ResponseInit): Response {\n return Response.json(data, init);\n}\n\n/** Best-effort client IP from forwarding headers (for the audit trail). */\nexport function clientIp(req: Request): string | null {\n const fwd = req.headers.get(\"x-forwarded-for\");\n if (fwd) return fwd.split(\",\")[0]?.trim() ?? null;\n return req.headers.get(\"x-real-ip\");\n}\n","import { EsignError } from \"./errors\";\n\n/**\n * Lifecycle of a single signing request. PENDING/VIEWED are the only active\n * states; SIGNED/DECLINED/EXPIRED/REVOKED are terminal. The submit handler is\n * idempotent, so a no-op transition to the same state is always allowed.\n */\nexport type EsignStatus =\n | \"PENDING\"\n | \"VIEWED\"\n | \"SIGNED\"\n | \"DECLINED\"\n | \"EXPIRED\"\n | \"REVOKED\";\n\nexport const ESIGN_STATUSES: readonly EsignStatus[] = [\n \"PENDING\",\n \"VIEWED\",\n \"SIGNED\",\n \"DECLINED\",\n \"EXPIRED\",\n \"REVOKED\",\n];\n\n/** Active (still-actionable) states — eligible for view/sign/decline. */\nexport const ACTIVE_STATUSES: readonly EsignStatus[] = [\"PENDING\", \"VIEWED\"];\n\n/** Terminal states — no further transitions. */\nexport const TERMINAL_STATUSES: readonly EsignStatus[] = [\n \"SIGNED\",\n \"DECLINED\",\n \"EXPIRED\",\n \"REVOKED\",\n];\n\nconst TRANSITIONS: Record<EsignStatus, readonly EsignStatus[]> = {\n PENDING: [\"VIEWED\", \"SIGNED\", \"DECLINED\", \"EXPIRED\", \"REVOKED\"],\n VIEWED: [\"SIGNED\", \"DECLINED\", \"EXPIRED\", \"REVOKED\"],\n SIGNED: [],\n DECLINED: [],\n EXPIRED: [],\n REVOKED: [],\n};\n\nexport function isActive(status: EsignStatus): boolean {\n return ACTIVE_STATUSES.includes(status);\n}\n\nexport function isTerminal(status: EsignStatus): boolean {\n return TERMINAL_STATUSES.includes(status);\n}\n\n/** Whether `from → to` is a legal move (a same-state no-op counts as legal). */\nexport function canTransition(from: EsignStatus, to: EsignStatus): boolean {\n if (from === to) return true;\n return TRANSITIONS[from].includes(to);\n}\n\n/** Throw `EsignError('CONFLICT')` on an illegal transition. */\nexport function assertTransition(from: EsignStatus, to: EsignStatus): void {\n if (!canTransition(from, to)) {\n throw new EsignError(\n \"CONFLICT\",\n `Illegal signing-request transition: ${from} → ${to}.`,\n );\n }\n}\n","import { type PDFDocument, type PDFFont, rgb, StandardFonts } from \"pdf-lib\";\n\nimport type { AuditLink } from \"./audit-chain\";\n\n/**\n * Human-readable signature certificate appended as the final page of every\n * sealed PDF. It prints the signer, the document content SHA-256, the audit\n * chain tip, and the full event log — so the seal is verifiable by eye, and the\n * printed hashes let anyone re-check integrity out of band.\n */\nexport interface CertInfo {\n documentTitle: string;\n signerName: string;\n signedAt: string;\n signerIp: string | null;\n requestId: string;\n /** sha256 of the flattened, signature-stamped content (pre-certificate). */\n documentSha256: string;\n /** The audit chain tip (SigningRequest.finalAuditHash). */\n finalHash: string;\n links: AuditLink[];\n}\n\nconst A4: [number, number] = [595.28, 841.89];\nconst MARGIN = 48;\nconst INK = rgb(0.12, 0.12, 0.14);\nconst MUTED = rgb(0.4, 0.42, 0.46);\n\nexport async function renderAuditCertificatePage(\n pdf: PDFDocument,\n info: CertInfo,\n): Promise<void> {\n const page = pdf.addPage(A4);\n const font = await pdf.embedFont(StandardFonts.Helvetica);\n const bold = await pdf.embedFont(StandardFonts.HelveticaBold);\n const mono = await pdf.embedFont(StandardFonts.Courier);\n const [pageW, pageH] = A4;\n\n let y = pageH - MARGIN;\n const draw = (\n text: string,\n opts: { x?: number; size?: number; font?: PDFFont; color?: typeof INK } = {},\n ) => {\n page.drawText(text, {\n x: opts.x ?? MARGIN,\n y,\n size: opts.size ?? 10,\n font: opts.font ?? font,\n color: opts.color ?? INK,\n });\n };\n const advance = (by: number) => {\n y -= by;\n };\n\n draw(\"Signature Certificate\", { size: 20, font: bold });\n advance(14);\n draw(\"Electronic signature with a tamper-evident (Level-1 sealed) audit trail.\", {\n size: 9,\n color: MUTED,\n });\n advance(28);\n\n const field = (label: string, value: string, valueFont: PDFFont = font) => {\n draw(label, { size: 8, font: bold, color: MUTED });\n advance(13);\n draw(value, { size: 10, font: valueFont });\n advance(20);\n };\n\n field(\"DOCUMENT\", info.documentTitle);\n field(\"SIGNED BY\", info.signerName);\n field(\"SIGNED AT\", info.signedAt);\n field(\"SIGNER IP\", info.signerIp ?? \"—\");\n field(\"REQUEST ID\", info.requestId, mono);\n field(\"DOCUMENT SHA-256\", info.documentSha256, mono);\n field(\"AUDIT CHAIN TIP\", info.finalHash, mono);\n\n advance(6);\n draw(\"AUDIT TRAIL\", { size: 8, font: bold, color: MUTED });\n advance(16);\n\n // Column header\n draw(\"#\", { x: MARGIN, size: 8, font: bold, color: MUTED });\n draw(\"EVENT\", { x: MARGIN + 24, size: 8, font: bold, color: MUTED });\n draw(\"WHEN\", { x: MARGIN + 170, size: 8, font: bold, color: MUTED });\n draw(\"HASH\", { x: MARGIN + 330, size: 8, font: bold, color: MUTED });\n advance(4);\n page.drawLine({\n start: { x: MARGIN, y },\n end: { x: pageW - MARGIN, y },\n thickness: 0.5,\n color: MUTED,\n });\n advance(14);\n\n for (const link of info.links) {\n if (y < MARGIN + 20) break; // single-page cert; chain is also stored in the DB\n draw(String(link.seq), { x: MARGIN, size: 9 });\n draw(link.type, { x: MARGIN + 24, size: 9 });\n draw(link.occurredAt, { x: MARGIN + 170, size: 8, color: MUTED });\n draw(`${link.hash.slice(0, 16)}…`, { x: MARGIN + 330, size: 8, font: mono });\n advance(15);\n }\n}\n","import { PDFDocument, rgb, StandardFonts } from \"pdf-lib\";\n\nimport { appendEvent, type AuditLink } from \"./audit-chain\";\nimport { renderAuditCertificatePage } from \"./audit-cert\";\nimport { EsignError } from \"./errors\";\nimport { sha256Hex } from \"./tokens\";\nimport { DEFAULT_DATE_FORMAT, formatPickedDate, type DocumentField } from \"./types\";\n\n/**\n * The Level-1 seal. Loads the version's source PDF, stamps the signature within\n * the manager's placement box, appends SIGNED + SEALED audit links, renders the\n * certificate page, and returns the flattened bytes plus the content hash and\n * chain tip. Pure + deterministic: a fixed input (incl. `signedAt`) yields\n * byte-identical output, so `sealedSha256` is reproducible and testable.\n *\n * `documentSha256` is the hash of the stamped content *before* the certificate\n * page (the bytes that were actually signed); `sealedSha256` covers the final\n * file. A future Level-2 PAdES seal wraps the returned `sealedPdf` unchanged.\n */\nexport interface SealInput {\n sourcePdf: Uint8Array;\n /** PNG bytes of the drawn or typed signature. */\n signaturePng: Uint8Array;\n /** The version's fields. Signature fields get the signature; date fields the picked date. */\n fields: DocumentField[];\n /** Picked date per date-field id (ISO `yyyy-mm-dd`). */\n dateValues: Record<string, string>;\n signerName: string;\n /** ISO instant — also pins the PDF metadata dates for reproducibility. */\n signedAt: string;\n signerIp: string | null;\n documentTitle: string;\n requestId: string;\n /** Existing chain (CREATED…CONSENTED). SIGNED + SEALED are appended here. */\n priorChain: AuditLink[];\n}\n\nexport interface SealResult {\n sealedPdf: Uint8Array;\n sealedSha256: string;\n documentSha256: string;\n finalHash: string;\n /** The SIGNED and SEALED links — the caller persists them. */\n newLinks: AuditLink[];\n}\n\nexport async function sealPdf(input: SealInput): Promise<SealResult> {\n let pdf: PDFDocument;\n try {\n pdf = await PDFDocument.load(input.sourcePdf);\n } catch {\n throw new EsignError(\n \"INVALID_INPUT\",\n \"Could not read the PDF — it may be encrypted or corrupt.\",\n );\n }\n\n const when = new Date(input.signedAt);\n pdf.setCreationDate(when);\n pdf.setModificationDate(when);\n pdf.setProducer(\"@josephomills/esign\");\n pdf.setCreator(\"@josephomills/esign\");\n\n const pages = pdf.getPages();\n const png = await pdf.embedPng(input.signaturePng);\n const font = await pdf.embedFont(StandardFonts.Helvetica);\n const caption = `Signed by ${input.signerName} · ${input.signedAt}${\n input.signerIp ? ` · IP ${input.signerIp}` : \"\"\n }`;\n\n // Stamp each field: the signature image on signature fields, the picked date\n // (formatted) on date fields. The caption goes once, under the first signature.\n let captionDrawn = false;\n input.fields.forEach((field) => {\n const pageIndex = Math.min(Math.max(field.page - 1, 0), pages.length - 1);\n const page = pages[pageIndex]!;\n const pageW = page.getWidth();\n const pageH = page.getHeight();\n // Fields are normalized top-left origin; pdf-lib is bottom-left.\n const boxX = field.x * pageW;\n const boxW = field.w * pageW;\n const boxH = field.h * pageH;\n const boxBottomY = pageH * (1 - field.y - field.h);\n\n if (field.type === \"date\") {\n const iso = input.dateValues[field.id];\n if (!iso) return; // unfilled date field — validation should prevent this\n const text = formatPickedDate(iso, field.dateFormat ?? DEFAULT_DATE_FORMAT);\n let size = Math.min(boxH * 0.62, 15);\n let textW = font.widthOfTextAtSize(text, size);\n if (textW > boxW && textW > 0) {\n size *= boxW / textW;\n textW = font.widthOfTextAtSize(text, size);\n }\n page.drawText(text, {\n x: boxX + Math.max(0, (boxW - textW) / 2),\n y: boxBottomY + (boxH - size) / 2 + size * 0.22,\n size,\n font,\n color: rgb(0.1, 0.1, 0.12),\n });\n return;\n }\n\n const scale = Math.min(boxW / png.width, boxH / png.height);\n const drawW = png.width * scale;\n const drawH = png.height * scale;\n page.drawImage(png, {\n x: boxX + (boxW - drawW) / 2,\n y: boxBottomY + (boxH - drawH) / 2,\n width: drawW,\n height: drawH,\n });\n if (!captionDrawn) {\n captionDrawn = true;\n page.drawText(caption, {\n x: boxX,\n y: Math.max(boxBottomY - 11, 4),\n size: 7,\n font,\n color: rgb(0.35, 0.35, 0.4),\n });\n }\n });\n\n // Content hash: the stamped document, before the certificate page is added.\n const stampedBytes = await pdf.save({ useObjectStreams: false });\n const documentSha256 = sha256Hex(stampedBytes);\n\n const last = input.priorChain.at(-1) ?? null;\n const signed = appendEvent(last, {\n type: \"SIGNED\",\n payload: {\n signerName: input.signerName,\n signerIp: input.signerIp,\n signedAt: input.signedAt,\n },\n occurredAt: input.signedAt,\n });\n const sealed = appendEvent(signed, {\n type: \"SEALED\",\n payload: { documentSha256 },\n occurredAt: input.signedAt,\n });\n const finalHash = sealed.hash;\n\n await renderAuditCertificatePage(pdf, {\n documentTitle: input.documentTitle,\n signerName: input.signerName,\n signedAt: input.signedAt,\n signerIp: input.signerIp,\n requestId: input.requestId,\n documentSha256,\n finalHash,\n links: [...input.priorChain, signed, sealed],\n });\n\n const sealedPdf = await pdf.save({ useObjectStreams: false });\n return {\n sealedPdf,\n sealedSha256: sha256Hex(sealedPdf),\n documentSha256,\n finalHash,\n newLinks: [signed, sealed],\n };\n}\n","import type { AuditLink } from \"./audit-chain\";\nimport { recordEvent } from \"./campaign\";\nimport { EsignError } from \"./errors\";\nimport { isActive } from \"./flow\";\nimport type {\n Clock,\n HooksPort,\n NotifierPort,\n PersistencePort,\n StoragePort,\n} from \"./ports\";\nimport { sealPdf } from \"./seal\";\nimport { sha256Hex } from \"./tokens\";\nimport type { SignatureField, SigningAuditEventDTO, SigningRequestDTO } from \"./types\";\n\nexport interface SignDeps {\n persistence: PersistencePort;\n storage: StoragePort;\n clock: Clock;\n notifier: NotifierPort;\n hooks?: HooksPort;\n}\n\nconst toLink = (e: SigningAuditEventDTO): AuditLink => ({\n seq: e.seq,\n type: e.type,\n payload: (e.payload as Record<string, unknown>) ?? {},\n prevHash: e.prevHash,\n hash: e.hash,\n occurredAt: e.occurredAt,\n});\n\n/** Resolve a request from its cleartext token, with no existence oracle. */\nasync function resolve(\n persistence: PersistencePort,\n token: string,\n): Promise<SigningRequestDTO | null> {\n return persistence.findRequestByTokenHash(sha256Hex(token));\n}\n\nexport interface SigningView {\n request: SigningRequestDTO;\n /** Source PDF object key + signature fields for the signer page to render. */\n sourceObjectKey: string;\n placements: SignatureField[];\n documentTitle: string;\n}\n\n/**\n * Data for the public signing page. Returns null for unknown / expired / revoked\n * / already-finished requests so the host shows one \"unavailable\" screen.\n */\nexport async function getSigningView(\n deps: Pick<SignDeps, \"persistence\" | \"clock\">,\n token: string,\n): Promise<SigningView | null> {\n const request = await resolve(deps.persistence, token);\n if (!request) return null;\n if (!isActive(request.status)) return null;\n if (request.revokedAt) return null;\n if (new Date(request.expiresAt) < deps.clock.now()) return null;\n\n const version = await deps.persistence.getVersion(request.documentVersionId);\n if (!version) return null;\n const document = await deps.persistence.getDocument(request.documentId);\n return {\n request,\n sourceObjectKey: version.sourceObjectKey,\n placements: version.placements,\n documentTitle: document?.title ?? \"Document\",\n };\n}\n\n/** Mark first view PENDING→VIEWED, recording a VIEWED audit event. Idempotent. */\nexport async function recordView(\n deps: Pick<SignDeps, \"persistence\" | \"clock\" | \"hooks\">,\n token: string,\n): Promise<void> {\n const request = await resolve(deps.persistence, token);\n if (!request || request.status !== \"PENDING\") return;\n const existing = (await deps.persistence.listAuditEvents(request.id)).map(toLink);\n const now = deps.clock.now();\n await recordEvent(deps.persistence, request.id, existing.at(-1) ?? null, {\n type: \"VIEWED\",\n payload: {},\n occurredAt: now.toISOString(),\n });\n const updated = await deps.persistence.updateRequest(request.id, {\n status: \"VIEWED\",\n viewedAt: now,\n });\n if (deps.hooks?.onRequestViewed) await deps.hooks.onRequestViewed(updated);\n}\n\nexport interface SubmitInput {\n token: string;\n signaturePng: Uint8Array;\n signerName: string;\n /** Picked date per date-field id (ISO `yyyy-mm-dd`). */\n dateValues?: Record<string, string>;\n ip: string | null;\n userAgent: string | null;\n}\n\nexport interface SubmitResult {\n requestId: string;\n sealedObjectKey: string;\n alreadySigned: boolean;\n}\n\n/**\n * The signer submit: consent → seal → store → persist SIGNED → fire hook →\n * optional emailed receipt. Idempotent — a re-submit of a signed request returns\n * the existing sealed key instead of re-sealing.\n */\nexport async function submitSignature(\n deps: SignDeps,\n input: SubmitInput,\n): Promise<SubmitResult> {\n const { persistence, storage, clock, notifier, hooks } = deps;\n const request = await resolve(persistence, input.token);\n if (!request) throw new EsignError(\"NOT_FOUND\", \"This signing link is not valid.\");\n\n if (request.status === \"SIGNED\") {\n return {\n requestId: request.id,\n sealedObjectKey: request.sealedObjectKey ?? \"\",\n alreadySigned: true,\n };\n }\n if (!isActive(request.status) || request.revokedAt) {\n throw new EsignError(\"GONE\", \"This signing link is no longer available.\");\n }\n const now = clock.now();\n if (new Date(request.expiresAt) < now) {\n await persistence.updateRequest(request.id, { status: \"EXPIRED\" });\n throw new EsignError(\"GONE\", \"This signing link has expired.\");\n }\n\n const version = await persistence.getVersion(request.documentVersionId);\n if (!version) throw new EsignError(\"INTERNAL\", \"Document version missing.\");\n const src = await storage.get(version.sourceObjectKey);\n if (!src) throw new EsignError(\"INTERNAL\", \"Source document missing.\");\n const document = await persistence.getDocument(request.documentId);\n\n // Every date field must be filled and not before its floor (the field's\n // minDate, else the document's creation date). yyyy-mm-dd compares lexically.\n const dateValues = input.dateValues ?? {};\n const createdFloor = document?.createdAt ? document.createdAt.slice(0, 10) : null;\n for (const field of version.placements) {\n if (field.type !== \"date\") continue;\n const value = dateValues[field.id];\n const name = field.label || \"date\";\n if (!value) throw new EsignError(\"INVALID_INPUT\", `Please fill in the \"${name}\" date.`);\n const floor = field.minDate ?? createdFloor;\n if (floor && value < floor) {\n throw new EsignError(\"INVALID_INPUT\", `The \"${name}\" date can't be before ${floor}.`);\n }\n }\n\n const existing = (await persistence.listAuditEvents(request.id)).map(toLink);\n const nowIso = now.toISOString();\n const consented = await recordEvent(persistence, request.id, existing.at(-1) ?? null, {\n type: \"CONSENTED\",\n payload: {\n signerName: input.signerName,\n ip: input.ip,\n userAgent: input.userAgent,\n },\n occurredAt: nowIso,\n });\n\n const seal = await sealPdf({\n sourcePdf: src.bytes,\n signaturePng: input.signaturePng,\n fields: version.placements,\n dateValues,\n signerName: input.signerName,\n signedAt: nowIso,\n signerIp: input.ip,\n documentTitle: document?.title ?? \"Document\",\n requestId: request.id,\n priorChain: [...existing, consented],\n });\n\n const sealedObjectKey = storage.sealedKey({\n scopeId: request.scopeId,\n campaignId: request.campaignId,\n requestId: request.id,\n });\n await storage.put({\n objectKey: sealedObjectKey,\n bytes: seal.sealedPdf,\n contentType: \"application/pdf\",\n });\n\n await persistence.updateRequest(request.id, {\n status: \"SIGNED\",\n signedAt: now,\n signerName: input.signerName,\n signerIp: input.ip ?? undefined,\n signerUserAgent: input.userAgent ?? undefined,\n sealedObjectKey,\n sealedSha256: seal.sealedSha256,\n finalAuditHash: seal.finalHash,\n });\n\n for (const link of seal.newLinks) {\n await persistence.appendAuditEvent({\n requestId: request.id,\n seq: link.seq,\n type: link.type,\n payload: link.payload,\n prevHash: link.prevHash,\n hash: link.hash,\n });\n }\n\n if (hooks?.onRequestSigned) {\n await hooks.onRequestSigned({\n subjectType: request.subjectType,\n subjectId: request.subjectId,\n documentId: request.documentId,\n documentType: document?.documentType ?? null,\n requestId: request.id,\n sealedObjectKey,\n signedAt: nowIso,\n });\n }\n\n // Optional emailed receipt — never blocks the signing result.\n const campaign = await persistence.getCampaign(request.campaignId);\n if (campaign?.emailReceipt && request.recipientEmail) {\n const title = document?.title ?? \"Document\";\n try {\n await notifier.send({\n channel: \"EMAIL\",\n recipient: request.recipientEmail,\n subject: `Signed copy: ${title}`,\n body: `Hello ${request.recipientName},\\n\\nAttached is your signed copy of \"${title}\".`,\n idempotencyKey: `${request.id}:receipt`,\n attachments: [\n {\n filename: `${title.replace(/[^a-z0-9-_ ]/gi, \"_\")}.pdf`,\n content: seal.sealedPdf,\n contentType: \"application/pdf\",\n },\n ],\n });\n } catch {\n // receipt delivery is best-effort\n }\n }\n\n return { requestId: request.id, sealedObjectKey, alreadySigned: false };\n}\n\nexport interface DeclineRequestInput {\n token: string;\n reason: string | null;\n}\n\n/** Signer declines: PENDING/VIEWED → DECLINED, recording a DECLINED event. */\nexport async function declineRequest(\n deps: Pick<SignDeps, \"persistence\" | \"clock\" | \"hooks\">,\n input: DeclineRequestInput,\n): Promise<void> {\n const request = await resolve(deps.persistence, input.token);\n if (!request || !isActive(request.status) || request.revokedAt) {\n throw new EsignError(\"GONE\", \"This signing link is no longer available.\");\n }\n const existing = (await deps.persistence.listAuditEvents(request.id)).map(toLink);\n const now = deps.clock.now();\n await recordEvent(deps.persistence, request.id, existing.at(-1) ?? null, {\n type: \"DECLINED\",\n payload: { reason: input.reason },\n occurredAt: now.toISOString(),\n });\n const updated = await deps.persistence.updateRequest(request.id, {\n status: \"DECLINED\",\n declinedAt: now,\n declineReason: input.reason ?? undefined,\n });\n if (deps.hooks?.onRequestDeclined) await deps.hooks.onRequestDeclined(updated);\n}\n","import { EsignError } from \"../errors\";\nimport { clientIp, ok, parseBody, publicRoute } from \"../route-utils\";\nimport { declineRequest, type SignDeps, submitSignature } from \"../sign\";\nimport { declineSchema, submitSignatureSchema } from \"../types\";\n\ntype RouteCtx = { params: { token: string } | Promise<{ token: string }> };\n\nconst PNG_MAGIC = [0x89, 0x50, 0x4e, 0x47];\n\n/** Decode a `data:image/png;base64,...` URL to bytes; reject anything not a PNG. */\nfunction pngFromDataUrl(dataUrl: string): Uint8Array {\n const comma = dataUrl.indexOf(\",\");\n const b64 = comma >= 0 ? dataUrl.slice(comma + 1) : dataUrl;\n const bytes = new Uint8Array(Buffer.from(b64, \"base64\"));\n const isPng = PNG_MAGIC.every((b, i) => bytes[i] === b);\n if (!isPng) {\n throw new EsignError(\"INVALID_INPUT\", \"Signature must be a PNG image.\");\n }\n return bytes;\n}\n\n/**\n * POST the signer action. `?action=decline` declines; otherwise it submits the\n * signature (consent → seal → SIGNED). Mount at `app/sign/[token]/submit/route.ts`.\n */\nexport function createSignActionsRoute(deps: SignDeps) {\n return {\n POST: publicRoute<RouteCtx>(async (req, ctx) => {\n const { token } = await ctx.params;\n const action = new URL(req.url).searchParams.get(\"action\");\n\n if (action === \"decline\") {\n const { reason } = await parseBody(req, declineSchema);\n await declineRequest(deps, { token, reason: reason ?? null });\n return ok({ ok: true, declined: true });\n }\n\n const body = await parseBody(req, submitSignatureSchema);\n const result = await submitSignature(deps, {\n token,\n signaturePng: pngFromDataUrl(body.signaturePng),\n signerName: body.signerName,\n dateValues: body.dateValues,\n ip: clientIp(req),\n userAgent: req.headers.get(\"user-agent\"),\n });\n return ok({\n ok: true,\n requestId: result.requestId,\n alreadySigned: result.alreadySigned,\n });\n }),\n };\n}\n","import { EsignError } from \"../errors\";\nimport type { Clock, PersistencePort, StoragePort } from \"../ports\";\nimport { publicRoute } from \"../route-utils\";\nimport { getSigningView } from \"../sign\";\n\ntype RouteCtx = { params: { token: string } | Promise<{ token: string }> };\n\nexport interface SignServeDeps {\n persistence: PersistencePort;\n storage: StoragePort;\n clock: Clock;\n}\n\n/**\n * GET the source PDF for the signer page, gated only by the (unguessable) token.\n * Bad / expired / revoked / finished tokens all 404 the same way (no oracle).\n * Mount at `app/api/esign/source/[token]/route.ts`; the host should rate-limit.\n */\nexport function createSignServeRoute(deps: SignServeDeps) {\n return {\n GET: publicRoute<RouteCtx>(async (_req, ctx) => {\n const { token } = await ctx.params;\n const view = await getSigningView(deps, token);\n if (!view) throw new EsignError(\"NOT_FOUND\", \"Not available.\");\n const obj = await deps.storage.get(view.sourceObjectKey);\n if (!obj) throw new EsignError(\"NOT_FOUND\", \"Not available.\");\n return new Response(obj.bytes as Uint8Array<ArrayBuffer>, {\n status: 200,\n headers: {\n \"content-type\": \"application/pdf\",\n \"content-disposition\": \"inline\",\n \"cache-control\": \"private, no-store\",\n \"x-robots-tag\": \"noindex\",\n },\n });\n }),\n };\n}\n","import {\n createCampaign,\n type CreateCampaignArgs,\n type CreateCampaignResult,\n} from \"./campaign\";\nimport { documentCoverage } from \"./coverage\";\nimport {\n deleteDocument,\n type DeleteDocumentInput,\n type DeleteDocumentResult,\n} from \"./delete\";\nimport {\n addVersion,\n type AddVersionInput,\n createDocument,\n type CreateDocumentInput,\n} from \"./documents\";\nimport type { Clock, EsignConfig } from \"./ports\";\nimport { createSignActionsRoute } from \"./routes/sign-actions\";\nimport { createSignServeRoute } from \"./routes/sign-serve\";\nimport {\n declineRequest,\n type DeclineRequestInput,\n getSigningView,\n recordView,\n type SigningView,\n type SubmitInput,\n type SubmitResult,\n submitSignature,\n} from \"./sign\";\nimport { newSigningToken } from \"./tokens\";\nimport type {\n CampaignStatsRow,\n CoverageReport,\n DocumentStatsRow,\n OutstandingRequest,\n ScopeStatsRow,\n SigningDocumentDTO,\n SigningDocumentVersionDTO,\n StatsRange,\n SubjectSigningStatus,\n VersionPolicy,\n} from \"./types\";\n\nconst DEFAULT_BASE = \"/api/esign\";\nconst DEFAULT_PRESIGN_TTL_S = 900;\nconst DEFAULT_EXPIRY_DAYS = 30;\n\nconst systemClock: Clock = { now: () => new Date() };\n\nexport type ResolvedEsignConfig<S> = EsignConfig<S> &\n Required<\n Pick<EsignConfig<S>, \"routeBasePath\" | \"presignTtlS\" | \"defaultExpiryDays\" | \"clock\">\n >;\n\nexport interface SubjectSigningStatusArgs {\n subjectType: string;\n subjectId: string;\n documentId?: string;\n documentType?: string;\n versionPolicy: VersionPolicy;\n}\n\n/**\n * The wired runtime: every engine function bound to the host's ports, plus the\n * route-handler factories the host mounts. Mirrors milestone-grid's\n * `configureMilestoneGrid(...) → { routes, ... }`.\n */\nexport interface EsignRuntime<S> {\n config: ResolvedEsignConfig<S>;\n newSigningToken: typeof newSigningToken;\n\n // Authoring\n createDocument(input: CreateDocumentInput): Promise<SigningDocumentDTO>;\n addVersion(input: AddVersionInput): Promise<SigningDocumentVersionDTO>;\n createCampaign(args: CreateCampaignArgs): Promise<CreateCampaignResult>;\n deleteDocument(input: DeleteDocumentInput): Promise<DeleteDocumentResult>;\n\n // Signing\n getSigningView(token: string): Promise<SigningView | null>;\n recordView(token: string): Promise<void>;\n submitSignature(input: SubmitInput): Promise<SubmitResult>;\n declineRequest(input: DeclineRequestInput): Promise<void>;\n\n // Status / coverage / stats\n subjectSigningStatus(args: SubjectSigningStatusArgs): Promise<SubjectSigningStatus>;\n documentCoverage(documentId: string): Promise<CoverageReport>;\n campaignStats(campaignId: string): Promise<CampaignStatsRow>;\n documentStats(documentId: string): Promise<DocumentStatsRow>;\n scopeStats(scopeId: string | null, range?: StatsRange): Promise<ScopeStatsRow>;\n outstandingRequests(filter: {\n scopeId?: string | null;\n documentId?: string;\n campaignId?: string;\n now: Date;\n limit?: number;\n }): Promise<OutstandingRequest[]>;\n\n routes: {\n signServe: ReturnType<typeof createSignServeRoute>;\n signActions: ReturnType<typeof createSignActionsRoute>;\n };\n}\n\nexport function configureEsign<S>(opts: EsignConfig<S>): EsignRuntime<S> {\n const config: ResolvedEsignConfig<S> = {\n ...opts,\n routeBasePath: opts.routeBasePath ?? DEFAULT_BASE,\n presignTtlS: opts.presignTtlS ?? DEFAULT_PRESIGN_TTL_S,\n defaultExpiryDays: opts.defaultExpiryDays ?? DEFAULT_EXPIRY_DAYS,\n clock: opts.clock ?? systemClock,\n };\n\n const { persistence, storage, notifier, subjects, hooks, clock, baseUrl } = config;\n const signDeps = { persistence, storage, clock, notifier, hooks };\n\n return {\n config,\n newSigningToken,\n\n createDocument: (input) => createDocument(persistence, input),\n addVersion: (input) => addVersion({ persistence, storage }, input),\n createCampaign: (args) =>\n createCampaign(\n {\n persistence,\n subjects,\n notifier,\n clock,\n baseUrl,\n defaultExpiryDays: config.defaultExpiryDays,\n },\n args,\n ),\n deleteDocument: (input) => deleteDocument({ persistence, storage, clock, hooks }, input),\n\n getSigningView: (token) => getSigningView({ persistence, clock }, token),\n recordView: (token) => recordView({ persistence, clock, hooks }, token),\n submitSignature: (input) => submitSignature(signDeps, input),\n declineRequest: (input) => declineRequest({ persistence, clock, hooks }, input),\n\n subjectSigningStatus: (args) => persistence.subjectSigningStatus(args),\n documentCoverage: (documentId) => documentCoverage({ persistence, subjects }, documentId),\n campaignStats: (campaignId) => persistence.campaignStats(campaignId),\n documentStats: (documentId) => persistence.documentStats(documentId),\n scopeStats: (scopeId, range) => persistence.scopeStats(scopeId, range),\n outstandingRequests: (filter) => persistence.outstandingRequests(filter),\n\n routes: {\n signServe: createSignServeRoute({ persistence, storage, clock }),\n signActions: createSignActionsRoute(signDeps),\n },\n };\n}\n","import type { SubjectsPort, SubjectTypeDescriptor } from \"./ports\";\n\n/**\n * Build a SubjectsPort from a list of host-defined subject-type descriptors.\n * The package renders targeting from `groupField` / `filterFields` and calls\n * the descriptor's enumeration/resolution methods; it never learns what a\n * \"MISSIONARY\" or \"APARTMENT\" actually is.\n */\nexport function registerSubjectTypes(types: SubjectTypeDescriptor[]): SubjectsPort {\n const map = new Map(types.map((t) => [t.type, t]));\n return {\n types,\n get: (type: string) => map.get(type),\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { S as SubjectSelection, E as EsignChannel, R as ResendPolicy, P as PersistencePort, a as SubjectsPort, N as NotifierPort, C as Clock, b as SkippedSubject, c as StoragePort, H as HooksPort, d as SignatureField, e as SigningDocumentVersionDTO, f as SigningDocumentDTO, g as SigningRequestDTO, h as EsignConfig, V as VersionPolicy, i as SubjectSigningStatus, j as CoverageReport, k as CampaignStatsRow, D as DocumentStatsRow, l as StatsRange, m as ScopeStatsRow, O as OutstandingRequest, n as SubjectTypeDescriptor, o as Placement } from '../ports-CkBaAepo.cjs';
2
- export { A as ACTIVE_STATUSES, p as AffectedSubject, q as AuthPort, r as DeclineInput, s as DocumentDeletionContext, t as ESIGN_CHANNELS, u as ESIGN_STATUSES, v as EsignStatus, G as GroupBreakdown, w as NewAuditEventRow, x as NewRequestRow, y as NotifierAttachment, z as Recipient, B as RequestSummary, F as SigningAuditEventDTO, I as SigningCampaignDTO, J as StatusCountMap, K as SubjectFilter, L as SubjectFilterField, M as SubjectSigningState, Q as SubjectSummary, T as SubmitSignatureInput, U as TERMINAL_STATUSES, W as assertTransition, X as canTransition, Y as declineSchema, Z as esignChannelSchema, _ as isActive, $ as isTerminal, a0 as placementSchema, a1 as placementsSchema, a2 as signatureFieldSchema, a3 as subjectSelectionSchema, a4 as submitSignatureSchema } from '../ports-CkBaAepo.cjs';
1
+ import { S as SubjectSelection, E as EsignChannel, R as ResendPolicy, P as PersistencePort, a as SubjectsPort, N as NotifierPort, C as Clock, b as SkippedSubject, c as StoragePort, H as HooksPort, d as SignatureField, e as SigningDocumentVersionDTO, f as SigningDocumentDTO, g as SigningRequestDTO, h as EsignConfig, V as VersionPolicy, i as SubjectSigningStatus, j as CoverageReport, k as CampaignStatsRow, D as DocumentStatsRow, l as StatsRange, m as ScopeStatsRow, O as OutstandingRequest, n as SubjectTypeDescriptor, o as DocumentField } from '../ports--YsOnh8H.cjs';
2
+ export { A as ACTIVE_STATUSES, p as AffectedSubject, q as AuthPort, r as DATE_FORMATS, s as DATE_FORMAT_LABELS, t as DEFAULT_DATE_FORMAT, u as DateFormat, v as DeclineInput, w as DocumentDeletionContext, x as ESIGN_CHANNELS, y as ESIGN_STATUSES, z as EsignStatus, F as FieldType, G as GroupBreakdown, B as NewAuditEventRow, I as NewRequestRow, J as NotifierAttachment, K as Placement, L as Recipient, M as RequestSummary, Q as SigningAuditEventDTO, T as SigningCampaignDTO, U as StatusCountMap, W as SubjectFilter, X as SubjectFilterField, Y as SubjectSigningState, Z as SubjectSummary, _ as SubmitSignatureInput, $ as TERMINAL_STATUSES, a0 as assertTransition, a1 as canTransition, a2 as declineSchema, a3 as documentFieldSchema, a4 as esignChannelSchema, a5 as formatPickedDate, a6 as isActive, a7 as isTerminal, a8 as placementSchema, a9 as placementsSchema, aa as signatureFieldSchema, ab as subjectSelectionSchema, ac as submitSignatureSchema } from '../ports--YsOnh8H.cjs';
3
3
  import { PDFDocument } from 'pdf-lib';
4
4
  import { ZodType } from 'zod';
5
5
 
@@ -176,6 +176,8 @@ interface SubmitInput {
176
176
  token: string;
177
177
  signaturePng: Uint8Array;
178
178
  signerName: string;
179
+ /** Picked date per date-field id (ISO `yyyy-mm-dd`). */
180
+ dateValues?: Record<string, string>;
179
181
  ip: string | null;
180
182
  userAgent: string | null;
181
183
  }
@@ -344,8 +346,10 @@ interface SealInput {
344
346
  sourcePdf: Uint8Array;
345
347
  /** PNG bytes of the drawn or typed signature. */
346
348
  signaturePng: Uint8Array;
347
- /** One or more boxes; the signature is stamped at each. */
348
- placements: Placement[];
349
+ /** The version's fields. Signature fields get the signature; date fields the picked date. */
350
+ fields: DocumentField[];
351
+ /** Picked date per date-field id (ISO `yyyy-mm-dd`). */
352
+ dateValues: Record<string, string>;
349
353
  signerName: string;
350
354
  /** ISO instant — also pins the PDF metadata dates for reproducibility. */
351
355
  signedAt: string;
@@ -390,4 +394,4 @@ declare class EsignError extends Error {
390
394
  }
391
395
  declare function toErrorResponse(err: unknown): Response;
392
396
 
393
- export { type AddVersionInput, type AuditEventInput, type AuditLink, type CampaignContentBuilder, CampaignStatsRow, type CertInfo, type ChannelContent, Clock, type CoverageDeps, CoverageReport, type CreateCampaignArgs, type CreateCampaignDeps, type CreateCampaignResult, type CreateDocumentInput, type DeclineRequestInput, type DeleteDocumentDeps, type DeleteDocumentInput, type DeleteDocumentResult, type DeleteMode, DocumentStatsRow, EsignChannel, EsignConfig, EsignError, type EsignErrorCode, type EsignRuntime, HooksPort, NotifierPort, OutstandingRequest, PersistencePort, Placement, ResendPolicy, type ResolvedEsignConfig, ScopeStatsRow, type SealInput, type SealResult, type SignDeps, type SignServeDeps, SignatureField, SigningDocumentDTO, SigningDocumentVersionDTO, SigningRequestDTO, type SigningToken, type SigningView, SkippedSubject, StatsRange, StoragePort, SubjectSelection, SubjectSigningStatus, type SubjectSigningStatusArgs, SubjectTypeDescriptor, SubjectsPort, type SubmitInput, type SubmitResult, VersionPolicy, type VersionSource, addVersion, appendEvent, buildChain, canonicalize, clientIp, configureEsign, createCampaign, createDocument, createSignActionsRoute, createSignServeRoute, declineRequest, deleteDocument, documentCoverage, getSigningView, linkHash, newSigningToken, ok, parseBody, recordEvent, recordView, registerSubjectTypes, renderAuditCertificatePage, sealPdf, sha256Hex, submitSignature, toErrorResponse, uid, verifyChain };
397
+ export { type AddVersionInput, type AuditEventInput, type AuditLink, type CampaignContentBuilder, CampaignStatsRow, type CertInfo, type ChannelContent, Clock, type CoverageDeps, CoverageReport, type CreateCampaignArgs, type CreateCampaignDeps, type CreateCampaignResult, type CreateDocumentInput, type DeclineRequestInput, type DeleteDocumentDeps, type DeleteDocumentInput, type DeleteDocumentResult, type DeleteMode, DocumentField, DocumentStatsRow, EsignChannel, EsignConfig, EsignError, type EsignErrorCode, type EsignRuntime, HooksPort, NotifierPort, OutstandingRequest, PersistencePort, ResendPolicy, type ResolvedEsignConfig, ScopeStatsRow, type SealInput, type SealResult, type SignDeps, type SignServeDeps, SignatureField, SigningDocumentDTO, SigningDocumentVersionDTO, SigningRequestDTO, type SigningToken, type SigningView, SkippedSubject, StatsRange, StoragePort, SubjectSelection, SubjectSigningStatus, type SubjectSigningStatusArgs, SubjectTypeDescriptor, SubjectsPort, type SubmitInput, type SubmitResult, VersionPolicy, type VersionSource, addVersion, appendEvent, buildChain, canonicalize, clientIp, configureEsign, createCampaign, createDocument, createSignActionsRoute, createSignServeRoute, declineRequest, deleteDocument, documentCoverage, getSigningView, linkHash, newSigningToken, ok, parseBody, recordEvent, recordView, registerSubjectTypes, renderAuditCertificatePage, sealPdf, sha256Hex, submitSignature, toErrorResponse, uid, verifyChain };