@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/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
+ }