@certysign/sdk 2.4.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +355 -1
- package/package.json +55 -54
- package/src/index.js +372 -214
- package/src/lib/BillingResource.js +90 -0
- package/src/lib/EnvelopeResource.js +306 -249
- package/src/lib/HashSigningResource.js +9 -2
- package/src/lib/HttpClient.js +219 -198
- package/src/lib/IdentityResource.js +153 -0
- package/src/lib/SignerResource.js +120 -0
- package/src/lib/SigningResource.js +11 -7
- package/src/lib/WebhookResource.js +88 -0
package/README.md
CHANGED
|
@@ -19,10 +19,15 @@ Official Node.js SDK for **CertySign Trust Services** — hash-based digital sig
|
|
|
19
19
|
- [client.hasher — Local Document Hashing](#clienthasher--local-document-hashing)
|
|
20
20
|
- [client.embedder — Local Signature Embedding](#clientembedder--local-signature-embedding)
|
|
21
21
|
- [client.dashboard — SDK Analytics](#clientdashboard--sdk-analytics)
|
|
22
|
+
- [client.identity — Identity Verification](#clientidentity--identity-verification)
|
|
22
23
|
- [client.certificates — X.509 Certificate Management](#clientcertificates--x509-certificate-management)
|
|
23
24
|
- [client.pki — PKI Infrastructure](#clientpki--pki-infrastructure)
|
|
24
25
|
- [client.envelopes — Envelope Management](#clientenvelopes--envelope-management)
|
|
25
|
-
- [client.legacySign — Legacy Document Signing](#clientlegacysign--legacy-document-signing)
|
|
26
|
+
- [client.legacySign — Legacy Document Signing](#clientlegacysign--legacy-document-signing)
|
|
27
|
+
- [client.webhooks — Event Notifications](#clientwebhooks--event-notifications)
|
|
28
|
+
- [client.billing — Wallet, Quotes and Pricing](#clientbilling--wallet-quotes-and-pricing)
|
|
29
|
+
- [client.signers — Sponsored Signer Certificates](#clientsigners--sponsored-signer-certificates)
|
|
30
|
+
- [client.request — Any Endpoint](#clientrequest--any-endpoint)
|
|
26
31
|
- [Complete Examples](#complete-examples)
|
|
27
32
|
- [Error Handling](#error-handling)
|
|
28
33
|
- [Rate Limiting](#rate-limiting)
|
|
@@ -862,6 +867,81 @@ const { data } = await client.dashboard.getDocuments({
|
|
|
862
867
|
|
|
863
868
|
---
|
|
864
869
|
|
|
870
|
+
### `client.identity` — Identity Verification
|
|
871
|
+
|
|
872
|
+
Verify a national ID against the issuing authority (IPRS for Kenya) and get the
|
|
873
|
+
biographic record — the same pipeline CertySign uses to onboard its own signers.
|
|
874
|
+
|
|
875
|
+
**Registry-first:** an ID already verified anywhere on the CertySign network is served
|
|
876
|
+
from our registry (`source: 'registry'`) with no authority call. A *rejected* ID is
|
|
877
|
+
cached briefly too, so repeated lookups of the same bad number don't incur repeated
|
|
878
|
+
charges. Pass `forceRefresh: true` to bypass both.
|
|
879
|
+
|
|
880
|
+
Requires the **`identity:verify`** scope, which is **not granted by default** — enable it
|
|
881
|
+
under *Settings → Security → SDK API Keys → Permissions*.
|
|
882
|
+
|
|
883
|
+
> **Consent is mandatory.** This processes another person's personal data, so
|
|
884
|
+
> `consent.obtained: true` is required — the SDK throws *before* making the call if it's
|
|
885
|
+
> missing. Your attestation, API key and IP are written to your tenant's audit trail on
|
|
886
|
+
> every call, evidencing a lawful basis under the Kenya Data Protection Act 2019.
|
|
887
|
+
> Store the returned `identityReference` instead of the raw ID number — the full number
|
|
888
|
+
> is never returned to you.
|
|
889
|
+
|
|
890
|
+
#### `verify(params)` — Verify a national ID
|
|
891
|
+
|
|
892
|
+
```js
|
|
893
|
+
const { data } = await client.identity.verify({
|
|
894
|
+
country: 'KE',
|
|
895
|
+
idNumber: '12345678',
|
|
896
|
+
idType: 'NATIONAL_ID', // optional — this is the default
|
|
897
|
+
consent: {
|
|
898
|
+
obtained: true, // REQUIRED
|
|
899
|
+
reference: 'loan-app-8821', // optional — your own consent record id
|
|
900
|
+
purpose: 'KYC onboarding' // optional
|
|
901
|
+
},
|
|
902
|
+
// Optional cross-check hints: firstName, lastName, dob
|
|
903
|
+
// forceRefresh: true // skip caches, go straight to the authority
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
// data.verified — true when the authority confirmed the ID
|
|
907
|
+
// data.decision — 'verified' | 'rejected' | 'provisional' | 'unknown'
|
|
908
|
+
// data.identityReference — privacy-preserving reference; store THIS
|
|
909
|
+
// data.idLast4 — last 4 digits only
|
|
910
|
+
// data.person — fullName, firstName, middleName, lastName,
|
|
911
|
+
// dob, gender, nationality
|
|
912
|
+
// data.source — 'registry' (cached) | 'authority' (fresh lookup)
|
|
913
|
+
// data.cached — true when served without an authority call
|
|
914
|
+
// data.resultCode — authority code, e.g. '1012' = valid ID
|
|
915
|
+
// data.checkedAt — ISO timestamp
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
#### `isVerified(params)` — Boolean convenience wrapper
|
|
919
|
+
|
|
920
|
+
```js
|
|
921
|
+
const ok = await client.identity.isVerified({
|
|
922
|
+
country: 'KE', idNumber: '12345678',
|
|
923
|
+
consent: { obtained: true, purpose: 'KYC onboarding' }
|
|
924
|
+
});
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
> A thrown error means **"we couldn't check"**, which is *not* the same as
|
|
928
|
+
> **"not verified"**. Never collapse the two — treat an error as retry/escalate,
|
|
929
|
+
> not as a failed identity.
|
|
930
|
+
|
|
931
|
+
#### Errors
|
|
932
|
+
|
|
933
|
+
| Code | HTTP | Meaning |
|
|
934
|
+
|---|---|---|
|
|
935
|
+
| `CONSENT_REQUIRED` | 403 | Consent attestation missing |
|
|
936
|
+
| `INSUFFICIENT_BALANCE` | 402 | Checked *before* any authority call — you're never charged for a lookup you couldn't afford |
|
|
937
|
+
| `COUNTRY_NOT_SUPPORTED` / `ID_TYPE_NOT_SUPPORTED` | 422 | Only `KE` / `NATIONAL_ID` today |
|
|
938
|
+
| `VERIFICATION_UNAVAILABLE` | 502 | Authority unreachable — not billed, retry later |
|
|
939
|
+
|
|
940
|
+
**Billing:** one `ekyc_check` per distinct ID per day. A *negative* result is billable
|
|
941
|
+
(the authority was queried); an *outage* is never billed.
|
|
942
|
+
|
|
943
|
+
---
|
|
944
|
+
|
|
865
945
|
### `client.certificates` — X.509 Certificate Management
|
|
866
946
|
|
|
867
947
|
#### `getActive()` — Get your tenant's active signing certificate
|
|
@@ -1041,6 +1121,272 @@ Legacy methods: `quickSign()`, `batchSign()`, `verifyById()`, `verifyDocument()`
|
|
|
1041
1121
|
|
|
1042
1122
|
---
|
|
1043
1123
|
|
|
1124
|
+
### `client.webhooks` — Event Notifications
|
|
1125
|
+
|
|
1126
|
+
Register an endpoint and CertySign calls you when something finishes, instead of you
|
|
1127
|
+
asking repeatedly. Requires the `webhook:manage` permission on your API key.
|
|
1128
|
+
**Deliveries are not charged**, and neither are the status endpoints.
|
|
1129
|
+
|
|
1130
|
+
#### `create({ url, events, description? })` — Register an endpoint
|
|
1131
|
+
|
|
1132
|
+
```js
|
|
1133
|
+
const { data } = await client.webhooks.create({
|
|
1134
|
+
url: 'https://api.example.com/hooks/certysign',
|
|
1135
|
+
events: ['envelope.completed', 'envelope.declined'], // omit for all events
|
|
1136
|
+
description: 'Production order pipeline',
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
// data.secret is returned ONCE and is never readable again. Store it now.
|
|
1140
|
+
process.env.CERTYSIGN_WEBHOOK_SECRET = data.secret;
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
Events: `envelope.sent`, `envelope.viewed`, `envelope.signed` (per signature),
|
|
1144
|
+
`envelope.completed`, `envelope.declined`, `envelope.voided`, `envelope.expired`,
|
|
1145
|
+
`signing_session.completed`, `sponsorship.created`,
|
|
1146
|
+
`sponsorship.certificate_issued`, `sponsorship.verification_rejected`,
|
|
1147
|
+
`sponsorship.failed`, `webhook.test`.
|
|
1148
|
+
|
|
1149
|
+
#### `list()`, `remove(webhookId)`, `test(webhookId)`
|
|
1150
|
+
|
|
1151
|
+
```js
|
|
1152
|
+
const { data } = await client.webhooks.list();
|
|
1153
|
+
await client.webhooks.test(data.webhooks[0].webhookId); // sends a webhook.test delivery
|
|
1154
|
+
await client.webhooks.remove(data.webhooks[0].webhookId);
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
#### `deliveries({ webhookId?, status?, limit? })`, `redeliver(deliveryId)`
|
|
1158
|
+
|
|
1159
|
+
```js
|
|
1160
|
+
// What did we send, and what did your endpoint say?
|
|
1161
|
+
const { data } = await client.webhooks.deliveries({ status: 'failed', limit: 50 });
|
|
1162
|
+
for (const d of data.deliveries) {
|
|
1163
|
+
console.log(d.event, d.responseStatus, d.error);
|
|
1164
|
+
await client.webhooks.redeliver(d.deliveryId);
|
|
1165
|
+
}
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
#### Verifying the signature
|
|
1169
|
+
|
|
1170
|
+
Use the built-in helper. It is timing-safe, enforces a freshness window, and reports
|
|
1171
|
+
the two mistakes that otherwise fail silently — signing the body alone (which leaves a
|
|
1172
|
+
captured delivery replayable forever) and verifying after `JSON.parse` (which changes
|
|
1173
|
+
the bytes the signature covers).
|
|
1174
|
+
|
|
1175
|
+
```js
|
|
1176
|
+
const { CertySignClient } = require('@certysign/sdk');
|
|
1177
|
+
|
|
1178
|
+
// express.raw, NOT express.json — the signature covers the bytes as sent.
|
|
1179
|
+
app.post('/hooks/certysign', express.raw({ type: 'application/json' }), (req, res) => {
|
|
1180
|
+
const { valid, reason, event } = CertySignClient.verifyWebhookSignature({
|
|
1181
|
+
secret: process.env.CERTYSIGN_WEBHOOK_SECRET,
|
|
1182
|
+
headers: req.headers,
|
|
1183
|
+
rawBody: req.body, // Buffer or string, never a parsed object
|
|
1184
|
+
toleranceSeconds: 300, // default
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
if (!valid) return res.status(401).send(reason);
|
|
1188
|
+
|
|
1189
|
+
if (alreadyHandled(event.eventId)) return res.sendStatus(200); // at-least-once
|
|
1190
|
+
handle(event);
|
|
1191
|
+
res.sendStatus(200); // answer fast; do the work afterwards
|
|
1192
|
+
});
|
|
1193
|
+
```
|
|
1194
|
+
|
|
1195
|
+
If you would rather implement it yourself: the signature is HMAC-SHA256 over
|
|
1196
|
+
`"<timestamp>.<raw body>"` — **not the body alone** — compared timing-safely, over the
|
|
1197
|
+
raw bytes, before any JSON parsing.
|
|
1198
|
+
|
|
1199
|
+
```js
|
|
1200
|
+
const crypto = require('crypto');
|
|
1201
|
+
|
|
1202
|
+
// express.raw, NOT express.json — the signature covers the bytes as sent.
|
|
1203
|
+
app.post('/hooks/certysign', express.raw({ type: 'application/json' }), (req, res) => {
|
|
1204
|
+
const ts = req.get('X-CertySign-Timestamp');
|
|
1205
|
+
const sig = (req.get('X-CertySign-Signature') || '').replace('sha256=', '');
|
|
1206
|
+
|
|
1207
|
+
// Reject anything older than 5 minutes.
|
|
1208
|
+
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(400);
|
|
1209
|
+
|
|
1210
|
+
const expected = crypto
|
|
1211
|
+
.createHmac('sha256', process.env.CERTYSIGN_WEBHOOK_SECRET)
|
|
1212
|
+
.update(ts + '.' + req.body.toString())
|
|
1213
|
+
.digest('hex');
|
|
1214
|
+
|
|
1215
|
+
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
|
|
1216
|
+
return res.sendStatus(401);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
const event = JSON.parse(req.body.toString());
|
|
1220
|
+
if (alreadyHandled(event.eventId)) return res.sendStatus(200); // at-least-once
|
|
1221
|
+
|
|
1222
|
+
handle(event);
|
|
1223
|
+
res.sendStatus(200); // answer fast; do the work afterwards
|
|
1224
|
+
});
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
#### Delivery, retries and duplicates
|
|
1228
|
+
|
|
1229
|
+
- Respond **2xx** quickly. Anything else counts as a failure.
|
|
1230
|
+
- Retries on network errors, timeouts and 5xx: 10s, 1m, 5m, 30m, 2h, then stop.
|
|
1231
|
+
- A **4xx other than 429 is not retried** — your endpoint rejected the shape, and the
|
|
1232
|
+
same bytes would be rejected again.
|
|
1233
|
+
- Delivery is **at-least-once**. De-duplicate on `eventId`, which is stable across
|
|
1234
|
+
retries and redeliveries.
|
|
1235
|
+
- After 20 consecutive failures the webhook is disabled and the reason recorded.
|
|
1236
|
+
|
|
1237
|
+
**Webhooks do not replace polling.** A delivery you never received is unrecoverable
|
|
1238
|
+
unless you can ask for the current state, so the status endpoints remain — and they
|
|
1239
|
+
are free to call.
|
|
1240
|
+
|
|
1241
|
+
---
|
|
1242
|
+
|
|
1243
|
+
### `client.billing` — Wallet, Quotes and Pricing
|
|
1244
|
+
|
|
1245
|
+
Read-only, and every call here is free — checking a balance must never itself cost
|
|
1246
|
+
money.
|
|
1247
|
+
|
|
1248
|
+
#### `wallet()` — Token balance and standing
|
|
1249
|
+
|
|
1250
|
+
```js
|
|
1251
|
+
const { data } = await client.billing.wallet();
|
|
1252
|
+
console.log(`${data.availableBalance} ${data.currency} available`);
|
|
1253
|
+
```
|
|
1254
|
+
|
|
1255
|
+
Spend against **`availableBalance`**, not `balance`: `balance` includes tokens already
|
|
1256
|
+
reserved by operations in flight. A `status` of `'suspended'` means chargeable calls
|
|
1257
|
+
are refused even when the balance looks healthy, so check it before concluding you can
|
|
1258
|
+
afford something.
|
|
1259
|
+
|
|
1260
|
+
#### `quote({ operationType, operationSubType?, quantity?, additionalSigners? })`
|
|
1261
|
+
|
|
1262
|
+
What an operation will cost, and whether you can currently cover it. Call it **before**
|
|
1263
|
+
a large batch: one answer up front beats `INSUFFICIENT_BALANCE` halfway through, with
|
|
1264
|
+
some documents signed and charged and the rest not.
|
|
1265
|
+
|
|
1266
|
+
```js
|
|
1267
|
+
const { data } = await client.billing.quote({
|
|
1268
|
+
operationType: 'document_signing', // or 'certificate_issuance'
|
|
1269
|
+
operationSubType: 'ADVANCED', // e.g. 'ADVANCED', 'ADES'
|
|
1270
|
+
quantity: documents.length,
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
if (!data.canAfford) {
|
|
1274
|
+
throw new Error(`Need ${data.tokensTotal}, have ${data.availableBalance}`);
|
|
1275
|
+
}
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
#### `transactions({ limit?, skip?, type?, status? })`, `plan()`, `pricing()`
|
|
1279
|
+
|
|
1280
|
+
```js
|
|
1281
|
+
const { data } = await client.billing.transactions({ limit: 100, type: 'debit' });
|
|
1282
|
+
const { data: plan } = await client.billing.plan(); // your tier and its limits
|
|
1283
|
+
const { data: rates } = await client.billing.pricing(); // the full price list
|
|
1284
|
+
```
|
|
1285
|
+
|
|
1286
|
+
---
|
|
1287
|
+
|
|
1288
|
+
### `client.signers` — Sponsored Signer Certificates
|
|
1289
|
+
|
|
1290
|
+
A person cannot sign until they hold a certificate. These let you pay for one on their
|
|
1291
|
+
behalf and watch it become usable, instead of discovering at signing time that it is
|
|
1292
|
+
not there.
|
|
1293
|
+
|
|
1294
|
+
#### `signingStatus(email, { issueCompletionUrl? })` — Can this person sign yet?
|
|
1295
|
+
|
|
1296
|
+
Requires `cert:status`. Free to call, so it is safe in front of every send.
|
|
1297
|
+
|
|
1298
|
+
```js
|
|
1299
|
+
const { data } = await client.signers.signingStatus('jane@example.com');
|
|
1300
|
+
|
|
1301
|
+
if (!data.canSign) {
|
|
1302
|
+
// data.reason is NO_SIGNING_CERTIFICATE or AWAITING_IDENTITY_VERIFICATION
|
|
1303
|
+
console.log(data.reason);
|
|
1304
|
+
}
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
Worth calling **before** a batch: it turns a per-document failure — discovered halfway
|
|
1308
|
+
through, after the wallet has been charged — into one answer up front.
|
|
1309
|
+
|
|
1310
|
+
For someone stuck at `AWAITING_IDENTITY_VERIFICATION`, ask for a link you can redirect
|
|
1311
|
+
them to, so they need not hunt for the invitation email:
|
|
1312
|
+
|
|
1313
|
+
```js
|
|
1314
|
+
const { data } = await client.signers.signingStatus(email, { issueCompletionUrl: true });
|
|
1315
|
+
if (data.pendingSponsorship?.completionUrl) {
|
|
1316
|
+
return redirect(data.pendingSponsorship.completionUrl);
|
|
1317
|
+
}
|
|
1318
|
+
```
|
|
1319
|
+
|
|
1320
|
+
`issueCompletionUrl` **mints a new link and the previous one stops working**, including
|
|
1321
|
+
the one already in their inbox. Ask for it when you are about to redirect someone, not
|
|
1322
|
+
on every poll. It needs `signer:sponsor`, because minting an onboarding credential is
|
|
1323
|
+
the same class of act as sponsoring one.
|
|
1324
|
+
|
|
1325
|
+
#### `sponsor({ email, name?, tier?, restrictToSponsor? })` — Pay for their certificate
|
|
1326
|
+
|
|
1327
|
+
Requires `signer:sponsor`, a paid plan and a funded wallet.
|
|
1328
|
+
|
|
1329
|
+
```js
|
|
1330
|
+
const { data } = await client.signers.sponsor({
|
|
1331
|
+
email: 'jane@example.com',
|
|
1332
|
+
name: 'Jane Mwangi', // shown on the invitation; the certificate carries the
|
|
1333
|
+
// name on their verified ID
|
|
1334
|
+
tier: 'ades', // 'ses' | 'ades' (default) | 'qes'
|
|
1335
|
+
restrictToSponsor: true, // only signs your documents (default)
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
return redirect(data.completionUrl);
|
|
1339
|
+
```
|
|
1340
|
+
|
|
1341
|
+
They **cannot sign when this returns** — `status` is `awaiting_member` until they
|
|
1342
|
+
complete identity verification. Subscribe to `sponsorship.certificate_issued` rather
|
|
1343
|
+
than polling for it.
|
|
1344
|
+
|
|
1345
|
+
This also makes them a **member of your organisation** once the certificate issues:
|
|
1346
|
+
they get an account, appear in your member list, and their certificate falls under your
|
|
1347
|
+
governance.
|
|
1348
|
+
|
|
1349
|
+
`restrictToSponsor: false` gives them a certificate usable anywhere, including with
|
|
1350
|
+
your competitors. That is a deliberate choice, not a default.
|
|
1351
|
+
|
|
1352
|
+
#### `resendSetup(email)` — Send the setup link again
|
|
1353
|
+
|
|
1354
|
+
```js
|
|
1355
|
+
await client.signers.resendSetup('jane@example.com');
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
**This rotates the token**, which invalidates the link in any email already sent. That
|
|
1359
|
+
is the point — an old link that still works is an old link someone else can use — but
|
|
1360
|
+
it does mean the earlier email stops working the moment you call this.
|
|
1361
|
+
|
|
1362
|
+
---
|
|
1363
|
+
|
|
1364
|
+
### `client.request` — Any Endpoint
|
|
1365
|
+
|
|
1366
|
+
The API can gain an endpoint at any time. This calls one that has no typed method yet,
|
|
1367
|
+
so you are never blocked waiting for an SDK release.
|
|
1368
|
+
|
|
1369
|
+
```js
|
|
1370
|
+
const res = await client.request('POST', '/sdk/v1/some-new-endpoint', {
|
|
1371
|
+
data: { foo: 'bar' },
|
|
1372
|
+
params: { verbose: true }, // query string
|
|
1373
|
+
idempotencyKey: 'batch-2026-10-01',
|
|
1374
|
+
});
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
Authentication, retries, idempotency-conflict handling, the error shape and the
|
|
1378
|
+
User-Agent all behave exactly as they do for a typed resource. The only thing you give
|
|
1379
|
+
up is the named method and its documentation.
|
|
1380
|
+
|
|
1381
|
+
Prefer a typed resource where one exists — it records the shape and keeps working if a
|
|
1382
|
+
path changes. Use this when there is no resource yet.
|
|
1383
|
+
|
|
1384
|
+
> New response fields need nothing at all: responses are passed through untouched, so
|
|
1385
|
+
> a field added server-side is readable immediately on whatever version you have
|
|
1386
|
+
> installed.
|
|
1387
|
+
|
|
1388
|
+
---
|
|
1389
|
+
|
|
1044
1390
|
## Complete Examples
|
|
1045
1391
|
|
|
1046
1392
|
### PDF: PAdES Sign with signCallback (Recommended)
|
|
@@ -1311,6 +1657,14 @@ For batch workloads, use `batchHashAndSign()` or `batchSignHashes()` to sign up
|
|
|
1311
1657
|
|
|
1312
1658
|
## Migration from v1
|
|
1313
1659
|
|
|
1660
|
+
### What's New in v2.5.1
|
|
1661
|
+
|
|
1662
|
+
- **`client.webhooks`** — register an endpoint and be told when envelopes and
|
|
1663
|
+
sponsorships change state, instead of polling. See
|
|
1664
|
+
[client.webhooks](#clientwebhooks--event-notifications).
|
|
1665
|
+
- The `User-Agent` now reports the real package version. It had been pinned at
|
|
1666
|
+
`1.0.0` for the whole 2.x line, so server logs could not tell SDK versions apart.
|
|
1667
|
+
|
|
1314
1668
|
### What's New in v2.2.0
|
|
1315
1669
|
|
|
1316
1670
|
| Feature | Description |
|
package/package.json
CHANGED
|
@@ -1,54 +1,55 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@certysign/sdk",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Official Node.js SDK for CertySign — hash-based digital signing, X.509 certificates, and PKI services. Documents never leave your system.",
|
|
5
|
-
"main": "src/index.js",
|
|
6
|
-
"types": "src/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"src/",
|
|
9
|
-
"README.md"
|
|
10
|
-
],
|
|
11
|
-
"scripts": {
|
|
12
|
-
"test": "jest --coverage",
|
|
13
|
-
"lint": "eslint src/**/*.js",
|
|
14
|
-
"build:types": "npx tsc --emitDeclarationOnly"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@certysign/sdk",
|
|
3
|
+
"version": "2.5.1",
|
|
4
|
+
"description": "Official Node.js SDK for CertySign — hash-based digital signing, X.509 certificates, and PKI services. Documents never leave your system.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "jest --coverage",
|
|
13
|
+
"lint": "eslint src/**/*.js",
|
|
14
|
+
"build:types": "npx tsc --emitDeclarationOnly",
|
|
15
|
+
"test:durability": "node test/durability.test.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"certysign",
|
|
19
|
+
"digital-signature",
|
|
20
|
+
"pki",
|
|
21
|
+
"x509",
|
|
22
|
+
"pdf-signing",
|
|
23
|
+
"document-signing",
|
|
24
|
+
"hash-based-signing",
|
|
25
|
+
"kenya",
|
|
26
|
+
"pades",
|
|
27
|
+
"xmldsig",
|
|
28
|
+
"otp"
|
|
29
|
+
],
|
|
30
|
+
"author": "CertySign Limited <sdk@certysign.io>",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"axios": "^1.6.0",
|
|
37
|
+
"form-data": "^4.0.0",
|
|
38
|
+
"node-forge": "^1.3.3",
|
|
39
|
+
"pdf-lib": "^1.17.1"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"jest": "^29.7.0"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/certysign/sdk-node.git"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://docs.certysign.io/sdk",
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/certysign/sdk-node/issues"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
}
|
|
55
|
+
}
|