@uverify/sdk 0.1.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/README.md +166 -0
- package/dist/index.d.mts +437 -0
- package/dist/index.d.ts +437 -0
- package/dist/index.js +307 -0
- package/dist/index.mjs +278 -0
- package/package.json +52 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
UVerifyApiError: () => UVerifyApiError,
|
|
24
|
+
UVerifyClient: () => UVerifyClient,
|
|
25
|
+
UVerifyValidationError: () => UVerifyValidationError
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/errors.ts
|
|
30
|
+
var UVerifyApiError = class extends Error {
|
|
31
|
+
constructor(message, statusCode, responseBody) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.statusCode = statusCode;
|
|
34
|
+
this.responseBody = responseBody;
|
|
35
|
+
this.name = "UVerifyApiError";
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var UVerifyValidationError = class extends Error {
|
|
39
|
+
constructor(message) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "UVerifyValidationError";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/UVerifyClient.ts
|
|
46
|
+
var DEFAULT_BASE_URL = "https://api.uverify.io";
|
|
47
|
+
var UVerifyClient = class {
|
|
48
|
+
constructor(options = {}) {
|
|
49
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
50
|
+
this.defaultHeaders = {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
Accept: "application/json",
|
|
53
|
+
...options.headers
|
|
54
|
+
};
|
|
55
|
+
this.defaultSignMessage = options.signMessage;
|
|
56
|
+
this.defaultSignTx = options.signTx;
|
|
57
|
+
this.core = {
|
|
58
|
+
buildTransaction: this._buildTransaction.bind(this),
|
|
59
|
+
submitTransaction: this._submitTransaction.bind(this),
|
|
60
|
+
requestUserAction: this._requestUserAction.bind(this),
|
|
61
|
+
executeUserAction: this._executeUserAction.bind(this)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Internal helpers
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
async request(method, path, body) {
|
|
68
|
+
const url = `${this.baseUrl}${path}`;
|
|
69
|
+
const init = {
|
|
70
|
+
method,
|
|
71
|
+
headers: this.defaultHeaders
|
|
72
|
+
};
|
|
73
|
+
if (body !== void 0) {
|
|
74
|
+
init.body = JSON.stringify(body);
|
|
75
|
+
}
|
|
76
|
+
const response = await fetch(url, init);
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
let responseBody;
|
|
79
|
+
try {
|
|
80
|
+
responseBody = await response.json();
|
|
81
|
+
} catch {
|
|
82
|
+
responseBody = await response.text();
|
|
83
|
+
}
|
|
84
|
+
throw new UVerifyApiError(
|
|
85
|
+
`UVerify API error ${response.status}: ${response.statusText}`,
|
|
86
|
+
response.status,
|
|
87
|
+
responseBody
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
const text = await response.text();
|
|
91
|
+
if (!text) return void 0;
|
|
92
|
+
return JSON.parse(text);
|
|
93
|
+
}
|
|
94
|
+
get(path) {
|
|
95
|
+
return this.request("GET", path);
|
|
96
|
+
}
|
|
97
|
+
post(path, body) {
|
|
98
|
+
return this.request("POST", path, body);
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Certificate Verification
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
/**
|
|
104
|
+
* Retrieve all on-chain certificates associated with the given data hash.
|
|
105
|
+
*
|
|
106
|
+
* @param hash - SHA-256 or SHA-512 hex hash of the data to look up.
|
|
107
|
+
* @returns Array of certificates, or an empty array if none exist.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const certs = await client.verify('a3b4c5d6...');
|
|
112
|
+
* if (certs.length > 0) {
|
|
113
|
+
* console.log('First issued at block', certs[0].blockNumber);
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
verify(hash) {
|
|
118
|
+
return this.get(`/api/v1/verify/${hash}`);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Retrieve a single certificate by its Cardano transaction hash and data hash.
|
|
122
|
+
*
|
|
123
|
+
* @param transactionHash - 64-character hex transaction hash.
|
|
124
|
+
* @param dataHash - SHA-256 or SHA-512 hex hash of the certified data.
|
|
125
|
+
*/
|
|
126
|
+
verifyByTransaction(transactionHash, dataHash) {
|
|
127
|
+
return this.get(
|
|
128
|
+
`/api/v1/verify/by-transaction-hash/${transactionHash}/${dataHash}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Low-level API (exposed via .core)
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
_buildTransaction(request) {
|
|
135
|
+
return this.post(
|
|
136
|
+
"/api/v1/transaction/build",
|
|
137
|
+
request
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
async _submitTransaction(transaction, witnessSet) {
|
|
141
|
+
await this.post("/api/v1/transaction/submit", {
|
|
142
|
+
transaction,
|
|
143
|
+
witnessSet
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
_requestUserAction(request) {
|
|
147
|
+
return this.post(
|
|
148
|
+
"/api/v1/user/request/action",
|
|
149
|
+
request
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
_executeUserAction(request) {
|
|
153
|
+
return this.post(
|
|
154
|
+
"/api/v1/user/state/action",
|
|
155
|
+
request
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
// High-level helpers
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
/**
|
|
162
|
+
* Issue certificates in a single step.
|
|
163
|
+
*
|
|
164
|
+
* Builds the unsigned transaction, passes it to `signCallback` to obtain a
|
|
165
|
+
* witness set, then submits the signed transaction to the blockchain.
|
|
166
|
+
*
|
|
167
|
+
* This is the recommended way to issue certificates when you control the full
|
|
168
|
+
* flow in one place. For more control (e.g. multi-sig flows) use
|
|
169
|
+
* {@link buildTransaction} and {@link submitTransaction} separately.
|
|
170
|
+
*
|
|
171
|
+
* @param address Cardano address of the signer / payer.
|
|
172
|
+
* @param stateId ID of the issuing state.
|
|
173
|
+
* @param certificates One or more certificates to certify.
|
|
174
|
+
* @param signCallback Callback that receives the unsigned transaction and
|
|
175
|
+
* returns the CIP-30 witness set CBOR hex.
|
|
176
|
+
*
|
|
177
|
+
* @example CIP-30 browser wallet
|
|
178
|
+
* ```ts
|
|
179
|
+
* await client.issueCertificates(
|
|
180
|
+
* 'addr1...',
|
|
181
|
+
* 'my-state-id',
|
|
182
|
+
* [{ hash: 'sha256-hash-of-doc', algorithm: 'SHA-256' }],
|
|
183
|
+
* (unsignedTx) => api.signTx(unsignedTx, true),
|
|
184
|
+
* );
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* @example mesh.js
|
|
188
|
+
* ```ts
|
|
189
|
+
* await client.issueCertificates(
|
|
190
|
+
* 'addr1...', 'my-state-id',
|
|
191
|
+
* [{ hash: 'sha256-hash-of-doc', algorithm: 'SHA-256' }],
|
|
192
|
+
* (unsignedTx) => wallet.signTx(unsignedTx, true),
|
|
193
|
+
* );
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
async issueCertificates(address, certificates, signCallback, stateId) {
|
|
197
|
+
const cb = this._resolveTxCallback(signCallback);
|
|
198
|
+
const { unsignedTransaction } = await this._buildTransaction({
|
|
199
|
+
type: "default",
|
|
200
|
+
address,
|
|
201
|
+
stateId,
|
|
202
|
+
certificates
|
|
203
|
+
});
|
|
204
|
+
const witnessSet = await cb(unsignedTransaction);
|
|
205
|
+
await this._submitTransaction(unsignedTransaction, witnessSet);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Retrieve the current state information for a user in a single step.
|
|
209
|
+
*
|
|
210
|
+
* Internally calls {@link requestUserAction} to obtain a server-signed
|
|
211
|
+
* challenge, invokes `signCallback` so the user's wallet can countersign,
|
|
212
|
+
* then calls {@link executeUserAction} and returns the resolved state.
|
|
213
|
+
*
|
|
214
|
+
* @param address Cardano address of the user.
|
|
215
|
+
* @param signCallback Callback that signs the challenge message and returns
|
|
216
|
+
* the CIP-30 `{ key, signature }` data signature object.
|
|
217
|
+
*
|
|
218
|
+
* @example CIP-30 browser wallet
|
|
219
|
+
* ```ts
|
|
220
|
+
* const state = await client.getUserInfo('addr1...', async (message) => {
|
|
221
|
+
* const hexAddress = await api.getChangeAddress();
|
|
222
|
+
* const hexMessage = Array.from(message)
|
|
223
|
+
* .map((c) => c.charCodeAt(0).toString(16).padStart(2, '0'))
|
|
224
|
+
* .join('');
|
|
225
|
+
* return api.signData(hexAddress, hexMessage);
|
|
226
|
+
* });
|
|
227
|
+
* console.log('Certificates left before renewal:', state?.countdown);
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
async getUserInfo(address, signCallback) {
|
|
231
|
+
const result = await this._performUserStateAction(
|
|
232
|
+
{ address, action: "USER_INFO" },
|
|
233
|
+
signCallback
|
|
234
|
+
);
|
|
235
|
+
return result.state;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Invalidate a user state in a single step.
|
|
239
|
+
*
|
|
240
|
+
* @param address Cardano address of the user.
|
|
241
|
+
* @param stateId ID of the state to invalidate.
|
|
242
|
+
* @param signCallback Callback that signs the challenge message.
|
|
243
|
+
* Falls back to the `signMessage` set in the constructor.
|
|
244
|
+
*/
|
|
245
|
+
async invalidateState(address, stateId, signCallback) {
|
|
246
|
+
return this._performUserStateAction(
|
|
247
|
+
{ address, action: "INVALIDATE_STATE", stateId },
|
|
248
|
+
signCallback
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Opt out of UVerify in a single step, removing the user's state.
|
|
253
|
+
*
|
|
254
|
+
* @param address Cardano address of the user.
|
|
255
|
+
* @param stateId ID of the state to remove.
|
|
256
|
+
* @param signCallback Callback that signs the challenge message.
|
|
257
|
+
* Falls back to the `signMessage` set in the constructor.
|
|
258
|
+
*/
|
|
259
|
+
async optOut(address, stateId, signCallback) {
|
|
260
|
+
return this._performUserStateAction(
|
|
261
|
+
{ address, action: "OPT_OUT", stateId },
|
|
262
|
+
signCallback
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Internal helper that runs the two-step user state action flow:
|
|
267
|
+
* request challenge → user signs → execute action.
|
|
268
|
+
*/
|
|
269
|
+
async _performUserStateAction(request, signCallback) {
|
|
270
|
+
const cb = this._resolveMessageCallback(signCallback);
|
|
271
|
+
const challenge = await this._requestUserAction(request);
|
|
272
|
+
const { key, signature } = await cb(challenge.message);
|
|
273
|
+
return this._executeUserAction({
|
|
274
|
+
address: challenge.address,
|
|
275
|
+
action: challenge.action,
|
|
276
|
+
message: challenge.message,
|
|
277
|
+
signature: challenge.signature,
|
|
278
|
+
timestamp: challenge.timestamp,
|
|
279
|
+
userSignature: signature,
|
|
280
|
+
userPublicKey: key
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
_resolveMessageCallback(override) {
|
|
284
|
+
const cb = override ?? this.defaultSignMessage;
|
|
285
|
+
if (!cb) {
|
|
286
|
+
throw new UVerifyValidationError(
|
|
287
|
+
"No message sign callback provided. Pass one to this method or set signMessage in UVerifyClientOptions."
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
return cb;
|
|
291
|
+
}
|
|
292
|
+
_resolveTxCallback(override) {
|
|
293
|
+
const cb = override ?? this.defaultSignTx;
|
|
294
|
+
if (!cb) {
|
|
295
|
+
throw new UVerifyValidationError(
|
|
296
|
+
"No transaction sign callback provided. Pass one to this method or set signTx in UVerifyClientOptions."
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
return cb;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
303
|
+
0 && (module.exports = {
|
|
304
|
+
UVerifyApiError,
|
|
305
|
+
UVerifyClient,
|
|
306
|
+
UVerifyValidationError
|
|
307
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var UVerifyApiError = class extends Error {
|
|
3
|
+
constructor(message, statusCode, responseBody) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.statusCode = statusCode;
|
|
6
|
+
this.responseBody = responseBody;
|
|
7
|
+
this.name = "UVerifyApiError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var UVerifyValidationError = class extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "UVerifyValidationError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/UVerifyClient.ts
|
|
18
|
+
var DEFAULT_BASE_URL = "https://api.uverify.io";
|
|
19
|
+
var UVerifyClient = class {
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
22
|
+
this.defaultHeaders = {
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
Accept: "application/json",
|
|
25
|
+
...options.headers
|
|
26
|
+
};
|
|
27
|
+
this.defaultSignMessage = options.signMessage;
|
|
28
|
+
this.defaultSignTx = options.signTx;
|
|
29
|
+
this.core = {
|
|
30
|
+
buildTransaction: this._buildTransaction.bind(this),
|
|
31
|
+
submitTransaction: this._submitTransaction.bind(this),
|
|
32
|
+
requestUserAction: this._requestUserAction.bind(this),
|
|
33
|
+
executeUserAction: this._executeUserAction.bind(this)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Internal helpers
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
async request(method, path, body) {
|
|
40
|
+
const url = `${this.baseUrl}${path}`;
|
|
41
|
+
const init = {
|
|
42
|
+
method,
|
|
43
|
+
headers: this.defaultHeaders
|
|
44
|
+
};
|
|
45
|
+
if (body !== void 0) {
|
|
46
|
+
init.body = JSON.stringify(body);
|
|
47
|
+
}
|
|
48
|
+
const response = await fetch(url, init);
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
let responseBody;
|
|
51
|
+
try {
|
|
52
|
+
responseBody = await response.json();
|
|
53
|
+
} catch {
|
|
54
|
+
responseBody = await response.text();
|
|
55
|
+
}
|
|
56
|
+
throw new UVerifyApiError(
|
|
57
|
+
`UVerify API error ${response.status}: ${response.statusText}`,
|
|
58
|
+
response.status,
|
|
59
|
+
responseBody
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const text = await response.text();
|
|
63
|
+
if (!text) return void 0;
|
|
64
|
+
return JSON.parse(text);
|
|
65
|
+
}
|
|
66
|
+
get(path) {
|
|
67
|
+
return this.request("GET", path);
|
|
68
|
+
}
|
|
69
|
+
post(path, body) {
|
|
70
|
+
return this.request("POST", path, body);
|
|
71
|
+
}
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Certificate Verification
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
/**
|
|
76
|
+
* Retrieve all on-chain certificates associated with the given data hash.
|
|
77
|
+
*
|
|
78
|
+
* @param hash - SHA-256 or SHA-512 hex hash of the data to look up.
|
|
79
|
+
* @returns Array of certificates, or an empty array if none exist.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const certs = await client.verify('a3b4c5d6...');
|
|
84
|
+
* if (certs.length > 0) {
|
|
85
|
+
* console.log('First issued at block', certs[0].blockNumber);
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
verify(hash) {
|
|
90
|
+
return this.get(`/api/v1/verify/${hash}`);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Retrieve a single certificate by its Cardano transaction hash and data hash.
|
|
94
|
+
*
|
|
95
|
+
* @param transactionHash - 64-character hex transaction hash.
|
|
96
|
+
* @param dataHash - SHA-256 or SHA-512 hex hash of the certified data.
|
|
97
|
+
*/
|
|
98
|
+
verifyByTransaction(transactionHash, dataHash) {
|
|
99
|
+
return this.get(
|
|
100
|
+
`/api/v1/verify/by-transaction-hash/${transactionHash}/${dataHash}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Low-level API (exposed via .core)
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
_buildTransaction(request) {
|
|
107
|
+
return this.post(
|
|
108
|
+
"/api/v1/transaction/build",
|
|
109
|
+
request
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
async _submitTransaction(transaction, witnessSet) {
|
|
113
|
+
await this.post("/api/v1/transaction/submit", {
|
|
114
|
+
transaction,
|
|
115
|
+
witnessSet
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
_requestUserAction(request) {
|
|
119
|
+
return this.post(
|
|
120
|
+
"/api/v1/user/request/action",
|
|
121
|
+
request
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
_executeUserAction(request) {
|
|
125
|
+
return this.post(
|
|
126
|
+
"/api/v1/user/state/action",
|
|
127
|
+
request
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// High-level helpers
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
/**
|
|
134
|
+
* Issue certificates in a single step.
|
|
135
|
+
*
|
|
136
|
+
* Builds the unsigned transaction, passes it to `signCallback` to obtain a
|
|
137
|
+
* witness set, then submits the signed transaction to the blockchain.
|
|
138
|
+
*
|
|
139
|
+
* This is the recommended way to issue certificates when you control the full
|
|
140
|
+
* flow in one place. For more control (e.g. multi-sig flows) use
|
|
141
|
+
* {@link buildTransaction} and {@link submitTransaction} separately.
|
|
142
|
+
*
|
|
143
|
+
* @param address Cardano address of the signer / payer.
|
|
144
|
+
* @param stateId ID of the issuing state.
|
|
145
|
+
* @param certificates One or more certificates to certify.
|
|
146
|
+
* @param signCallback Callback that receives the unsigned transaction and
|
|
147
|
+
* returns the CIP-30 witness set CBOR hex.
|
|
148
|
+
*
|
|
149
|
+
* @example CIP-30 browser wallet
|
|
150
|
+
* ```ts
|
|
151
|
+
* await client.issueCertificates(
|
|
152
|
+
* 'addr1...',
|
|
153
|
+
* 'my-state-id',
|
|
154
|
+
* [{ hash: 'sha256-hash-of-doc', algorithm: 'SHA-256' }],
|
|
155
|
+
* (unsignedTx) => api.signTx(unsignedTx, true),
|
|
156
|
+
* );
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @example mesh.js
|
|
160
|
+
* ```ts
|
|
161
|
+
* await client.issueCertificates(
|
|
162
|
+
* 'addr1...', 'my-state-id',
|
|
163
|
+
* [{ hash: 'sha256-hash-of-doc', algorithm: 'SHA-256' }],
|
|
164
|
+
* (unsignedTx) => wallet.signTx(unsignedTx, true),
|
|
165
|
+
* );
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
async issueCertificates(address, certificates, signCallback, stateId) {
|
|
169
|
+
const cb = this._resolveTxCallback(signCallback);
|
|
170
|
+
const { unsignedTransaction } = await this._buildTransaction({
|
|
171
|
+
type: "default",
|
|
172
|
+
address,
|
|
173
|
+
stateId,
|
|
174
|
+
certificates
|
|
175
|
+
});
|
|
176
|
+
const witnessSet = await cb(unsignedTransaction);
|
|
177
|
+
await this._submitTransaction(unsignedTransaction, witnessSet);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Retrieve the current state information for a user in a single step.
|
|
181
|
+
*
|
|
182
|
+
* Internally calls {@link requestUserAction} to obtain a server-signed
|
|
183
|
+
* challenge, invokes `signCallback` so the user's wallet can countersign,
|
|
184
|
+
* then calls {@link executeUserAction} and returns the resolved state.
|
|
185
|
+
*
|
|
186
|
+
* @param address Cardano address of the user.
|
|
187
|
+
* @param signCallback Callback that signs the challenge message and returns
|
|
188
|
+
* the CIP-30 `{ key, signature }` data signature object.
|
|
189
|
+
*
|
|
190
|
+
* @example CIP-30 browser wallet
|
|
191
|
+
* ```ts
|
|
192
|
+
* const state = await client.getUserInfo('addr1...', async (message) => {
|
|
193
|
+
* const hexAddress = await api.getChangeAddress();
|
|
194
|
+
* const hexMessage = Array.from(message)
|
|
195
|
+
* .map((c) => c.charCodeAt(0).toString(16).padStart(2, '0'))
|
|
196
|
+
* .join('');
|
|
197
|
+
* return api.signData(hexAddress, hexMessage);
|
|
198
|
+
* });
|
|
199
|
+
* console.log('Certificates left before renewal:', state?.countdown);
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
async getUserInfo(address, signCallback) {
|
|
203
|
+
const result = await this._performUserStateAction(
|
|
204
|
+
{ address, action: "USER_INFO" },
|
|
205
|
+
signCallback
|
|
206
|
+
);
|
|
207
|
+
return result.state;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Invalidate a user state in a single step.
|
|
211
|
+
*
|
|
212
|
+
* @param address Cardano address of the user.
|
|
213
|
+
* @param stateId ID of the state to invalidate.
|
|
214
|
+
* @param signCallback Callback that signs the challenge message.
|
|
215
|
+
* Falls back to the `signMessage` set in the constructor.
|
|
216
|
+
*/
|
|
217
|
+
async invalidateState(address, stateId, signCallback) {
|
|
218
|
+
return this._performUserStateAction(
|
|
219
|
+
{ address, action: "INVALIDATE_STATE", stateId },
|
|
220
|
+
signCallback
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Opt out of UVerify in a single step, removing the user's state.
|
|
225
|
+
*
|
|
226
|
+
* @param address Cardano address of the user.
|
|
227
|
+
* @param stateId ID of the state to remove.
|
|
228
|
+
* @param signCallback Callback that signs the challenge message.
|
|
229
|
+
* Falls back to the `signMessage` set in the constructor.
|
|
230
|
+
*/
|
|
231
|
+
async optOut(address, stateId, signCallback) {
|
|
232
|
+
return this._performUserStateAction(
|
|
233
|
+
{ address, action: "OPT_OUT", stateId },
|
|
234
|
+
signCallback
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Internal helper that runs the two-step user state action flow:
|
|
239
|
+
* request challenge → user signs → execute action.
|
|
240
|
+
*/
|
|
241
|
+
async _performUserStateAction(request, signCallback) {
|
|
242
|
+
const cb = this._resolveMessageCallback(signCallback);
|
|
243
|
+
const challenge = await this._requestUserAction(request);
|
|
244
|
+
const { key, signature } = await cb(challenge.message);
|
|
245
|
+
return this._executeUserAction({
|
|
246
|
+
address: challenge.address,
|
|
247
|
+
action: challenge.action,
|
|
248
|
+
message: challenge.message,
|
|
249
|
+
signature: challenge.signature,
|
|
250
|
+
timestamp: challenge.timestamp,
|
|
251
|
+
userSignature: signature,
|
|
252
|
+
userPublicKey: key
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
_resolveMessageCallback(override) {
|
|
256
|
+
const cb = override ?? this.defaultSignMessage;
|
|
257
|
+
if (!cb) {
|
|
258
|
+
throw new UVerifyValidationError(
|
|
259
|
+
"No message sign callback provided. Pass one to this method or set signMessage in UVerifyClientOptions."
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return cb;
|
|
263
|
+
}
|
|
264
|
+
_resolveTxCallback(override) {
|
|
265
|
+
const cb = override ?? this.defaultSignTx;
|
|
266
|
+
if (!cb) {
|
|
267
|
+
throw new UVerifyValidationError(
|
|
268
|
+
"No transaction sign callback provided. Pass one to this method or set signTx in UVerifyClientOptions."
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
return cb;
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
export {
|
|
275
|
+
UVerifyApiError,
|
|
276
|
+
UVerifyClient,
|
|
277
|
+
UVerifyValidationError
|
|
278
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uverify/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official TypeScript/JavaScript SDK for the UVerify API",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
20
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"uverify",
|
|
27
|
+
"cardano",
|
|
28
|
+
"blockchain",
|
|
29
|
+
"certificate",
|
|
30
|
+
"verification",
|
|
31
|
+
"sdk"
|
|
32
|
+
],
|
|
33
|
+
"author": "Fabian Bormann",
|
|
34
|
+
"license": "AGPL-3.0",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/UVerify-io/uverify-sdks"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://docs.uverify.io",
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"tsup": "^8.0.0",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
43
|
+
"vitest": "^4.0.18"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18.0.0"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public",
|
|
50
|
+
"registry": "https://registry.npmjs.org/"
|
|
51
|
+
}
|
|
52
|
+
}
|