@classytic/esign
v0.1.0
Published
Electronic-signature kernel — signature-request lifecycle (sequential/parallel signers), tamper-evident hash-chained evidence trail, and the crypto-engine ports (certificate store, PDF signer, RFC3161 TSA, identity bridge). Pure TypeScript, zero dependenc
Readme
@classytic/esign
Electronic-signature kernel — signature-request lifecycle, tamper-evident evidence trail, and the crypto/trust ports. Pure TypeScript, zero dependencies (
node:cryptoonly).
The base of the classytic trust stack:
Identity (eKYC) ──▶ Certificate (CA) ──▶ Signature (this kernel + engines) ──▶ Evidence (hash chain)What ships in this package (P1)
| Layer | Module | Status |
| --- | --- | --- |
| Signature-request lifecycle (sequential/parallel signers, decline/void/expire) | request.ts | ✅ implemented + tested |
| Tamper-evident evidence chain (sha256 hash chain, canonical JSON) | evidence.ts | ✅ implemented + tested |
| Crypto-engine + trust ports (PdfSigner, TimestampAuthority, CertificateStore, CertificateIssuer, IdentityBridge) | ports.ts | ✅ contracts (engines land in P2+) |
import {
createSignatureRequest, sendRequest, applySignature,
appendEvidence, verifyEvidenceChain, digestContent,
} from '@classytic/esign';
let req = createSignatureRequest({
documentDigest: digestContent(pdfBytes),
order: 'sequential',
parties: [{ id: 'buyer' }, { id: 'seller' }],
});
req = sendRequest(req);
req = applySignature(req, { partyId: 'buyer', artifact: { contentDigest: digestContent(pdfBytes) } });
let evidence = appendEvidence([], { event: 'party.signed', at: new Date().toISOString(), actor: 'buyer' });
verifyEvidenceChain(evidence); // { ok: true, length: 1 } — any later edit breaks itDesign rules
- Fail-closed everywhere trust is involved. A TSA failure is an error, never a silent local-clock fallback (the DocuSeal anti-pattern). Verification that cannot parse fails, it does not pass.
- Kernel = pure value objects + ports. No I/O, no PDF bytes, no vendor SDKs. Engines implement the ports in their own packages, so this package's zero-dep guarantee holds.
- One decline kills a request. Re-negotiation is a NEW request — the declined trail stays intact as evidence.
- Identity is a bridge, not a feature.
IdentityBridgemirrors@classytic/payee'sComplianceBridge(start → webhook/poll → decision) so one eKYC engine gates both payability and signing.
Roadmap (tech phases)
- P1 (this package) — lifecycle + evidence + ports. Zero-dep, host-composable today.
- P2 — crypto engine (
@classytic/esign-pkior/pkisubpath): PKCS#12 load, CMS (PKCS#7 detached) over PDF ByteRange (PAdES baseline), fail-closed RFC 3161 TSA client, verification. Self-signed org chain (integrity seal) + CA-issued P12 (legal validity). - P3 —
@classytic/arc-esign(arc-ecosystem): signature-request REST resources composingwithApprovalChain(who/order), arc-notifications (invites), mongokit persistence, evidence chain on every event. - P4 — identity engine + country packs:
@classytic/identity(govt-ID / NID lookup, doc OCR port, liveness port — satisfies bothIdentityBridgeand payee'sComplianceBridge);esign-bdcountry pack (CCA-licensed CA integrations — thebd-taxjurisdiction-pack template). - P5 — product: multi-tenant signing portal (host app) + RA/partner integrations with licensed CAs.
Legal note (Bangladesh)
A signature from a self-signed credential is an integrity seal with contract-law weight between consenting parties — it carries no statutory presumption under the ICT Act 2006. Statutory digital signatures require certificates issued by a CCA-licensed Certifying Authority. This kernel is deliberately CA-agnostic: SigningCredential.trustLevel distinguishes the two, and licensed-CA integration arrives via CertificateIssuer bridges (P4). Verify current licensing rules with the CCA — capital, facility-audit, and CPS requirements apply to becoming a CA.
License
MIT © Classytic
Trademark
MIT-licensed code. "Classytic"/"arc" names + logos are trademarks of Classytic LLC — see TRADEMARK.md.
