@certysign/sdk 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@certysign/sdk",
3
- "version": "1.0.0",
4
- "description": "Official Node.js SDK for CertySign — digital signing, X.509 certificates, and PKI services",
3
+ "version": "2.0.0",
4
+ "description": "Official Node.js SDK for CertySign — hash-based digital signing, X.509 certificates, and PKI services. Documents never leave your system.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
7
+ "files": [
8
+ "src/",
9
+ "README.md"
10
+ ],
7
11
  "scripts": {
8
12
  "test": "jest --coverage",
9
13
  "lint": "eslint src/**/*.js",
@@ -16,17 +20,21 @@
16
20
  "x509",
17
21
  "pdf-signing",
18
22
  "document-signing",
23
+ "hash-based-signing",
19
24
  "kenya",
20
- "pades"
25
+ "pades",
26
+ "xmldsig",
27
+ "otp"
21
28
  ],
22
- "author": "CertySign Limited <sdk@certysign.com>",
29
+ "author": "CertySign Limited <sdk@certysign.io>",
23
30
  "license": "MIT",
24
31
  "engines": {
25
32
  "node": ">=18.0.0"
26
33
  },
27
34
  "dependencies": {
28
35
  "axios": "^1.6.0",
29
- "form-data": "^4.0.0"
36
+ "form-data": "^4.0.0",
37
+ "pdf-lib": "^1.17.1"
30
38
  },
31
39
  "devDependencies": {
32
40
  "jest": "^29.7.0"
@@ -35,7 +43,7 @@
35
43
  "type": "git",
36
44
  "url": "git+https://github.com/certysign/sdk-node.git"
37
45
  },
38
- "homepage": "https://docs.certysign.com/sdk",
46
+ "homepage": "https://docs.certysign.io/sdk",
39
47
  "bugs": {
40
48
  "url": "https://github.com/certysign/sdk-node/issues"
41
49
  },
package/src/index.js CHANGED
@@ -18,39 +18,59 @@
18
18
  'use strict';
19
19
 
20
20
  const { HttpClient, CertySignError } = require('./lib/HttpClient');
21
- const { SigningResource } = require('./lib/SigningResource');
22
- const { CertificateResource } = require('./lib/CertificateResource');
23
- const { PkiResource } = require('./lib/PkiResource');
24
- const { EnvelopeResource } = require('./lib/EnvelopeResource');
21
+ const { SigningResource } = require('./lib/SigningResource');
22
+ const { HashSigningResource } = require('./lib/HashSigningResource');
23
+ const { CertificateResource } = require('./lib/CertificateResource');
24
+ const { PkiResource } = require('./lib/PkiResource');
25
+ const { EnvelopeResource } = require('./lib/EnvelopeResource');
26
+ const { SigningSessionResource } = require('./lib/SigningSessionResource');
27
+ const { DashboardResource } = require('./lib/DashboardResource');
28
+ const { DocumentHasher } = require('./lib/DocumentHasher');
29
+ const { SignatureEmbedder } = require('./lib/SignatureEmbedder');
25
30
 
26
31
  /**
27
32
  * CertySign API client.
28
33
  *
29
34
  * Resources are accessed as properties:
30
- * - client.sign — document signing (quickSign, batchSign, verify)
31
- * - client.certificates — X.509 certificate lifecycle (issue, verify, status)
35
+ * - client.sign — hash-based document signing (documents stay local)
36
+ * - client.sessions — multi-recipient signing sessions with OTP verification
37
+ * - client.dashboard — SDK usage analytics (stats, recipients, documents)
38
+ * - client.certificates — X.509 certificate lifecycle (issue, verify, status, getActive)
32
39
  * - client.pki — PKI infrastructure (CRL, OCSP, CA chain, info)
33
40
  * - client.envelopes — envelope management (create, upload, send, sign, audit)
41
+ * - client.hasher — local document hashing utility
42
+ * - client.embedder — local signature embedding (PDF, XML, JSON)
43
+ * - client.legacySign — legacy file-upload signing (deprecated)
34
44
  *
35
- * @example
45
+ * @example Hash-based signing (documents never leave your system)
36
46
  * const { CertySignClient } = require('@certysign/sdk');
37
47
  *
38
48
  * const client = new CertySignClient({
39
49
  * publicKey: process.env.CERTYSIGN_PUBLIC_KEY,
40
50
  * secretKey: process.env.CERTYSIGN_SECRET_KEY,
41
- * environment: 'production' // or 'staging', 'development'
51
+ * environment: 'production'
42
52
  * });
43
53
  *
44
- * // Sign a document
45
- * const result = await client.sign.quickSign({
46
- * document: fs.readFileSync('./claim.pdf'),
47
- * filename: 'claim.pdf',
48
- * signerName: 'Dr. Amina Okonkwo',
49
- * reason: 'Health records approval'
54
+ * // 1. Hash locally → sign remotely → embed locally
55
+ * const result = await client.sign.hashAndSign({
56
+ * document: fs.readFileSync('./contract.pdf'),
57
+ * fileName: 'contract.pdf',
58
+ * reason: 'Contract approval'
50
59
  * });
51
60
  *
52
- * console.log(result.data.envelopeId);
53
- * console.log(result.data.certificate.serialNumber);
61
+ * // 2. Embed signature into the PDF on your system
62
+ * const signedPdf = await client.embedder.embedInPdf(
63
+ * fs.readFileSync('./contract.pdf'),
64
+ * {
65
+ * signature: result.data.signature,
66
+ * certificate: result.data.certificate,
67
+ * chain: result.data.chain,
68
+ * signerName: 'Dr. Amina Okonkwo',
69
+ * reason: 'Contract approval',
70
+ * certSerialNumber: result.data.certSerialNumber
71
+ * }
72
+ * );
73
+ * fs.writeFileSync('./contract-signed.pdf', signedPdf);
54
74
  */
55
75
  class CertySignClient {
56
76
  /**
@@ -90,10 +110,15 @@ class CertySignClient {
90
110
  });
91
111
 
92
112
  // ── Resource objects ──
93
- this.sign = new SigningResource(this._http);
113
+ this.sign = new HashSigningResource(this._http); // Hash-based signing (documents stay local)
114
+ this.legacySign = new SigningResource(this._http); // Legacy file-upload signing
94
115
  this.certificates = new CertificateResource(this._http);
95
116
  this.pki = new PkiResource(this._http);
96
117
  this.envelopes = new EnvelopeResource(this._http);
118
+ this.sessions = new SigningSessionResource(this._http); // Multi-recipient signing sessions
119
+ this.dashboard = new DashboardResource(this._http); // SDK usage analytics
120
+ this.hasher = new DocumentHasher(); // Local document hashing
121
+ this.embedder = new SignatureEmbedder(); // Local signature embedding
97
122
 
98
123
  this.publicKey = publicKey;
99
124
  this.environment = environment;
@@ -106,8 +131,8 @@ class CertySignClient {
106
131
  */
107
132
  static get BASE_URLS() {
108
133
  return {
109
- production: 'https://api.certysign.com',
110
- staging: 'https://api-staging.certysign.com',
134
+ production: 'https://core.certysign.io',
135
+ staging: 'https://service.certysign.io',
111
136
  development: 'http://localhost:8000',
112
137
  test: 'http://localhost:8000'
113
138
  };
@@ -157,5 +182,15 @@ class CertySignClient {
157
182
 
158
183
  module.exports = {
159
184
  CertySignClient,
160
- CertySignError
185
+ CertySignError,
186
+ DocumentHasher,
187
+ SignatureEmbedder,
188
+ HashSigningResource,
189
+ SigningSessionResource,
190
+ DashboardResource,
191
+ // Legacy exports
192
+ SigningResource,
193
+ CertificateResource,
194
+ PkiResource,
195
+ EnvelopeResource
161
196
  };
@@ -26,9 +26,9 @@ class CertificateResource {
26
26
  *
27
27
  * The certificate is bound to the subscriber's organisation and the specific
28
28
  * document. It includes:
29
- * - CRL Distribution Point → https://pki.certysign.com/crl/intermediate.crl
30
- * - OCSP AIA → https://pki.certysign.com/ocsp
31
- * - CA Issuers AIA → https://pki.certysign.com/certs/intermediate.crt
29
+ * - CRL Distribution Point → https://pki.certysign.io/crl/intermediate.crl
30
+ * - OCSP AIA → https://pki.certysign.io/ocsp
31
+ * - CA Issuers AIA → https://pki.certysign.io/certs/intermediate.crt
32
32
  *
33
33
  * The private key is returned ONCE in the response (PEM). CertySign does not
34
34
  * retain the private key after issuance.
@@ -122,6 +122,27 @@ class CertificateResource {
122
122
  if (!serialNumber) throw new Error('certificates.status: serialNumber is required');
123
123
  return this._http.get(`/sdk/v1/certificates/${encodeURIComponent(serialNumber)}/status`);
124
124
  }
125
+
126
+ // ── Active Certificate ─────────────────────────────────────────────────────
127
+
128
+ /**
129
+ * Get the tenant's active signing certificate.
130
+ * The certificate is resolved based on the API keys used for authentication.
131
+ *
132
+ * Returns the PEM certificate, chain, serial number, fingerprint,
133
+ * and validity information.
134
+ *
135
+ * @returns {Promise<Object>}
136
+ *
137
+ * @example
138
+ * const { data } = await client.certificates.getActive();
139
+ * console.log(data.certSerialNumber);
140
+ * console.log(data.certificate); // PEM
141
+ * console.log(data.validUntil);
142
+ */
143
+ getActive() {
144
+ return this._http.get('/sdk/v1/certificates/active');
145
+ }
125
146
  }
126
147
 
127
148
  /**
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @fileoverview DashboardResource — SDK usage analytics
3
+ *
4
+ * Access dashboard statistics for your SDK-based signing operations:
5
+ * - Documents signed (total, today, this month)
6
+ * - Unique recipients across all signing sessions
7
+ * - Success / failure rates
8
+ * - Daily signing trends
9
+ * - Signed document listing with recipient details
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ class DashboardResource {
15
+ /** @param {import('./HttpClient').HttpClient} http */
16
+ constructor(http) {
17
+ this._http = http;
18
+ }
19
+
20
+ /**
21
+ * Get aggregate statistics for SDK signing activity.
22
+ *
23
+ * @param {Object} [options]
24
+ * @param {string} [options.from] - ISO date — start of range (default: 30 days ago)
25
+ * @param {string} [options.to] - ISO date — end of range (default: now)
26
+ * @returns {Promise<Object>}
27
+ *
28
+ * @example
29
+ * const { data } = await client.dashboard.getStats();
30
+ * console.log('Documents signed today:', data.documentsSignedToday);
31
+ * console.log('Unique recipients:', data.uniqueRecipientsCount);
32
+ * console.log('Success rate:', data.successRate + '%');
33
+ */
34
+ getStats(options = {}) {
35
+ const params = {};
36
+ if (options.from) params.from = options.from;
37
+ if (options.to) params.to = options.to;
38
+
39
+ return this._http.get('/sdk/v1/dashboard/stats', { params });
40
+ }
41
+
42
+ /**
43
+ * List unique recipients across all signing sessions.
44
+ *
45
+ * @param {Object} [options]
46
+ * @param {number} [options.page] - Page number (default: 1)
47
+ * @param {number} [options.limit] - Results per page (default: 50)
48
+ * @param {string} [options.search] - Search by email or name
49
+ * @returns {Promise<Object>}
50
+ *
51
+ * @example
52
+ * const { data } = await client.dashboard.getRecipients({ search: 'ceo' });
53
+ * for (const r of data.recipients) {
54
+ * console.log(`${r.email}: signed ${r.signedSessions} sessions`);
55
+ * }
56
+ */
57
+ getRecipients(options = {}) {
58
+ const params = {};
59
+ if (options.page) params.page = options.page;
60
+ if (options.limit) params.limit = options.limit;
61
+ if (options.search) params.search = options.search;
62
+
63
+ return this._http.get('/sdk/v1/dashboard/recipients', { params });
64
+ }
65
+
66
+ /**
67
+ * List documents across all signing sessions with signature details.
68
+ *
69
+ * @param {Object} [options]
70
+ * @param {number} [options.page] - Page number (default: 1)
71
+ * @param {number} [options.limit] - Results per page (default: 20)
72
+ * @param {string} [options.status] - Filter by session status: 'active' | 'completed' | 'expired'
73
+ * @returns {Promise<Object>}
74
+ *
75
+ * @example
76
+ * const { data } = await client.dashboard.getDocuments({ status: 'completed' });
77
+ * for (const doc of data.documents) {
78
+ * console.log(`${doc.fileName}: ${doc.signatureCount} signatures`);
79
+ * }
80
+ */
81
+ getDocuments(options = {}) {
82
+ const params = {};
83
+ if (options.page) params.page = options.page;
84
+ if (options.limit) params.limit = options.limit;
85
+ if (options.status) params.status = options.status;
86
+
87
+ return this._http.get('/sdk/v1/dashboard/documents', { params });
88
+ }
89
+ }
90
+
91
+ module.exports = { DashboardResource };
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @fileoverview DocumentHasher — local document hashing
3
+ *
4
+ * Hashes documents on the subscriber's system so the raw document
5
+ * NEVER leaves their infrastructure. Only the hash is sent to CertySign.
6
+ *
7
+ * Supports: SHA-256, SHA-384, SHA-512
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const crypto = require('crypto');
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ const SUPPORTED_ALGORITHMS = ['sha256', 'sha384', 'sha512'];
17
+
18
+ class DocumentHasher {
19
+ /**
20
+ * @param {Object} [options]
21
+ * @param {string} [options.algorithm='sha256'] - Hash algorithm
22
+ */
23
+ constructor(options = {}) {
24
+ this.algorithm = (options.algorithm || 'sha256').toLowerCase();
25
+ if (!SUPPORTED_ALGORITHMS.includes(this.algorithm)) {
26
+ throw new Error(`Unsupported algorithm: ${this.algorithm}. Use: ${SUPPORTED_ALGORITHMS.join(', ')}`);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Hash a document from a Buffer or string.
32
+ *
33
+ * @param {Buffer|string} data - Document contents
34
+ * @param {string} [algorithm] - Override default algorithm
35
+ * @returns {{ hash: string, algorithm: string, size: number }}
36
+ *
37
+ * @example
38
+ * const hasher = new DocumentHasher();
39
+ * const result = hasher.hash(fs.readFileSync('./contract.pdf'));
40
+ * console.log(result.hash); // "a1b2c3..."
41
+ */
42
+ hash(data, algorithm) {
43
+ const algo = (algorithm || this.algorithm).toLowerCase();
44
+ if (!SUPPORTED_ALGORITHMS.includes(algo)) {
45
+ throw new Error(`Unsupported algorithm: ${algo}`);
46
+ }
47
+
48
+ const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
49
+ const hash = crypto.createHash(algo).update(buf).digest('hex');
50
+
51
+ return { hash, algorithm: algo, size: buf.length };
52
+ }
53
+
54
+ /**
55
+ * Hash a document from a file path.
56
+ *
57
+ * Uses streaming to handle large files without loading the entire
58
+ * file into memory.
59
+ *
60
+ * @param {string} filePath - Absolute or relative file path
61
+ * @param {string} [algorithm] - Override default algorithm
62
+ * @returns {Promise<{ hash: string, algorithm: string, size: number, fileName: string }>}
63
+ *
64
+ * @example
65
+ * const hasher = new DocumentHasher();
66
+ * const result = await hasher.hashFile('./contract.pdf');
67
+ * console.log(result.hash);
68
+ * console.log(result.fileName); // "contract.pdf"
69
+ */
70
+ hashFile(filePath, algorithm) {
71
+ const algo = (algorithm || this.algorithm).toLowerCase();
72
+ if (!SUPPORTED_ALGORITHMS.includes(algo)) {
73
+ return Promise.reject(new Error(`Unsupported algorithm: ${algo}`));
74
+ }
75
+
76
+ return new Promise((resolve, reject) => {
77
+ const hash = crypto.createHash(algo);
78
+ let size = 0;
79
+
80
+ const stream = fs.createReadStream(filePath);
81
+ stream.on('data', (chunk) => {
82
+ hash.update(chunk);
83
+ size += chunk.length;
84
+ });
85
+ stream.on('end', () => {
86
+ resolve({
87
+ hash: hash.digest('hex'),
88
+ algorithm: algo,
89
+ size,
90
+ fileName: path.basename(filePath)
91
+ });
92
+ });
93
+ stream.on('error', reject);
94
+ });
95
+ }
96
+
97
+ /**
98
+ * Hash multiple documents (Buffers).
99
+ *
100
+ * @param {{ data: Buffer, fileName: string }[]} documents
101
+ * @param {string} [algorithm]
102
+ * @returns {{ hash: string, algorithm: string, size: number, fileName: string }[]}
103
+ */
104
+ hashMany(documents, algorithm) {
105
+ return documents.map(doc => {
106
+ const result = this.hash(doc.data, algorithm);
107
+ return { ...result, fileName: doc.fileName };
108
+ });
109
+ }
110
+
111
+ /**
112
+ * Hash multiple files by path.
113
+ *
114
+ * @param {string[]} filePaths
115
+ * @param {string} [algorithm]
116
+ * @returns {Promise<{ hash: string, algorithm: string, size: number, fileName: string }[]>}
117
+ */
118
+ hashFiles(filePaths, algorithm) {
119
+ return Promise.all(filePaths.map(fp => this.hashFile(fp, algorithm)));
120
+ }
121
+ }
122
+
123
+ module.exports = { DocumentHasher };
@@ -0,0 +1,220 @@
1
+ /**
2
+ * @fileoverview HashSigningResource — hash-based document signing
3
+ *
4
+ * Documents NEVER leave the subscriber's system.
5
+ * Flow: hash locally → send hash to CertySign → receive signature → embed locally.
6
+ *
7
+ * Covers:
8
+ * - hashAndSign() Hash a document and sign in one call
9
+ * - signHash() Sign a pre-computed hash
10
+ * - batchHashAndSign() Hash and sign multiple documents
11
+ * - batchSignHashes() Sign multiple pre-computed hashes
12
+ * - verifyById() Verify an envelope's signatures
13
+ */
14
+
15
+ 'use strict';
16
+
17
+ const { DocumentHasher } = require('./DocumentHasher');
18
+
19
+ class HashSigningResource {
20
+ /**
21
+ * @param {import('./HttpClient').HttpClient} http
22
+ */
23
+ constructor(http) {
24
+ this._http = http;
25
+ this._hasher = new DocumentHasher();
26
+ }
27
+
28
+ // ── Hash + Sign (single document) ─────────────────────────────────────────
29
+
30
+ /**
31
+ * Hash a document locally and send the hash to CertySign for signing.
32
+ * The document never leaves your system.
33
+ *
34
+ * @param {HashAndSignOptions} options
35
+ * @returns {Promise<HashSignResult>}
36
+ *
37
+ * @example
38
+ * const result = await client.sign.hashAndSign({
39
+ * document: fs.readFileSync('./contract.pdf'),
40
+ * fileName: 'contract.pdf',
41
+ * reason: 'Contract approval',
42
+ * location: 'Nairobi, Kenya'
43
+ * });
44
+ *
45
+ * console.log(result.data.signature); // Base64 CMS/PKCS#7
46
+ * console.log(result.data.certificate); // PEM certificate
47
+ * console.log(result.data.documentHash); // SHA-256 hex
48
+ */
49
+ async hashAndSign(options) {
50
+ const {
51
+ document,
52
+ fileName = 'document.pdf',
53
+ reason = 'Digital signature',
54
+ location = 'Nairobi, Kenya',
55
+ hashAlgorithm = 'sha256',
56
+ metadata = {}
57
+ } = options;
58
+
59
+ if (!document) throw new Error('hashAndSign: document (Buffer) is required');
60
+
61
+ // Hash locally — document stays on subscriber system
62
+ const { hash } = this._hasher.hash(document, hashAlgorithm);
63
+
64
+ // Send only the hash to CertySign
65
+ return this._http.post('/sdk/v1/sign/hash', {
66
+ data: {
67
+ documentHash: hash,
68
+ hashAlgorithm,
69
+ fileName,
70
+ reason,
71
+ location,
72
+ metadata
73
+ }
74
+ });
75
+ }
76
+
77
+ // ── Sign pre-computed hash ─────────────────────────────────────────────────
78
+
79
+ /**
80
+ * Sign a pre-computed document hash.
81
+ * Use this when you've already computed the hash yourself.
82
+ *
83
+ * @param {SignHashOptions} options
84
+ * @returns {Promise<HashSignResult>}
85
+ *
86
+ * @example
87
+ * const hash = crypto.createHash('sha256').update(pdfBuffer).digest('hex');
88
+ * const result = await client.sign.signHash({
89
+ * documentHash: hash,
90
+ * hashAlgorithm: 'sha256',
91
+ * fileName: 'invoice.pdf',
92
+ * reason: 'Invoice approval'
93
+ * });
94
+ */
95
+ async signHash(options) {
96
+ const {
97
+ documentHash,
98
+ hashAlgorithm = 'sha256',
99
+ fileName,
100
+ reason = 'Digital signature',
101
+ location = 'Nairobi, Kenya',
102
+ metadata = {}
103
+ } = options;
104
+
105
+ if (!documentHash) throw new Error('signHash: documentHash is required');
106
+
107
+ return this._http.post('/sdk/v1/sign/hash', {
108
+ data: { documentHash, hashAlgorithm, fileName, reason, location, metadata }
109
+ });
110
+ }
111
+
112
+ // ── Batch hash + sign ──────────────────────────────────────────────────────
113
+
114
+ /**
115
+ * Hash and sign multiple documents in one API call.
116
+ * All documents are hashed locally — none leave your system.
117
+ *
118
+ * @param {BatchHashAndSignOptions} options
119
+ * @returns {Promise<BatchHashSignResult>}
120
+ *
121
+ * @example
122
+ * const result = await client.sign.batchHashAndSign({
123
+ * documents: [
124
+ * { data: fs.readFileSync('./doc1.pdf'), fileName: 'doc1.pdf' },
125
+ * { data: fs.readFileSync('./doc2.pdf'), fileName: 'doc2.pdf' }
126
+ * ],
127
+ * reason: 'Batch approval'
128
+ * });
129
+ */
130
+ async batchHashAndSign(options) {
131
+ const {
132
+ documents,
133
+ reason = 'Batch digital signature',
134
+ hashAlgorithm = 'sha256',
135
+ metadata = {}
136
+ } = options;
137
+
138
+ if (!documents?.length) throw new Error('batchHashAndSign: documents array is required');
139
+
140
+ // Hash all documents locally
141
+ const hashed = documents.map(doc => {
142
+ const { hash } = this._hasher.hash(doc.data, hashAlgorithm);
143
+ return {
144
+ documentHash: hash,
145
+ hashAlgorithm,
146
+ fileName: doc.fileName || 'document.pdf'
147
+ };
148
+ });
149
+
150
+ return this._http.post('/sdk/v1/sign/hash/batch', {
151
+ data: { documents: hashed, reason, metadata }
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Sign multiple pre-computed hashes in one API call.
157
+ *
158
+ * @param {BatchSignHashesOptions} options
159
+ * @returns {Promise<BatchHashSignResult>}
160
+ */
161
+ async batchSignHashes(options) {
162
+ const { documents, reason = 'Batch digital signature', metadata = {} } = options;
163
+
164
+ if (!documents?.length) throw new Error('batchSignHashes: documents array is required');
165
+
166
+ return this._http.post('/sdk/v1/sign/hash/batch', {
167
+ data: { documents, reason, metadata }
168
+ });
169
+ }
170
+
171
+ // ── Verify ─────────────────────────────────────────────────────────────────
172
+
173
+ /**
174
+ * Verify the signature of a previously signed envelope.
175
+ *
176
+ * @param {string} envelopeId
177
+ * @returns {Promise<Object>}
178
+ */
179
+ verifyById(envelopeId) {
180
+ if (!envelopeId) throw new Error('verifyById: envelopeId is required');
181
+ return this._http.get(`/sdk/v1/verify/${encodeURIComponent(envelopeId)}`);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * @typedef {Object} HashAndSignOptions
187
+ * @property {Buffer} document - Document contents (stays local)
188
+ * @property {string} [fileName] - File name
189
+ * @property {string} [reason] - Signing reason
190
+ * @property {string} [location] - Signing location
191
+ * @property {string} [hashAlgorithm] - sha256 | sha384 | sha512
192
+ * @property {Object} [metadata] - Custom key/value metadata
193
+ */
194
+
195
+ /**
196
+ * @typedef {Object} SignHashOptions
197
+ * @property {string} documentHash - Hex-encoded hash
198
+ * @property {string} [hashAlgorithm] - sha256 | sha384 | sha512
199
+ * @property {string} [fileName]
200
+ * @property {string} [reason]
201
+ * @property {string} [location]
202
+ * @property {Object} [metadata]
203
+ */
204
+
205
+ /**
206
+ * @typedef {Object} BatchHashAndSignOptions
207
+ * @property {{ data: Buffer, fileName?: string }[]} documents
208
+ * @property {string} [reason]
209
+ * @property {string} [hashAlgorithm]
210
+ * @property {Object} [metadata]
211
+ */
212
+
213
+ /**
214
+ * @typedef {Object} BatchSignHashesOptions
215
+ * @property {{ documentHash: string, hashAlgorithm?: string, fileName?: string }[]} documents
216
+ * @property {string} [reason]
217
+ * @property {Object} [metadata]
218
+ */
219
+
220
+ module.exports = { HashSigningResource };
@@ -15,7 +15,7 @@ const FormData = require('form-data');
15
15
  const crypto = require('crypto');
16
16
 
17
17
  /** Default base URL — override per environment */
18
- const DEFAULT_BASE_URL = 'https://api.certysign.com';
18
+ const DEFAULT_BASE_URL = 'https://core.certysign.io';
19
19
 
20
20
  /** Statuses that should trigger a retry */
21
21
  const RETRYABLE_STATUS = new Set([429, 502, 503, 504]);