@proofchain/sdk 1.2.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/LICENSE +21 -0
- package/README.md +254 -114
- package/dist/index.d.mts +2501 -276
- package/dist/index.d.ts +2501 -276
- package/dist/index.js +2031 -275
- package/dist/index.mjs +2004 -271
- package/package.json +43 -19
- package/src/client.ts +0 -312
- package/src/contract.ts +0 -212
- package/src/index.ts +0 -65
- package/src/types.ts +0 -228
- package/tsconfig.json +0 -18
package/dist/index.mjs
CHANGED
|
@@ -1,347 +1,2080 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
var
|
|
3
|
-
constructor(message,
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var ProofChainError = class extends Error {
|
|
3
|
+
constructor(message, statusCode, responseBody) {
|
|
4
4
|
super(message);
|
|
5
|
-
this.
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
5
|
+
this.name = "ProofChainError";
|
|
6
|
+
this.statusCode = statusCode;
|
|
7
|
+
this.responseBody = responseBody;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
-
var
|
|
11
|
-
constructor(
|
|
12
|
-
|
|
13
|
-
this.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
var AuthenticationError = class extends ProofChainError {
|
|
11
|
+
constructor(message = "Invalid or missing API key") {
|
|
12
|
+
super(message, 401);
|
|
13
|
+
this.name = "AuthenticationError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var AuthorizationError = class extends ProofChainError {
|
|
17
|
+
constructor(message = "Access denied") {
|
|
18
|
+
super(message, 403);
|
|
19
|
+
this.name = "AuthorizationError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var NotFoundError = class extends ProofChainError {
|
|
23
|
+
constructor(message = "Resource not found") {
|
|
24
|
+
super(message, 404);
|
|
25
|
+
this.name = "NotFoundError";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var ValidationError = class extends ProofChainError {
|
|
29
|
+
constructor(message = "Validation error", errors = []) {
|
|
30
|
+
super(message, 422);
|
|
31
|
+
this.name = "ValidationError";
|
|
32
|
+
this.errors = errors;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var RateLimitError = class extends ProofChainError {
|
|
36
|
+
constructor(retryAfter) {
|
|
37
|
+
super("Rate limit exceeded", 429);
|
|
38
|
+
this.name = "RateLimitError";
|
|
39
|
+
this.retryAfter = retryAfter;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var ServerError = class extends ProofChainError {
|
|
43
|
+
constructor(message = "Server error", statusCode = 500) {
|
|
44
|
+
super(message, statusCode);
|
|
45
|
+
this.name = "ServerError";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var NetworkError = class extends ProofChainError {
|
|
49
|
+
constructor(message = "Network error", cause) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = "NetworkError";
|
|
52
|
+
this.cause = cause;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var TimeoutError = class extends ProofChainError {
|
|
56
|
+
constructor(message = "Request timed out") {
|
|
57
|
+
super(message);
|
|
58
|
+
this.name = "TimeoutError";
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/http.ts
|
|
63
|
+
var DEFAULT_BASE_URL = "https://api.proofchain.co.za";
|
|
64
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
65
|
+
var USER_AGENT = "proofchain-js/0.1.0";
|
|
66
|
+
var HttpClient = class {
|
|
67
|
+
constructor(options) {
|
|
68
|
+
this.apiKey = options.apiKey;
|
|
69
|
+
this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
70
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
71
|
+
this.maxRetries = options.maxRetries ?? 3;
|
|
72
|
+
}
|
|
73
|
+
getHeaders() {
|
|
74
|
+
return {
|
|
75
|
+
"X-API-Key": this.apiKey,
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
"User-Agent": USER_AGENT
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async handleResponse(response) {
|
|
81
|
+
const contentType = response.headers.get("content-type");
|
|
82
|
+
const isJson = contentType?.includes("application/json");
|
|
83
|
+
if (response.ok) {
|
|
84
|
+
if (response.status === 204 || !isJson) {
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
return response.json();
|
|
88
|
+
}
|
|
89
|
+
const body = isJson ? await response.json().catch(() => ({})) : {};
|
|
90
|
+
const message = body.detail || body.message || `HTTP ${response.status}`;
|
|
91
|
+
switch (response.status) {
|
|
92
|
+
case 401:
|
|
93
|
+
throw new AuthenticationError(message);
|
|
94
|
+
case 403:
|
|
95
|
+
throw new AuthorizationError(message);
|
|
96
|
+
case 404:
|
|
97
|
+
throw new NotFoundError(message);
|
|
98
|
+
case 422:
|
|
99
|
+
case 400:
|
|
100
|
+
throw new ValidationError(message, body.errors);
|
|
101
|
+
case 429:
|
|
102
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
103
|
+
throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : void 0);
|
|
104
|
+
default:
|
|
105
|
+
if (response.status >= 500) {
|
|
106
|
+
throw new ServerError(message, response.status);
|
|
107
|
+
}
|
|
108
|
+
throw new ProofChainError(message, response.status, body);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async fetchWithRetry(url, options, retries = 0) {
|
|
19
112
|
const controller = new AbortController();
|
|
20
113
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
114
|
+
try {
|
|
115
|
+
const response = await fetch(url, {
|
|
116
|
+
...options,
|
|
117
|
+
signal: controller.signal
|
|
118
|
+
});
|
|
119
|
+
clearTimeout(timeoutId);
|
|
120
|
+
return this.handleResponse(response);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
clearTimeout(timeoutId);
|
|
123
|
+
if (error instanceof ProofChainError) {
|
|
124
|
+
if (error instanceof RateLimitError && retries < this.maxRetries) {
|
|
125
|
+
const delay = Math.min((error.retryAfter || 1) * 1e3, 6e4);
|
|
126
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
127
|
+
return this.fetchWithRetry(url, options, retries + 1);
|
|
128
|
+
}
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
if (error instanceof Error) {
|
|
132
|
+
if (error.name === "AbortError") {
|
|
133
|
+
throw new TimeoutError();
|
|
134
|
+
}
|
|
135
|
+
if (retries < this.maxRetries) {
|
|
136
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * (retries + 1)));
|
|
137
|
+
return this.fetchWithRetry(url, options, retries + 1);
|
|
138
|
+
}
|
|
139
|
+
throw new NetworkError(error.message, error);
|
|
140
|
+
}
|
|
141
|
+
throw new NetworkError("Unknown error");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async request(method, path, options = {}) {
|
|
145
|
+
let url = `${this.baseUrl}${path}`;
|
|
146
|
+
if (options.params) {
|
|
147
|
+
const searchParams = new URLSearchParams();
|
|
148
|
+
for (const [key, value] of Object.entries(options.params)) {
|
|
149
|
+
if (value !== void 0) {
|
|
150
|
+
searchParams.append(key, String(value));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const queryString = searchParams.toString();
|
|
154
|
+
if (queryString) {
|
|
155
|
+
url += `?${queryString}`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const fetchOptions = {
|
|
159
|
+
method,
|
|
160
|
+
headers: this.getHeaders()
|
|
24
161
|
};
|
|
25
|
-
if (
|
|
26
|
-
|
|
162
|
+
if (options.body) {
|
|
163
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
27
164
|
}
|
|
165
|
+
return this.fetchWithRetry(url, fetchOptions);
|
|
166
|
+
}
|
|
167
|
+
async requestMultipart(path, formData) {
|
|
168
|
+
const url = `${this.baseUrl}${path}`;
|
|
169
|
+
const headers = {
|
|
170
|
+
"X-API-Key": this.apiKey,
|
|
171
|
+
"User-Agent": USER_AGENT
|
|
172
|
+
};
|
|
173
|
+
return this.fetchWithRetry(url, {
|
|
174
|
+
method: "POST",
|
|
175
|
+
headers,
|
|
176
|
+
body: formData
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
async getRaw(path) {
|
|
180
|
+
const url = `${this.baseUrl}${path}`;
|
|
181
|
+
const controller = new AbortController();
|
|
182
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
28
183
|
try {
|
|
29
184
|
const response = await fetch(url, {
|
|
30
|
-
method,
|
|
31
|
-
headers
|
|
32
|
-
|
|
33
|
-
|
|
185
|
+
method: "GET",
|
|
186
|
+
headers: {
|
|
187
|
+
"X-API-Key": this.apiKey,
|
|
188
|
+
"User-Agent": USER_AGENT
|
|
189
|
+
},
|
|
190
|
+
signal: controller.signal
|
|
34
191
|
});
|
|
35
192
|
clearTimeout(timeoutId);
|
|
36
193
|
if (!response.ok) {
|
|
37
|
-
|
|
38
|
-
throw new AttestationClientError(
|
|
39
|
-
`Request failed: ${response.status} ${response.statusText}`,
|
|
40
|
-
response.status,
|
|
41
|
-
errorBody
|
|
42
|
-
);
|
|
194
|
+
throw new ProofChainError(`HTTP ${response.status}`, response.status);
|
|
43
195
|
}
|
|
44
|
-
return response.
|
|
196
|
+
return response.arrayBuffer();
|
|
45
197
|
} catch (error) {
|
|
46
198
|
clearTimeout(timeoutId);
|
|
47
|
-
if (error instanceof
|
|
48
|
-
throw new
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
199
|
+
if (error instanceof ProofChainError) throw error;
|
|
200
|
+
throw new NetworkError(error.message);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
get(path, params) {
|
|
204
|
+
return this.request("GET", path, { params });
|
|
205
|
+
}
|
|
206
|
+
post(path, body) {
|
|
207
|
+
return this.request("POST", path, { body });
|
|
208
|
+
}
|
|
209
|
+
put(path, body) {
|
|
210
|
+
return this.request("PUT", path, { body });
|
|
211
|
+
}
|
|
212
|
+
patch(path, body) {
|
|
213
|
+
return this.request("PATCH", path, { body });
|
|
214
|
+
}
|
|
215
|
+
delete(path) {
|
|
216
|
+
return this.request("DELETE", path);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/resources/vault.ts
|
|
221
|
+
var VaultResource = class {
|
|
222
|
+
constructor(http) {
|
|
223
|
+
this.http = http;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* List files and folders in the vault.
|
|
227
|
+
*/
|
|
228
|
+
async list(folderId) {
|
|
229
|
+
const params = {};
|
|
230
|
+
if (folderId) params.folder_id = folderId;
|
|
231
|
+
return this.http.get("/tenant/vault", params);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Upload a file to the vault.
|
|
235
|
+
*/
|
|
236
|
+
async upload(request) {
|
|
237
|
+
const formData = new FormData();
|
|
238
|
+
if (request.file instanceof Blob) {
|
|
239
|
+
formData.append("file", request.file, request.filename || "file");
|
|
240
|
+
} else if (request.file instanceof ArrayBuffer) {
|
|
241
|
+
const blob = new Blob([request.file]);
|
|
242
|
+
formData.append("file", blob, request.filename || "file");
|
|
243
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(request.file)) {
|
|
244
|
+
const uint8 = new Uint8Array(request.file);
|
|
245
|
+
const blob = new Blob([uint8]);
|
|
246
|
+
formData.append("file", blob, request.filename || "file");
|
|
52
247
|
}
|
|
248
|
+
formData.append("user_id", request.userId);
|
|
249
|
+
if (request.folderId) formData.append("folder_id", request.folderId);
|
|
250
|
+
formData.append("access_mode", request.accessMode || "private");
|
|
251
|
+
return this.http.requestMultipart("/tenant/vault/upload", formData);
|
|
53
252
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
253
|
+
/**
|
|
254
|
+
* Get file details.
|
|
255
|
+
*/
|
|
256
|
+
async get(fileId) {
|
|
257
|
+
return this.http.get(`/tenant/vault/files/${fileId}`);
|
|
57
258
|
}
|
|
58
|
-
|
|
59
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Download a file.
|
|
261
|
+
*/
|
|
262
|
+
async download(fileId) {
|
|
263
|
+
return this.http.getRaw(`/tenant/vault/files/${fileId}/download`);
|
|
60
264
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
265
|
+
/**
|
|
266
|
+
* Delete a file.
|
|
267
|
+
*/
|
|
268
|
+
async delete(fileId) {
|
|
269
|
+
await this.http.delete(`/tenant/vault/files/${fileId}`);
|
|
64
270
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Move a file to a folder.
|
|
273
|
+
*/
|
|
274
|
+
async move(fileId, folderId) {
|
|
275
|
+
return this.http.post(`/tenant/vault/files/${fileId}/move`, {
|
|
276
|
+
folder_id: folderId
|
|
69
277
|
});
|
|
70
278
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Create a folder.
|
|
281
|
+
*/
|
|
282
|
+
async createFolder(name, parentId) {
|
|
283
|
+
return this.http.post("/tenant/vault/folders", {
|
|
284
|
+
name,
|
|
285
|
+
parent_id: parentId
|
|
76
286
|
});
|
|
77
|
-
if (response.access_token) {
|
|
78
|
-
this.setAccessToken(response.access_token);
|
|
79
|
-
}
|
|
80
|
-
return response;
|
|
81
287
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Delete a folder.
|
|
290
|
+
*/
|
|
291
|
+
async deleteFolder(folderId) {
|
|
292
|
+
await this.http.delete(`/tenant/vault/folders/${folderId}`);
|
|
85
293
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (options?.fetchData) params.set("fetch_data", "true");
|
|
92
|
-
const query = params.toString();
|
|
93
|
-
return this.request(
|
|
94
|
-
"GET",
|
|
95
|
-
`/data/events/${userId}${query ? `?${query}` : ""}`
|
|
96
|
-
);
|
|
294
|
+
/**
|
|
295
|
+
* Get vault statistics.
|
|
296
|
+
*/
|
|
297
|
+
async stats() {
|
|
298
|
+
return this.http.get("/tenant/vault/stats");
|
|
97
299
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Create a shareable link.
|
|
302
|
+
*/
|
|
303
|
+
async share(fileId, expiresInHours) {
|
|
304
|
+
return this.http.post("/tenant/vault/share", {
|
|
305
|
+
file_id: fileId,
|
|
306
|
+
expires_in_hours: expiresInHours
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// src/resources/search.ts
|
|
312
|
+
var SearchResource = class {
|
|
313
|
+
constructor(http) {
|
|
314
|
+
this.http = http;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Search events with filters.
|
|
318
|
+
*/
|
|
319
|
+
async query(request = {}) {
|
|
320
|
+
return this.http.post("/search", {
|
|
321
|
+
filters: request.filters,
|
|
322
|
+
offset: request.offset,
|
|
323
|
+
limit: request.limit,
|
|
324
|
+
include_data: request.includeData
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Quick search across all fields.
|
|
329
|
+
*/
|
|
330
|
+
async quick(query, limit = 20) {
|
|
331
|
+
return this.http.get("/search/quick", { q: query, limit });
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Get events for a specific user.
|
|
335
|
+
*/
|
|
336
|
+
async byUser(userId, limit, offset) {
|
|
337
|
+
return this.http.get(`/search/by-user/${userId}`, { limit, offset });
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Get event by certificate ID.
|
|
341
|
+
*/
|
|
342
|
+
async byCertificate(certificateId) {
|
|
343
|
+
return this.http.get(`/search/by-certificate/${certificateId}`);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get faceted aggregations.
|
|
347
|
+
*/
|
|
348
|
+
async facets(fromDate, toDate) {
|
|
349
|
+
return this.http.get("/search/facets", {
|
|
350
|
+
from_date: fromDate,
|
|
351
|
+
to_date: toDate
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Get search statistics.
|
|
356
|
+
*/
|
|
357
|
+
async stats() {
|
|
358
|
+
return this.http.get("/search/stats");
|
|
104
359
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// src/resources/verify.ts
|
|
363
|
+
var VerifyResource = class {
|
|
364
|
+
constructor(http) {
|
|
365
|
+
this.http = http;
|
|
108
366
|
}
|
|
109
|
-
|
|
110
|
-
|
|
367
|
+
/**
|
|
368
|
+
* Verify a certificate by ID.
|
|
369
|
+
*/
|
|
370
|
+
async certificate(certificateId) {
|
|
371
|
+
return this.http.get(`/verify/cert/${certificateId}`);
|
|
111
372
|
}
|
|
112
|
-
|
|
113
|
-
|
|
373
|
+
/**
|
|
374
|
+
* Verify an event by IPFS hash.
|
|
375
|
+
*/
|
|
376
|
+
async event(ipfsHash) {
|
|
377
|
+
return this.http.get(`/verify/event/${ipfsHash}`);
|
|
114
378
|
}
|
|
115
|
-
|
|
116
|
-
|
|
379
|
+
/**
|
|
380
|
+
* Verify a Merkle proof.
|
|
381
|
+
*/
|
|
382
|
+
async proof(leaf, proof, root) {
|
|
383
|
+
return this.http.post("/verify/proof", {
|
|
117
384
|
leaf,
|
|
118
385
|
proof,
|
|
119
386
|
root
|
|
120
387
|
});
|
|
121
388
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
389
|
+
/**
|
|
390
|
+
* Verify a batch by ID.
|
|
391
|
+
*/
|
|
392
|
+
async batch(batchId) {
|
|
393
|
+
return this.http.get(`/verify/batch/${batchId}`);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Get batch proof for an event.
|
|
397
|
+
*/
|
|
398
|
+
async eventBatchProof(eventId) {
|
|
399
|
+
return this.http.get(`/verify/event/${eventId}/batch-proof`);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Batch verify multiple items.
|
|
403
|
+
*/
|
|
404
|
+
async batchVerify(items) {
|
|
405
|
+
return this.http.post("/verify/batch", { items });
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
// src/resources/tenant.ts
|
|
410
|
+
var TenantResource = class {
|
|
411
|
+
constructor(http) {
|
|
412
|
+
this.http = http;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* List all API keys.
|
|
416
|
+
*/
|
|
417
|
+
async listApiKeys() {
|
|
418
|
+
return this.http.get("/tenant/api-keys");
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Create a new API key.
|
|
422
|
+
*/
|
|
423
|
+
async createApiKey(request) {
|
|
424
|
+
return this.http.post("/tenant/api-keys", {
|
|
425
|
+
name: request.name,
|
|
426
|
+
permissions: request.permissions,
|
|
427
|
+
expires_in_days: request.expiresInDays
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Delete an API key.
|
|
432
|
+
*/
|
|
433
|
+
async deleteApiKey(keyId) {
|
|
434
|
+
await this.http.delete(`/tenant/api-keys/${keyId}`);
|
|
125
435
|
}
|
|
126
|
-
|
|
127
|
-
|
|
436
|
+
/**
|
|
437
|
+
* Get detailed usage statistics.
|
|
438
|
+
*/
|
|
439
|
+
async usageDetailed(fromDate, toDate) {
|
|
440
|
+
return this.http.get("/tenant/usage/detailed", {
|
|
441
|
+
from_date: fromDate,
|
|
442
|
+
to_date: toDate
|
|
443
|
+
});
|
|
128
444
|
}
|
|
129
|
-
// ============ Quests ============
|
|
130
445
|
/**
|
|
131
|
-
*
|
|
132
|
-
* @param userId - End user external ID
|
|
133
|
-
* @param options - Filter options
|
|
446
|
+
* Get tenant context.
|
|
134
447
|
*/
|
|
135
|
-
async
|
|
136
|
-
|
|
137
|
-
params.set("user_id", userId);
|
|
138
|
-
if (options?.category) params.set("category", options.category);
|
|
139
|
-
if (options?.limit) params.set("limit", options.limit.toString());
|
|
140
|
-
return this.request(
|
|
141
|
-
"GET",
|
|
142
|
-
`/quests/available?${params.toString()}`
|
|
143
|
-
);
|
|
448
|
+
async context() {
|
|
449
|
+
return this.http.get("/tenant/context");
|
|
144
450
|
}
|
|
145
451
|
/**
|
|
146
|
-
* Get
|
|
147
|
-
* @param questId - Quest ID
|
|
452
|
+
* Get blockchain statistics.
|
|
148
453
|
*/
|
|
149
|
-
async
|
|
150
|
-
return this.
|
|
454
|
+
async blockchainStats() {
|
|
455
|
+
return this.http.get("/tenant/blockchain/stats");
|
|
151
456
|
}
|
|
152
457
|
/**
|
|
153
|
-
*
|
|
154
|
-
* @param questId - Quest ID
|
|
155
|
-
* @param userId - End user external ID
|
|
458
|
+
* Verify a certificate on the blockchain.
|
|
156
459
|
*/
|
|
157
|
-
async
|
|
158
|
-
return this.
|
|
159
|
-
"POST",
|
|
160
|
-
`/quests/${questId}/start?user_id=${encodeURIComponent(userId)}`,
|
|
161
|
-
{}
|
|
162
|
-
);
|
|
460
|
+
async blockchainVerify(certificateId) {
|
|
461
|
+
return this.http.get(`/tenant/blockchain/verify/${certificateId}`);
|
|
163
462
|
}
|
|
164
463
|
/**
|
|
165
|
-
*
|
|
166
|
-
* @param questId - Quest ID
|
|
167
|
-
* @param userId - End user external ID
|
|
464
|
+
* List blockchain certificates.
|
|
168
465
|
*/
|
|
169
|
-
async
|
|
170
|
-
return this.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
);
|
|
466
|
+
async blockchainCertificates(limit, offset) {
|
|
467
|
+
return this.http.get("/tenant/blockchain/certificates", {
|
|
468
|
+
limit,
|
|
469
|
+
offset
|
|
470
|
+
});
|
|
174
471
|
}
|
|
175
472
|
/**
|
|
176
|
-
*
|
|
177
|
-
* @param userId - End user external ID
|
|
178
|
-
* @param status - Optional status filter
|
|
473
|
+
* Force batch settlement.
|
|
179
474
|
*/
|
|
180
|
-
async
|
|
181
|
-
|
|
182
|
-
if (status) params.set("status", status);
|
|
183
|
-
const query = params.toString();
|
|
184
|
-
return this.request(
|
|
185
|
-
"GET",
|
|
186
|
-
`/quests/user/${encodeURIComponent(userId)}/progress${query ? `?${query}` : ""}`
|
|
187
|
-
);
|
|
475
|
+
async forceBatch() {
|
|
476
|
+
return this.http.post("/tenant/events/force-batch");
|
|
188
477
|
}
|
|
189
478
|
/**
|
|
190
|
-
*
|
|
191
|
-
* @param questId - Quest ID
|
|
192
|
-
* @param userId - End user external ID
|
|
193
|
-
* @param stepIndex - Step index (0-based)
|
|
194
|
-
* @param options - Completion options
|
|
479
|
+
* Settle all pending events.
|
|
195
480
|
*/
|
|
196
|
-
async
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
{}
|
|
205
|
-
);
|
|
481
|
+
async settleAll() {
|
|
482
|
+
return this.http.post("/tenant/events/settle-all");
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Settle a specific event.
|
|
486
|
+
*/
|
|
487
|
+
async settleEvent(eventId) {
|
|
488
|
+
return this.http.post(`/tenant/events/${eventId}/settle`);
|
|
206
489
|
}
|
|
207
490
|
};
|
|
208
491
|
|
|
209
|
-
// src/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
"function attestationRoots(address wallet) view returns (bytes32 merkleRoot, uint256 eventCount, uint256 lastUpdated, string latestIpfsHash)",
|
|
214
|
-
"function getRoot(address wallet) view returns (bytes32 root, uint256 eventCount, uint256 lastUpdated, string latestIpfsHash)",
|
|
215
|
-
"function getHistoryCount(address wallet) view returns (uint256 count)",
|
|
216
|
-
"function getHistoricalRoot(address wallet, uint256 index) view returns (bytes32 root, uint256 eventCount, uint256 timestamp)",
|
|
217
|
-
"function verifyAttestation(address wallet, bytes32 leaf, bytes32[] proof) view returns (bool valid)",
|
|
218
|
-
"function computeLeaf(string ipfsHash, string eventType, uint256 timestamp) pure returns (bytes32 leaf)",
|
|
219
|
-
"function getWalletByIpfsHash(string ipfsHash) view returns (address wallet)",
|
|
220
|
-
"function authorizedUpdaters(address) view returns (bool)",
|
|
221
|
-
"function owner() view returns (address)",
|
|
222
|
-
// Write functions
|
|
223
|
-
"function updateRoot(address wallet, bytes32 newRoot, uint256 eventCount, string latestIpfsHash)",
|
|
224
|
-
"function batchUpdateRoots(address[] wallets, bytes32[] roots, uint256[] eventCounts, string[] ipfsHashes)",
|
|
225
|
-
"function setAuthorizedUpdater(address updater, bool authorized)",
|
|
226
|
-
// Events
|
|
227
|
-
"event RootUpdated(address indexed wallet, bytes32 indexed newRoot, bytes32 indexed previousRoot, uint256 eventCount, string latestIpfsHash)",
|
|
228
|
-
"event AttestationVerified(address indexed wallet, bytes32 indexed leaf, string ipfsHash, bool valid)",
|
|
229
|
-
"event UpdaterAuthorized(address indexed updater, bool authorized)"
|
|
230
|
-
];
|
|
231
|
-
var AttestationRegistryContract = class {
|
|
232
|
-
constructor(contractAddress, signerOrProvider) {
|
|
233
|
-
this.contract = new ethers.Contract(
|
|
234
|
-
contractAddress,
|
|
235
|
-
ATTESTATION_REGISTRY_ABI,
|
|
236
|
-
signerOrProvider
|
|
237
|
-
);
|
|
238
|
-
if ("getAddress" in signerOrProvider) {
|
|
239
|
-
this.signer = signerOrProvider;
|
|
240
|
-
}
|
|
492
|
+
// src/passports.ts
|
|
493
|
+
var PassportClient = class {
|
|
494
|
+
constructor(http) {
|
|
495
|
+
this.http = http;
|
|
241
496
|
}
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
497
|
+
// ---------------------------------------------------------------------------
|
|
498
|
+
// Passports
|
|
499
|
+
// ---------------------------------------------------------------------------
|
|
500
|
+
/**
|
|
501
|
+
* List all passports for the tenant
|
|
502
|
+
*/
|
|
503
|
+
async list(options = {}) {
|
|
504
|
+
const params = new URLSearchParams();
|
|
505
|
+
if (options.limit) params.append("limit", options.limit.toString());
|
|
506
|
+
if (options.offset) params.append("offset", options.offset.toString());
|
|
507
|
+
return this.http.get(`/passports?${params.toString()}`);
|
|
251
508
|
}
|
|
252
|
-
|
|
253
|
-
|
|
509
|
+
/**
|
|
510
|
+
* Get a passport by user ID
|
|
511
|
+
*/
|
|
512
|
+
async get(userId) {
|
|
513
|
+
return this.http.get(`/passports/${encodeURIComponent(userId)}`);
|
|
254
514
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
515
|
+
/**
|
|
516
|
+
* Get a passport with all field values
|
|
517
|
+
*/
|
|
518
|
+
async getWithFields(userId) {
|
|
519
|
+
const passport = await this.get(userId);
|
|
520
|
+
const fields = await this.getFieldValues(userId);
|
|
521
|
+
return { ...passport, field_values: fields };
|
|
258
522
|
}
|
|
259
|
-
|
|
260
|
-
|
|
523
|
+
/**
|
|
524
|
+
* Create a new passport for a user
|
|
525
|
+
*/
|
|
526
|
+
async create(data) {
|
|
527
|
+
return this.http.post("/passports", data);
|
|
261
528
|
}
|
|
262
|
-
|
|
263
|
-
|
|
529
|
+
/**
|
|
530
|
+
* Update a passport
|
|
531
|
+
*/
|
|
532
|
+
async update(userId, data) {
|
|
533
|
+
return this.http.put(`/passports/${encodeURIComponent(userId)}`, data);
|
|
264
534
|
}
|
|
265
|
-
|
|
266
|
-
|
|
535
|
+
/**
|
|
536
|
+
* Delete a passport
|
|
537
|
+
*/
|
|
538
|
+
async delete(userId) {
|
|
539
|
+
await this.http.delete(`/passports/${encodeURIComponent(userId)}`);
|
|
267
540
|
}
|
|
268
|
-
|
|
269
|
-
|
|
541
|
+
/**
|
|
542
|
+
* Add points to a passport
|
|
543
|
+
*/
|
|
544
|
+
async addPoints(userId, points, reason) {
|
|
545
|
+
return this.http.post(`/passports/${encodeURIComponent(userId)}/add-points`, {
|
|
546
|
+
points,
|
|
547
|
+
reason
|
|
548
|
+
});
|
|
270
549
|
}
|
|
271
|
-
|
|
272
|
-
|
|
550
|
+
/**
|
|
551
|
+
* Level up a passport
|
|
552
|
+
*/
|
|
553
|
+
async levelUp(userId) {
|
|
554
|
+
return this.http.post(`/passports/${encodeURIComponent(userId)}/level-up`, {});
|
|
273
555
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
return this.contract.updateRoot(wallet, newRoot, eventCount, latestIpfsHash);
|
|
556
|
+
/**
|
|
557
|
+
* Link a wallet address to a passport
|
|
558
|
+
*/
|
|
559
|
+
async linkWallet(userId, walletAddress) {
|
|
560
|
+
return this.update(userId, { wallet_address: walletAddress });
|
|
280
561
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
562
|
+
// ---------------------------------------------------------------------------
|
|
563
|
+
// Field Values
|
|
564
|
+
// ---------------------------------------------------------------------------
|
|
565
|
+
/**
|
|
566
|
+
* Get all field values for a passport
|
|
567
|
+
*/
|
|
568
|
+
async getFieldValues(userId) {
|
|
569
|
+
return this.http.get(`/passports/${encodeURIComponent(userId)}/fields`);
|
|
286
570
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
571
|
+
/**
|
|
572
|
+
* Set a field value manually
|
|
573
|
+
*/
|
|
574
|
+
async setFieldValue(userId, fieldKey, value) {
|
|
575
|
+
await this.http.put(`/passports/${encodeURIComponent(userId)}/fields/${fieldKey}`, value);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Recompute all computed field values
|
|
579
|
+
*/
|
|
580
|
+
async recomputeFields(userId) {
|
|
581
|
+
return this.http.post(`/passports/${encodeURIComponent(userId)}/recompute`, {});
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Assign a template to a passport
|
|
585
|
+
*/
|
|
586
|
+
async assignTemplate(userId, templateId) {
|
|
587
|
+
await this.http.post(`/passports/${encodeURIComponent(userId)}/assign-template/${templateId}`, {});
|
|
588
|
+
}
|
|
589
|
+
// ---------------------------------------------------------------------------
|
|
590
|
+
// Templates
|
|
591
|
+
// ---------------------------------------------------------------------------
|
|
592
|
+
/**
|
|
593
|
+
* List all passport templates
|
|
594
|
+
*/
|
|
595
|
+
async listTemplates() {
|
|
596
|
+
return this.http.get("/passports/templates");
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get a template by ID
|
|
600
|
+
*/
|
|
601
|
+
async getTemplate(templateId) {
|
|
602
|
+
return this.http.get(`/passports/templates/${templateId}`);
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Create a new template
|
|
606
|
+
*/
|
|
607
|
+
async createTemplate(data) {
|
|
608
|
+
return this.http.post("/passports/templates", data);
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Add a field to a template
|
|
612
|
+
*/
|
|
613
|
+
async addTemplateField(templateId, field) {
|
|
614
|
+
return this.http.post(`/passports/templates/${templateId}/fields`, field);
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Delete a template
|
|
618
|
+
*/
|
|
619
|
+
async deleteTemplate(templateId) {
|
|
620
|
+
await this.http.delete(`/passports/templates/${templateId}`);
|
|
621
|
+
}
|
|
622
|
+
// ---------------------------------------------------------------------------
|
|
623
|
+
// Badges
|
|
624
|
+
// ---------------------------------------------------------------------------
|
|
625
|
+
/**
|
|
626
|
+
* List all badges
|
|
627
|
+
*/
|
|
628
|
+
async listBadges() {
|
|
629
|
+
return this.http.get("/passports/badges");
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Create a badge
|
|
633
|
+
*/
|
|
634
|
+
async createBadge(data) {
|
|
635
|
+
return this.http.post("/passports/badges", data);
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Award a badge to a user
|
|
639
|
+
*/
|
|
640
|
+
async awardBadge(userId, badgeId, metadata) {
|
|
641
|
+
return this.http.post(`/passports/${encodeURIComponent(userId)}/badges/${badgeId}`, {
|
|
642
|
+
metadata
|
|
304
643
|
});
|
|
305
644
|
}
|
|
306
|
-
|
|
307
|
-
|
|
645
|
+
/**
|
|
646
|
+
* Get badges earned by a user
|
|
647
|
+
*/
|
|
648
|
+
async getUserBadges(userId) {
|
|
649
|
+
return this.http.get(`/passports/${encodeURIComponent(userId)}/badges`);
|
|
650
|
+
}
|
|
651
|
+
// ---------------------------------------------------------------------------
|
|
652
|
+
// Achievements
|
|
653
|
+
// ---------------------------------------------------------------------------
|
|
654
|
+
/**
|
|
655
|
+
* List all achievements
|
|
656
|
+
*/
|
|
657
|
+
async listAchievements() {
|
|
658
|
+
return this.http.get("/passports/achievements");
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Create an achievement
|
|
662
|
+
*/
|
|
663
|
+
async createAchievement(data) {
|
|
664
|
+
return this.http.post("/passports/achievements", data);
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Get achievements for a user
|
|
668
|
+
*/
|
|
669
|
+
async getUserAchievements(userId) {
|
|
670
|
+
return this.http.get(`/passports/${encodeURIComponent(userId)}/achievements`);
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Update achievement progress
|
|
674
|
+
*/
|
|
675
|
+
async updateAchievementProgress(userId, achievementId, progress) {
|
|
676
|
+
return this.http.put(
|
|
677
|
+
`/passports/${encodeURIComponent(userId)}/achievements/${achievementId}`,
|
|
678
|
+
{ progress }
|
|
679
|
+
);
|
|
308
680
|
}
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
681
|
+
// ---------------------------------------------------------------------------
|
|
682
|
+
// History
|
|
683
|
+
// ---------------------------------------------------------------------------
|
|
684
|
+
/**
|
|
685
|
+
* Get passport history/activity log
|
|
686
|
+
*/
|
|
687
|
+
async getHistory(userId, options = {}) {
|
|
688
|
+
const params = new URLSearchParams();
|
|
689
|
+
if (options.limit) params.append("limit", options.limit.toString());
|
|
690
|
+
if (options.offset) params.append("offset", options.offset.toString());
|
|
691
|
+
return this.http.get(
|
|
692
|
+
`/passports/${encodeURIComponent(userId)}/history?${params.toString()}`
|
|
316
693
|
);
|
|
317
694
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
return
|
|
695
|
+
// ---------------------------------------------------------------------------
|
|
696
|
+
// Passport V2 (Data View Integration)
|
|
697
|
+
// ---------------------------------------------------------------------------
|
|
698
|
+
/**
|
|
699
|
+
* Get passport data for a user using Passport V2 API.
|
|
700
|
+
* This integrates with custom data views for dynamic computation.
|
|
701
|
+
*
|
|
702
|
+
* @param userId - The user ID
|
|
703
|
+
* @param passportId - Optional specific passport definition ID
|
|
704
|
+
* @returns Passport data with computed fields from data view
|
|
705
|
+
*/
|
|
706
|
+
async getPassportV2(userId, passportId) {
|
|
707
|
+
const params = passportId ? `?passport_id=${passportId}` : "";
|
|
708
|
+
return this.http.get(`/passport-v2/users/${encodeURIComponent(userId)}${params}`);
|
|
332
709
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
710
|
+
/**
|
|
711
|
+
* Get passport view data for a user (alias for getPassportV2).
|
|
712
|
+
*
|
|
713
|
+
* @param userId - The user ID
|
|
714
|
+
* @param passportId - Optional specific passport definition ID
|
|
715
|
+
* @returns Passport data with computed fields from data view
|
|
716
|
+
*/
|
|
717
|
+
async getPassportView(userId, passportId) {
|
|
718
|
+
return this.getPassportV2(userId, passportId);
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Get user milestones from Passport V2.
|
|
722
|
+
*
|
|
723
|
+
* @param userId - The user ID
|
|
724
|
+
* @param passportId - Optional passport ID to filter milestones
|
|
725
|
+
* @returns List of milestones achieved by the user
|
|
726
|
+
*/
|
|
727
|
+
async getMilestones(userId, passportId) {
|
|
728
|
+
const params = passportId ? `?passport_id=${passportId}` : "";
|
|
729
|
+
return this.http.get(`/passport-v2/users/${encodeURIComponent(userId)}/milestones${params}`);
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* List available data views that can be used for passports.
|
|
733
|
+
* Includes built-in views and custom data views.
|
|
734
|
+
*
|
|
735
|
+
* @returns List of available views with their columns
|
|
736
|
+
*/
|
|
737
|
+
async listAvailableViews() {
|
|
738
|
+
return this.http.get("/passport-v2/available-views");
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* List passport definitions for the tenant.
|
|
742
|
+
*
|
|
743
|
+
* @returns List of passport definitions
|
|
744
|
+
*/
|
|
745
|
+
async listPassportDefinitions() {
|
|
746
|
+
return this.http.get("/passport-v2/definitions");
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Create a new passport definition linked to a data view.
|
|
750
|
+
*
|
|
751
|
+
* @param definition - The passport definition to create
|
|
752
|
+
* @returns Created passport definition
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* ```typescript
|
|
756
|
+
* const passport = await client.passports.createPassportDefinition({
|
|
757
|
+
* name: 'Fan Engagement Passport',
|
|
758
|
+
* description: 'Track fan engagement metrics',
|
|
759
|
+
* data_view_id: 'builtin-fan-profile', // or custom view UUID
|
|
760
|
+
* display_columns: ['fan_score', 'loyalty_tier', 'total_events'],
|
|
761
|
+
* column_labels: {
|
|
762
|
+
* fan_score: 'Engagement Score',
|
|
763
|
+
* loyalty_tier: 'Tier',
|
|
764
|
+
* total_events: 'Activities'
|
|
765
|
+
* }
|
|
766
|
+
* });
|
|
767
|
+
* ```
|
|
768
|
+
*/
|
|
769
|
+
async createPassportDefinition(definition) {
|
|
770
|
+
return this.http.post("/passport-v2/definitions", definition);
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// src/wallets.ts
|
|
775
|
+
var WalletClient = class {
|
|
776
|
+
constructor(http) {
|
|
777
|
+
this.http = http;
|
|
778
|
+
}
|
|
779
|
+
// ---------------------------------------------------------------------------
|
|
780
|
+
// Single Wallets
|
|
781
|
+
// ---------------------------------------------------------------------------
|
|
782
|
+
/**
|
|
783
|
+
* Create a single wallet for a user
|
|
784
|
+
*/
|
|
785
|
+
async create(data) {
|
|
786
|
+
return this.http.post("/wallets", data);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Get a wallet by ID
|
|
790
|
+
*/
|
|
791
|
+
async get(walletId) {
|
|
792
|
+
return this.http.get(`/wallets/${walletId}`);
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* List wallets for a user
|
|
796
|
+
*/
|
|
797
|
+
async listByUser(userId) {
|
|
798
|
+
return this.http.get(`/wallets/user/${encodeURIComponent(userId)}`);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Get wallet statistics
|
|
802
|
+
*/
|
|
803
|
+
async stats() {
|
|
804
|
+
return this.http.get("/wallets/stats");
|
|
805
|
+
}
|
|
806
|
+
// ---------------------------------------------------------------------------
|
|
807
|
+
// Dual Wallets (EOA + Smart Account)
|
|
808
|
+
// ---------------------------------------------------------------------------
|
|
809
|
+
/**
|
|
810
|
+
* Create dual wallets (EOA asset wallet + Smart Account) for a user
|
|
811
|
+
*/
|
|
812
|
+
async createDual(data) {
|
|
813
|
+
return this.http.post("/wallets/dual", data);
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Bulk create dual wallets for multiple users
|
|
817
|
+
*/
|
|
818
|
+
async createDualBulk(userIds, network = "base-sepolia") {
|
|
819
|
+
return this.http.post("/wallets/dual/bulk", {
|
|
820
|
+
user_ids: userIds,
|
|
821
|
+
network
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
// ---------------------------------------------------------------------------
|
|
825
|
+
// Balances
|
|
826
|
+
// ---------------------------------------------------------------------------
|
|
827
|
+
/**
|
|
828
|
+
* Get wallet balance
|
|
829
|
+
*/
|
|
830
|
+
async getBalance(walletId) {
|
|
831
|
+
return this.http.get(`/wallets/${walletId}/balance`);
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Get comprehensive wallet information in a single call.
|
|
835
|
+
*
|
|
836
|
+
* Returns everything about a wallet:
|
|
837
|
+
* - Basic wallet details (address, type, network)
|
|
838
|
+
* - Token balances (native + ERC20)
|
|
839
|
+
* - NFT holdings with metadata
|
|
840
|
+
* - Recent activity (swaps, transfers)
|
|
841
|
+
*
|
|
842
|
+
* @param walletId - Wallet ID to query
|
|
843
|
+
* @param options - Control what data is included
|
|
844
|
+
*/
|
|
845
|
+
async getInfo(walletId, options = {}) {
|
|
846
|
+
const params = new URLSearchParams();
|
|
847
|
+
if (options.includeBalances !== void 0) {
|
|
848
|
+
params.set("include_balances", String(options.includeBalances));
|
|
849
|
+
}
|
|
850
|
+
if (options.includeNfts !== void 0) {
|
|
851
|
+
params.set("include_nfts", String(options.includeNfts));
|
|
852
|
+
}
|
|
853
|
+
if (options.includeActivity !== void 0) {
|
|
854
|
+
params.set("include_activity", String(options.includeActivity));
|
|
855
|
+
}
|
|
856
|
+
const query = params.toString();
|
|
857
|
+
return this.http.get(
|
|
858
|
+
`/wallets/${walletId}/info${query ? `?${query}` : ""}`
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Get comprehensive summary of all wallets for a user.
|
|
863
|
+
*
|
|
864
|
+
* Returns all wallets (EOA + Smart) with aggregated stats:
|
|
865
|
+
* - Total NFTs across all wallets
|
|
866
|
+
* - Total swaps executed
|
|
867
|
+
* - Token balances (optional)
|
|
868
|
+
*
|
|
869
|
+
* @param userId - User ID to query
|
|
870
|
+
* @param includeBalances - Include token balances (requires Alchemy)
|
|
871
|
+
*/
|
|
872
|
+
async getUserSummary(userId, includeBalances = true) {
|
|
873
|
+
return this.http.get(
|
|
874
|
+
`/wallets/user/${encodeURIComponent(userId)}/summary?include_balances=${includeBalances}`
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
// ---------------------------------------------------------------------------
|
|
878
|
+
// Key Export
|
|
879
|
+
// ---------------------------------------------------------------------------
|
|
880
|
+
/**
|
|
881
|
+
* Export private key for an EOA wallet (requires acknowledgment)
|
|
882
|
+
*/
|
|
883
|
+
async exportKey(walletId) {
|
|
884
|
+
return this.http.post(`/wallets/${walletId}/export-key`, {
|
|
885
|
+
acknowledge_warning: true
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
// ---------------------------------------------------------------------------
|
|
889
|
+
// Token Transfers
|
|
890
|
+
// ---------------------------------------------------------------------------
|
|
891
|
+
/**
|
|
892
|
+
* Transfer tokens from one address to another.
|
|
893
|
+
*
|
|
894
|
+
* @param request - Transfer details
|
|
895
|
+
* @returns Transaction result with hash and status
|
|
896
|
+
*
|
|
897
|
+
* @example
|
|
898
|
+
* ```typescript
|
|
899
|
+
* const result = await client.wallets.transfer({
|
|
900
|
+
* from_address: '0x123...',
|
|
901
|
+
* to_address: '0x456...',
|
|
902
|
+
* amount: '0.1',
|
|
903
|
+
* token: 'ETH',
|
|
904
|
+
* network: 'base-sepolia',
|
|
905
|
+
* });
|
|
906
|
+
* console.log('TX Hash:', result.tx_hash);
|
|
907
|
+
* ```
|
|
908
|
+
*/
|
|
909
|
+
async transfer(request) {
|
|
910
|
+
return this.http.post("/wallets/transfer", request);
|
|
911
|
+
}
|
|
912
|
+
// ---------------------------------------------------------------------------
|
|
913
|
+
// Token Swaps
|
|
914
|
+
// ---------------------------------------------------------------------------
|
|
915
|
+
/**
|
|
916
|
+
* Get a swap quote
|
|
917
|
+
*/
|
|
918
|
+
async getSwapQuote(request) {
|
|
919
|
+
return this.http.post("/wallets/swaps/quote", request);
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Execute a token swap
|
|
923
|
+
*/
|
|
924
|
+
async executeSwap(request) {
|
|
925
|
+
return this.http.post("/wallets/swaps/execute", request);
|
|
926
|
+
}
|
|
927
|
+
// ---------------------------------------------------------------------------
|
|
928
|
+
// NFTs
|
|
929
|
+
// ---------------------------------------------------------------------------
|
|
930
|
+
/**
|
|
931
|
+
* Get NFTs for a wallet
|
|
932
|
+
*/
|
|
933
|
+
async getNFTs(walletId) {
|
|
934
|
+
return this.http.get(`/wallets/${walletId}/nfts`);
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Get all NFTs for a user (across all wallets)
|
|
938
|
+
*/
|
|
939
|
+
async getUserNFTs(userId) {
|
|
940
|
+
return this.http.get(`/wallets/user/${encodeURIComponent(userId)}/nfts`);
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Add an NFT to wallet tracking
|
|
944
|
+
*/
|
|
945
|
+
async addNFT(walletId, nft) {
|
|
946
|
+
return this.http.post(`/wallets/${walletId}/nfts`, nft);
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
// src/users.ts
|
|
951
|
+
var EndUsersClient = class {
|
|
952
|
+
constructor(http) {
|
|
953
|
+
this.http = http;
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* List end-users with pagination and filters
|
|
957
|
+
*/
|
|
958
|
+
async list(options = {}) {
|
|
959
|
+
const params = new URLSearchParams();
|
|
960
|
+
if (options.page) params.append("page", options.page.toString());
|
|
961
|
+
if (options.page_size) params.append("page_size", options.page_size.toString());
|
|
962
|
+
if (options.search) params.append("search", options.search);
|
|
963
|
+
if (options.status) params.append("status", options.status);
|
|
964
|
+
if (options.segment) params.append("segment", options.segment);
|
|
965
|
+
if (options.has_wallet !== void 0) params.append("has_wallet", options.has_wallet.toString());
|
|
966
|
+
if (options.sort_by) params.append("sort_by", options.sort_by);
|
|
967
|
+
if (options.sort_order) params.append("sort_order", options.sort_order);
|
|
968
|
+
return this.http.get(`/end-users?${params.toString()}`);
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Get an end-user by ID
|
|
972
|
+
*/
|
|
973
|
+
async get(userId) {
|
|
974
|
+
return this.http.get(`/end-users/${userId}`);
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Get an end-user by external ID
|
|
978
|
+
*/
|
|
979
|
+
async getByExternalId(externalId) {
|
|
980
|
+
return this.http.get(`/end-users/external/${encodeURIComponent(externalId)}`);
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Create an end-user manually
|
|
984
|
+
*/
|
|
985
|
+
async create(data) {
|
|
986
|
+
return this.http.post("/end-users", data);
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Update an end-user profile
|
|
990
|
+
*/
|
|
991
|
+
async update(userId, data) {
|
|
992
|
+
return this.http.patch(`/end-users/${userId}`, data);
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Delete an end-user
|
|
996
|
+
*/
|
|
997
|
+
async delete(userId) {
|
|
998
|
+
await this.http.delete(`/end-users/${userId}`);
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Link a wallet to an end-user
|
|
1002
|
+
*/
|
|
1003
|
+
async linkWallet(userId, request) {
|
|
1004
|
+
return this.http.post(`/end-users/${userId}/wallet`, request);
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Unlink wallet from an end-user
|
|
1008
|
+
*/
|
|
1009
|
+
async unlinkWallet(userId) {
|
|
1010
|
+
return this.http.delete(`/end-users/${userId}/wallet`);
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Get user activity/events
|
|
1014
|
+
*/
|
|
1015
|
+
async getActivity(userId, options = {}) {
|
|
1016
|
+
const params = new URLSearchParams();
|
|
1017
|
+
if (options.page) params.append("page", options.page.toString());
|
|
1018
|
+
if (options.page_size) params.append("page_size", options.page_size.toString());
|
|
1019
|
+
if (options.event_type) params.append("event_type", options.event_type);
|
|
1020
|
+
return this.http.get(`/end-users/${userId}/activity?${params.toString()}`);
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Add points to a user
|
|
1024
|
+
*/
|
|
1025
|
+
async addPoints(userId, points, reason) {
|
|
1026
|
+
return this.http.post(`/end-users/${userId}/points`, { points, reason });
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Add a segment to a user
|
|
1030
|
+
*/
|
|
1031
|
+
async addSegment(userId, segment) {
|
|
1032
|
+
return this.http.post(`/end-users/${userId}/segments`, { segment });
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Remove a segment from a user
|
|
1036
|
+
*/
|
|
1037
|
+
async removeSegment(userId, segment) {
|
|
1038
|
+
return this.http.delete(`/end-users/${userId}/segments/${encodeURIComponent(segment)}`);
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Merge two users (moves all data from source to target)
|
|
1042
|
+
*/
|
|
1043
|
+
async merge(request) {
|
|
1044
|
+
return this.http.post("/end-users/merge", request);
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Export users as CSV
|
|
1048
|
+
*/
|
|
1049
|
+
async export(options = {}) {
|
|
1050
|
+
const params = new URLSearchParams();
|
|
1051
|
+
if (options.segment) params.append("segment", options.segment);
|
|
1052
|
+
if (options.format) params.append("format", options.format);
|
|
1053
|
+
const response = await fetch(`/end-users/export?${params.toString()}`, {
|
|
1054
|
+
headers: { "Accept": "text/csv" }
|
|
1055
|
+
});
|
|
1056
|
+
return response.blob();
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
|
|
1060
|
+
// src/rewards.ts
|
|
1061
|
+
var RewardsClient = class {
|
|
1062
|
+
constructor(http) {
|
|
1063
|
+
this.http = http;
|
|
1064
|
+
}
|
|
1065
|
+
// ---------------------------------------------------------------------------
|
|
1066
|
+
// Reward Definitions
|
|
1067
|
+
// ---------------------------------------------------------------------------
|
|
1068
|
+
/**
|
|
1069
|
+
* List reward definitions
|
|
1070
|
+
*/
|
|
1071
|
+
async listDefinitions(options = {}) {
|
|
1072
|
+
const params = new URLSearchParams();
|
|
1073
|
+
if (options.is_active !== void 0) params.append("is_active", options.is_active.toString());
|
|
1074
|
+
if (options.reward_type) params.append("reward_type", options.reward_type);
|
|
1075
|
+
return this.http.get(`/rewards/definitions?${params.toString()}`);
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Get a reward definition by ID
|
|
1079
|
+
*/
|
|
1080
|
+
async getDefinition(definitionId) {
|
|
1081
|
+
return this.http.get(`/rewards/definitions/${definitionId}`);
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Create a reward definition
|
|
1085
|
+
*/
|
|
1086
|
+
async createDefinition(data) {
|
|
1087
|
+
return this.http.post("/rewards/definitions", data);
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Update a reward definition
|
|
1091
|
+
*/
|
|
1092
|
+
async updateDefinition(definitionId, data) {
|
|
1093
|
+
return this.http.patch(`/rewards/definitions/${definitionId}`, data);
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Delete a reward definition
|
|
1097
|
+
*/
|
|
1098
|
+
async deleteDefinition(definitionId) {
|
|
1099
|
+
await this.http.delete(`/rewards/definitions/${definitionId}`);
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Activate a reward definition
|
|
1103
|
+
*/
|
|
1104
|
+
async activateDefinition(definitionId) {
|
|
1105
|
+
return this.http.post(`/rewards/definitions/${definitionId}/activate`, {});
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Deactivate a reward definition
|
|
1109
|
+
*/
|
|
1110
|
+
async deactivateDefinition(definitionId) {
|
|
1111
|
+
return this.http.post(`/rewards/definitions/${definitionId}/deactivate`, {});
|
|
1112
|
+
}
|
|
1113
|
+
// ---------------------------------------------------------------------------
|
|
1114
|
+
// Earned Rewards
|
|
1115
|
+
// ---------------------------------------------------------------------------
|
|
1116
|
+
/**
|
|
1117
|
+
* List earned rewards
|
|
1118
|
+
*/
|
|
1119
|
+
async listEarned(options = {}) {
|
|
1120
|
+
const params = new URLSearchParams();
|
|
1121
|
+
if (options.user_id) params.append("user_id", options.user_id);
|
|
1122
|
+
if (options.definition_id) params.append("definition_id", options.definition_id);
|
|
1123
|
+
if (options.status) params.append("status", options.status);
|
|
1124
|
+
if (options.limit) params.append("limit", options.limit.toString());
|
|
1125
|
+
if (options.offset) params.append("offset", options.offset.toString());
|
|
1126
|
+
return this.http.get(`/rewards/earned?${params.toString()}`);
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Get earned rewards for a user
|
|
1130
|
+
*/
|
|
1131
|
+
async getUserRewards(userId) {
|
|
1132
|
+
return this.http.get(`/rewards/earned/user/${userId}`);
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Manually award rewards to users
|
|
1136
|
+
*/
|
|
1137
|
+
async awardManual(request) {
|
|
1138
|
+
return this.http.post("/rewards/award", request);
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Distribute pending rewards (mint NFTs, transfer tokens)
|
|
1142
|
+
*/
|
|
1143
|
+
async distributePending(earnedRewardId) {
|
|
1144
|
+
return this.http.post(`/rewards/earned/${earnedRewardId}/distribute`, {});
|
|
1145
|
+
}
|
|
1146
|
+
// ---------------------------------------------------------------------------
|
|
1147
|
+
// Reward Assets
|
|
1148
|
+
// ---------------------------------------------------------------------------
|
|
1149
|
+
/**
|
|
1150
|
+
* Upload an asset for a reward (image, metadata JSON)
|
|
1151
|
+
*/
|
|
1152
|
+
async uploadAsset(definitionId, file, assetType) {
|
|
1153
|
+
const formData = new FormData();
|
|
1154
|
+
formData.append("file", file);
|
|
1155
|
+
formData.append("asset_type", assetType);
|
|
1156
|
+
return this.http.requestMultipart(
|
|
1157
|
+
`/rewards/definitions/${definitionId}/assets`,
|
|
1158
|
+
formData
|
|
1159
|
+
);
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* List assets for a reward definition
|
|
1163
|
+
*/
|
|
1164
|
+
async listAssets(definitionId) {
|
|
1165
|
+
return this.http.get(`/rewards/definitions/${definitionId}/assets`);
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
|
|
1169
|
+
// src/quests.ts
|
|
1170
|
+
var QuestsClient = class {
|
|
1171
|
+
constructor(http) {
|
|
1172
|
+
this.http = http;
|
|
1173
|
+
}
|
|
1174
|
+
// ---------------------------------------------------------------------------
|
|
1175
|
+
// Quest CRUD
|
|
1176
|
+
// ---------------------------------------------------------------------------
|
|
1177
|
+
/**
|
|
1178
|
+
* List quests
|
|
1179
|
+
*/
|
|
1180
|
+
async list(options = {}) {
|
|
1181
|
+
const params = new URLSearchParams();
|
|
1182
|
+
if (options.status) params.append("status", options.status);
|
|
1183
|
+
if (options.category) params.append("category", options.category);
|
|
1184
|
+
if (options.is_public !== void 0) params.append("is_public", options.is_public.toString());
|
|
1185
|
+
if (options.is_featured !== void 0) params.append("is_featured", options.is_featured.toString());
|
|
1186
|
+
if (options.limit) params.append("limit", options.limit.toString());
|
|
1187
|
+
if (options.offset) params.append("offset", options.offset.toString());
|
|
1188
|
+
return this.http.get(`/quests?${params.toString()}`);
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Get a quest by ID
|
|
1192
|
+
*/
|
|
1193
|
+
async get(questId) {
|
|
1194
|
+
return this.http.get(`/quests/${questId}`);
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Get a quest by slug
|
|
1198
|
+
*/
|
|
1199
|
+
async getBySlug(slug) {
|
|
1200
|
+
return this.http.get(`/quests/slug/${encodeURIComponent(slug)}`);
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Create a quest
|
|
1204
|
+
*/
|
|
1205
|
+
async create(data) {
|
|
1206
|
+
return this.http.post("/quests", data);
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Update a quest
|
|
1210
|
+
*/
|
|
1211
|
+
async update(questId, data) {
|
|
1212
|
+
return this.http.put(`/quests/${questId}`, data);
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Delete a quest
|
|
1216
|
+
*/
|
|
1217
|
+
async delete(questId) {
|
|
1218
|
+
await this.http.delete(`/quests/${questId}`);
|
|
1219
|
+
}
|
|
1220
|
+
// ---------------------------------------------------------------------------
|
|
1221
|
+
// Quest Status
|
|
1222
|
+
// ---------------------------------------------------------------------------
|
|
1223
|
+
/**
|
|
1224
|
+
* Activate a quest
|
|
1225
|
+
*/
|
|
1226
|
+
async activate(questId) {
|
|
1227
|
+
return this.http.post(`/quests/${questId}/activate`, {});
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Pause a quest
|
|
1231
|
+
*/
|
|
1232
|
+
async pause(questId) {
|
|
1233
|
+
return this.http.post(`/quests/${questId}/pause`, {});
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Archive a quest
|
|
1237
|
+
*/
|
|
1238
|
+
async archive(questId) {
|
|
1239
|
+
return this.http.post(`/quests/${questId}/archive`, {});
|
|
1240
|
+
}
|
|
1241
|
+
// ---------------------------------------------------------------------------
|
|
1242
|
+
// User Progress
|
|
1243
|
+
// ---------------------------------------------------------------------------
|
|
1244
|
+
/**
|
|
1245
|
+
* Get quest with user progress
|
|
1246
|
+
*/
|
|
1247
|
+
async getWithProgress(questId, userId) {
|
|
1248
|
+
return this.http.get(`/quests/${questId}/progress/${encodeURIComponent(userId)}`);
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* List quests with progress for a user
|
|
1252
|
+
*/
|
|
1253
|
+
async listWithProgress(userId, options = {}) {
|
|
1254
|
+
const params = new URLSearchParams();
|
|
1255
|
+
params.append("user_id", userId);
|
|
1256
|
+
if (options.status) params.append("status", options.status);
|
|
1257
|
+
if (options.category) params.append("category", options.category);
|
|
1258
|
+
return this.http.get(`/quests/with-progress?${params.toString()}`);
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Start a quest for a user
|
|
1262
|
+
*/
|
|
1263
|
+
async startQuest(questId, userId) {
|
|
1264
|
+
return this.http.post(`/quests/${questId}/start`, { user_id: userId });
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Get user's progress on a quest
|
|
1268
|
+
*/
|
|
1269
|
+
async getUserProgress(questId, userId) {
|
|
1270
|
+
return this.http.get(`/quests/${questId}/progress/${encodeURIComponent(userId)}`);
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Complete a step manually
|
|
1274
|
+
*/
|
|
1275
|
+
async completeStep(questId, userId, stepId) {
|
|
1276
|
+
return this.http.post(`/quests/${questId}/steps/${stepId}/complete`, {
|
|
1277
|
+
user_id: userId
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Get all quest progress for a user
|
|
1282
|
+
*/
|
|
1283
|
+
async getAllUserProgress(userId) {
|
|
1284
|
+
return this.http.get(`/quests/user/${encodeURIComponent(userId)}/progress`);
|
|
1285
|
+
}
|
|
1286
|
+
// ---------------------------------------------------------------------------
|
|
1287
|
+
// Quest Steps
|
|
1288
|
+
// ---------------------------------------------------------------------------
|
|
1289
|
+
/**
|
|
1290
|
+
* Add a step to a quest
|
|
1291
|
+
*/
|
|
1292
|
+
async addStep(questId, step) {
|
|
1293
|
+
return this.http.post(`/quests/${questId}/steps`, step);
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Update a step
|
|
1297
|
+
*/
|
|
1298
|
+
async updateStep(questId, stepId, data) {
|
|
1299
|
+
return this.http.put(`/quests/${questId}/steps/${stepId}`, data);
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Delete a step
|
|
1303
|
+
*/
|
|
1304
|
+
async deleteStep(questId, stepId) {
|
|
1305
|
+
await this.http.delete(`/quests/${questId}/steps/${stepId}`);
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Reorder steps
|
|
1309
|
+
*/
|
|
1310
|
+
async reorderSteps(questId, stepIds) {
|
|
1311
|
+
return this.http.post(`/quests/${questId}/steps/reorder`, { step_ids: stepIds });
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
// src/schemas.ts
|
|
1316
|
+
var SchemasClient = class {
|
|
1317
|
+
constructor(http) {
|
|
1318
|
+
this.http = http;
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* List schemas
|
|
1322
|
+
*/
|
|
1323
|
+
async list(options = {}) {
|
|
1324
|
+
const params = new URLSearchParams();
|
|
1325
|
+
if (options.status) params.append("status", options.status);
|
|
1326
|
+
if (options.search) params.append("search", options.search);
|
|
1327
|
+
if (options.limit) params.append("limit", options.limit.toString());
|
|
1328
|
+
if (options.offset) params.append("offset", options.offset.toString());
|
|
1329
|
+
return this.http.get(`/schemas?${params.toString()}`);
|
|
1330
|
+
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Get a schema by name and optional version
|
|
1333
|
+
*/
|
|
1334
|
+
async get(name, version) {
|
|
1335
|
+
const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/schemas/${encodeURIComponent(name)}`;
|
|
1336
|
+
return this.http.get(path);
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Create a schema from YAML content
|
|
1340
|
+
*
|
|
1341
|
+
* Example YAML:
|
|
1342
|
+
* ```yaml
|
|
1343
|
+
* name: my_event
|
|
1344
|
+
* version: "1.0"
|
|
1345
|
+
* description: My custom event schema
|
|
1346
|
+
*
|
|
1347
|
+
* fields:
|
|
1348
|
+
* user_id:
|
|
1349
|
+
* type: string
|
|
1350
|
+
* required: true
|
|
1351
|
+
* amount:
|
|
1352
|
+
* type: number
|
|
1353
|
+
* min: 0
|
|
1354
|
+
* status:
|
|
1355
|
+
* type: enum
|
|
1356
|
+
* values: [pending, completed, failed]
|
|
1357
|
+
* ```
|
|
1358
|
+
*/
|
|
1359
|
+
async create(yamlContent) {
|
|
1360
|
+
return this.http.post("/schemas", { yaml_content: yamlContent });
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Update a schema (creates new version)
|
|
1364
|
+
*/
|
|
1365
|
+
async update(name, yamlContent) {
|
|
1366
|
+
return this.http.put(`/schemas/${encodeURIComponent(name)}`, {
|
|
1367
|
+
yaml_content: yamlContent
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Delete a schema
|
|
1372
|
+
*/
|
|
1373
|
+
async delete(name, version) {
|
|
1374
|
+
const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/schemas/${encodeURIComponent(name)}`;
|
|
1375
|
+
await this.http.delete(path);
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Activate a schema (make it available for validation)
|
|
1379
|
+
*/
|
|
1380
|
+
async activate(name, version) {
|
|
1381
|
+
const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}/activate` : `/schemas/${encodeURIComponent(name)}/activate`;
|
|
1382
|
+
return this.http.post(path, {});
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Deprecate a schema
|
|
1386
|
+
*/
|
|
1387
|
+
async deprecate(name, version) {
|
|
1388
|
+
const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}/deprecate` : `/schemas/${encodeURIComponent(name)}/deprecate`;
|
|
1389
|
+
return this.http.post(path, {});
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Set a schema as the default for its name
|
|
1393
|
+
*/
|
|
1394
|
+
async setDefault(name, version) {
|
|
1395
|
+
return this.http.post(
|
|
1396
|
+
`/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}/set-default`,
|
|
1397
|
+
{}
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Validate data against a schema
|
|
1402
|
+
*/
|
|
1403
|
+
async validate(request) {
|
|
1404
|
+
return this.http.post("/schemas/validate", request);
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Validate data against multiple schemas
|
|
1408
|
+
*/
|
|
1409
|
+
async validateMultiple(schemaNames, data) {
|
|
1410
|
+
return this.http.post("/schemas/validate/batch", {
|
|
1411
|
+
schema_names: schemaNames,
|
|
1412
|
+
data
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Get schema usage statistics
|
|
1417
|
+
*/
|
|
1418
|
+
async getUsageStats(name) {
|
|
1419
|
+
return this.http.get(`/schemas/${encodeURIComponent(name)}/stats`);
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Clone a schema with a new name
|
|
1423
|
+
*/
|
|
1424
|
+
async clone(sourceName, newName, newVersion) {
|
|
1425
|
+
return this.http.post(`/schemas/${encodeURIComponent(sourceName)}/clone`, {
|
|
1426
|
+
new_name: newName,
|
|
1427
|
+
new_version: newVersion
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
// src/dataviews.ts
|
|
1433
|
+
var DataViewsClient = class {
|
|
1434
|
+
constructor(http) {
|
|
1435
|
+
this.http = http;
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* List all available data views.
|
|
1439
|
+
* Returns own views, public views from other tenants, and builtin views.
|
|
1440
|
+
*/
|
|
1441
|
+
async list() {
|
|
1442
|
+
return this.http.get("/data-mesh/views");
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* Get detailed information about a specific data view.
|
|
1446
|
+
*/
|
|
1447
|
+
async get(viewName) {
|
|
1448
|
+
return this.http.get(`/data-mesh/views/custom/${viewName}`);
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Create a new custom data view.
|
|
1452
|
+
*
|
|
1453
|
+
* @example
|
|
1454
|
+
* ```typescript
|
|
1455
|
+
* const view = await client.dataViews.create({
|
|
1456
|
+
* name: 'engagement_score',
|
|
1457
|
+
* display_name: 'User Engagement Score',
|
|
1458
|
+
* description: 'Weighted score based on user activity',
|
|
1459
|
+
* view_type: 'multi-computation',
|
|
1460
|
+
* computation: [
|
|
1461
|
+
* {
|
|
1462
|
+
* type: 'score',
|
|
1463
|
+
* name: 'activity_score',
|
|
1464
|
+
* event_types: ['page_view', 'purchase'],
|
|
1465
|
+
* event_weights: { page_view: 1, purchase: 10 },
|
|
1466
|
+
* max_score: 1000
|
|
1467
|
+
* },
|
|
1468
|
+
* {
|
|
1469
|
+
* type: 'tier',
|
|
1470
|
+
* name: 'loyalty_tier',
|
|
1471
|
+
* score_source: 'activity_score',
|
|
1472
|
+
* tiers: [
|
|
1473
|
+
* { name: 'Bronze', min: 0, max: 100 },
|
|
1474
|
+
* { name: 'Silver', min: 100, max: 500 },
|
|
1475
|
+
* { name: 'Gold', min: 500, max: 1000 }
|
|
1476
|
+
* ]
|
|
1477
|
+
* }
|
|
1478
|
+
* ]
|
|
1479
|
+
* });
|
|
1480
|
+
* ```
|
|
1481
|
+
*/
|
|
1482
|
+
async create(request) {
|
|
1483
|
+
return this.http.post("/data-mesh/views/custom", request);
|
|
1484
|
+
}
|
|
1485
|
+
/**
|
|
1486
|
+
* Update an existing data view.
|
|
1487
|
+
*/
|
|
1488
|
+
async update(viewName, request) {
|
|
1489
|
+
return this.http.patch(`/data-mesh/views/custom/${viewName}`, request);
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Delete a data view.
|
|
1493
|
+
*/
|
|
1494
|
+
async delete(viewName) {
|
|
1495
|
+
await this.http.delete(`/data-mesh/views/custom/${viewName}`);
|
|
1496
|
+
}
|
|
1497
|
+
/**
|
|
1498
|
+
* Execute a data view for a specific user.
|
|
1499
|
+
*
|
|
1500
|
+
* The identifier can be either:
|
|
1501
|
+
* - A wallet address (0x...) - queries web3-bound events
|
|
1502
|
+
* - A user_id - queries all events for that user
|
|
1503
|
+
*
|
|
1504
|
+
* @example
|
|
1505
|
+
* ```typescript
|
|
1506
|
+
* // By user ID
|
|
1507
|
+
* const result = await client.dataViews.execute('user-123', 'fan_score');
|
|
1508
|
+
*
|
|
1509
|
+
* // By wallet address
|
|
1510
|
+
* const result = await client.dataViews.execute('0x123...abc', 'fan_score');
|
|
1511
|
+
*
|
|
1512
|
+
* console.log('Data:', result.data);
|
|
1513
|
+
* console.log('Events processed:', result.total_events);
|
|
1514
|
+
* ```
|
|
1515
|
+
*/
|
|
1516
|
+
async execute(identifier, viewName) {
|
|
1517
|
+
return this.http.get(
|
|
1518
|
+
`/data-mesh/views/${identifier}/custom/${viewName}`
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* Preview a data view computation without saving it.
|
|
1523
|
+
* Useful for testing computation configurations before creating a view.
|
|
1524
|
+
*
|
|
1525
|
+
* @example
|
|
1526
|
+
* ```typescript
|
|
1527
|
+
* const preview = await client.dataViews.preview({
|
|
1528
|
+
* wallet_address: '0x123...',
|
|
1529
|
+
* computation: {
|
|
1530
|
+
* type: 'score',
|
|
1531
|
+
* event_types: ['purchase', 'login'],
|
|
1532
|
+
* event_weights: { purchase: 10, login: 1 },
|
|
1533
|
+
* max_score: 1000
|
|
1534
|
+
* },
|
|
1535
|
+
* time_window_days: 30
|
|
1536
|
+
* });
|
|
1537
|
+
* ```
|
|
1538
|
+
*/
|
|
1539
|
+
async preview(request) {
|
|
1540
|
+
return this.http.post("/data-mesh/views/preview", request);
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Get the fan profile view for a wallet.
|
|
1544
|
+
* This is a builtin view that aggregates user activity into a profile.
|
|
1545
|
+
*/
|
|
1546
|
+
async getFanProfile(walletAddress) {
|
|
1547
|
+
return this.http.get(`/data-mesh/views/${walletAddress}/fan-profile`);
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* Get the activity summary view for a wallet.
|
|
1551
|
+
* This is a builtin view that summarizes user activity over time.
|
|
1552
|
+
*/
|
|
1553
|
+
async getActivitySummary(walletAddress, days = 30) {
|
|
1554
|
+
return this.http.get(
|
|
1555
|
+
`/data-mesh/views/${walletAddress}/activity-summary`,
|
|
1556
|
+
{ days }
|
|
1557
|
+
);
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Get event metadata including available event types and their counts.
|
|
1561
|
+
* Useful for building dynamic UIs that show available event types.
|
|
1562
|
+
*/
|
|
1563
|
+
async getEventMetadata() {
|
|
1564
|
+
return this.http.get("/data-mesh/event-metadata");
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* Get available view templates for creating new views.
|
|
1568
|
+
* Templates provide pre-configured computation patterns.
|
|
1569
|
+
*/
|
|
1570
|
+
async getTemplates() {
|
|
1571
|
+
const response = await this.http.get("/data-mesh/views/templates");
|
|
1572
|
+
return response.templates || [];
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
|
|
1576
|
+
// src/client.ts
|
|
1577
|
+
var DocumentsResource = class {
|
|
1578
|
+
constructor(http) {
|
|
1579
|
+
this.http = http;
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Attest a document file.
|
|
1583
|
+
*/
|
|
1584
|
+
async attest(request) {
|
|
1585
|
+
const formData = new FormData();
|
|
1586
|
+
if (request.file instanceof Blob) {
|
|
1587
|
+
formData.append("file", request.file, request.filename || "document");
|
|
1588
|
+
} else if (request.file instanceof ArrayBuffer) {
|
|
1589
|
+
const blob = new Blob([request.file]);
|
|
1590
|
+
formData.append("file", blob, request.filename || "document");
|
|
1591
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(request.file)) {
|
|
1592
|
+
const uint8 = new Uint8Array(request.file);
|
|
1593
|
+
const blob = new Blob([uint8]);
|
|
1594
|
+
formData.append("file", blob, request.filename || "document");
|
|
1595
|
+
}
|
|
1596
|
+
formData.append("user_id", request.userId);
|
|
1597
|
+
formData.append("event_type", request.eventType || "document_uploaded");
|
|
1598
|
+
if (request.metadata) {
|
|
1599
|
+
formData.append("metadata", JSON.stringify(request.metadata));
|
|
1600
|
+
}
|
|
1601
|
+
if (request.encrypt) {
|
|
1602
|
+
formData.append("encrypt", "1");
|
|
1603
|
+
}
|
|
1604
|
+
return this.http.requestMultipart("/tenant/documents", formData);
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* Get a document by its IPFS hash.
|
|
1608
|
+
*/
|
|
1609
|
+
async get(ipfsHash) {
|
|
1610
|
+
return this.http.get(`/tenant/events/by-hash/${ipfsHash}`);
|
|
1611
|
+
}
|
|
1612
|
+
};
|
|
1613
|
+
var EventsResource = class {
|
|
1614
|
+
constructor(http) {
|
|
1615
|
+
this.http = http;
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Create a new attestation event.
|
|
1619
|
+
*/
|
|
1620
|
+
async create(request) {
|
|
1621
|
+
return this.http.post("/tenant/events", {
|
|
1622
|
+
event_type: request.eventType,
|
|
1623
|
+
user_id: request.userId,
|
|
1624
|
+
event_source: request.source || "api",
|
|
1625
|
+
data: request.data || {}
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
/**
|
|
1629
|
+
* Get an event by ID.
|
|
1630
|
+
*/
|
|
1631
|
+
async get(eventId) {
|
|
1632
|
+
return this.http.get(`/tenant/events/${eventId}`);
|
|
1633
|
+
}
|
|
1634
|
+
/**
|
|
1635
|
+
* List events with optional filters.
|
|
1636
|
+
*/
|
|
1637
|
+
async list(request = {}) {
|
|
1638
|
+
const response = await this.http.get("/tenant/events", {
|
|
1639
|
+
user_id: request.userId,
|
|
1640
|
+
event_type: request.eventType,
|
|
1641
|
+
status: request.status,
|
|
1642
|
+
start_date: request.startDate,
|
|
1643
|
+
end_date: request.endDate,
|
|
1644
|
+
limit: request.limit,
|
|
1645
|
+
offset: request.offset
|
|
1646
|
+
});
|
|
1647
|
+
return response.events || [];
|
|
1648
|
+
}
|
|
1649
|
+
/**
|
|
1650
|
+
* Search events by query.
|
|
1651
|
+
*/
|
|
1652
|
+
async search(request) {
|
|
1653
|
+
return this.http.post("/search", {
|
|
1654
|
+
query: request.query,
|
|
1655
|
+
user_id: request.userId,
|
|
1656
|
+
event_type: request.eventType,
|
|
1657
|
+
start_date: request.startDate,
|
|
1658
|
+
end_date: request.endDate,
|
|
1659
|
+
limit: request.limit,
|
|
1660
|
+
page: request.page
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
/**
|
|
1664
|
+
* Get an event by its IPFS hash.
|
|
1665
|
+
*/
|
|
1666
|
+
async byHash(ipfsHash) {
|
|
1667
|
+
return this.http.get(`/tenant/events/by-hash/${ipfsHash}`);
|
|
1668
|
+
}
|
|
1669
|
+
/**
|
|
1670
|
+
* Create multiple events in a batch.
|
|
1671
|
+
*
|
|
1672
|
+
* Note: For high-throughput ingestion, use the IngestionClient instead.
|
|
1673
|
+
* This method is a convenience wrapper that creates events sequentially.
|
|
1674
|
+
*
|
|
1675
|
+
* @param events - Array of event requests
|
|
1676
|
+
* @returns Array of created events
|
|
1677
|
+
*/
|
|
1678
|
+
async createBatch(events) {
|
|
1679
|
+
const results = [];
|
|
1680
|
+
for (const event of events) {
|
|
1681
|
+
const created = await this.create(event);
|
|
1682
|
+
results.push(created);
|
|
1683
|
+
}
|
|
1684
|
+
return results;
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
var ChannelsResource = class {
|
|
1688
|
+
constructor(http) {
|
|
1689
|
+
this.http = http;
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Create a new state channel.
|
|
1693
|
+
*/
|
|
1694
|
+
async create(request) {
|
|
1695
|
+
return this.http.post("/channels", {
|
|
1696
|
+
name: request.name,
|
|
1697
|
+
description: request.description
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* Get a channel by ID.
|
|
1702
|
+
*/
|
|
1703
|
+
async get(channelId) {
|
|
1704
|
+
return this.http.get(`/channels/${channelId}`);
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Get detailed status of a channel.
|
|
1708
|
+
*/
|
|
1709
|
+
async status(channelId) {
|
|
1710
|
+
return this.http.get(`/channels/${channelId}/status`);
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* List all channels.
|
|
1714
|
+
*/
|
|
1715
|
+
async list(limit = 50, offset = 0) {
|
|
1716
|
+
const response = await this.http.get("/channels", {
|
|
1717
|
+
limit,
|
|
1718
|
+
offset
|
|
1719
|
+
});
|
|
1720
|
+
return response.channels || [];
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Stream an event to a channel.
|
|
1724
|
+
*/
|
|
1725
|
+
async stream(channelId, request) {
|
|
1726
|
+
return this.http.post(`/channels/${channelId}/stream`, {
|
|
1727
|
+
event_type: request.eventType,
|
|
1728
|
+
user_id: request.userId,
|
|
1729
|
+
event_source: request.source || "sdk",
|
|
1730
|
+
data: request.data
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Stream multiple events in a single request.
|
|
1735
|
+
*/
|
|
1736
|
+
async streamBatch(channelId, events) {
|
|
1737
|
+
return this.http.post(`/channels/${channelId}/stream/batch`, {
|
|
1738
|
+
events
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Settle a channel on-chain.
|
|
1743
|
+
*/
|
|
1744
|
+
async settle(channelId) {
|
|
1745
|
+
return this.http.post(`/channels/${channelId}/settle`);
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Close a channel.
|
|
1749
|
+
*/
|
|
1750
|
+
async close(channelId) {
|
|
1751
|
+
return this.http.post(`/channels/${channelId}/close`);
|
|
1752
|
+
}
|
|
1753
|
+
};
|
|
1754
|
+
var CertificatesResource = class {
|
|
1755
|
+
constructor(http) {
|
|
1756
|
+
this.http = http;
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Issue a new certificate.
|
|
1760
|
+
*/
|
|
1761
|
+
async issue(request) {
|
|
1762
|
+
return this.http.post("/certificates", {
|
|
1763
|
+
recipient_name: request.recipientName,
|
|
1764
|
+
recipient_email: request.recipientEmail,
|
|
1765
|
+
title: request.title,
|
|
1766
|
+
description: request.description,
|
|
1767
|
+
metadata: request.metadata,
|
|
1768
|
+
expires_at: request.expiresAt
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
/**
|
|
1772
|
+
* Get a certificate by ID.
|
|
1773
|
+
*/
|
|
1774
|
+
async get(certificateId) {
|
|
1775
|
+
return this.http.get(`/certificates/${certificateId}`);
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* List certificates.
|
|
1779
|
+
*/
|
|
1780
|
+
async list(request = {}) {
|
|
1781
|
+
const response = await this.http.get(
|
|
1782
|
+
"/certificates",
|
|
1783
|
+
{
|
|
1784
|
+
recipient_email: request.recipientEmail,
|
|
1785
|
+
limit: request.limit,
|
|
1786
|
+
offset: request.offset
|
|
1787
|
+
}
|
|
1788
|
+
);
|
|
1789
|
+
return response.certificates || [];
|
|
1790
|
+
}
|
|
1791
|
+
/**
|
|
1792
|
+
* Revoke a certificate.
|
|
1793
|
+
*/
|
|
1794
|
+
async revoke(certificateId, reason) {
|
|
1795
|
+
return this.http.post(`/certificates/${certificateId}/revoke`, {
|
|
1796
|
+
reason
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* Verify a certificate.
|
|
1801
|
+
*/
|
|
1802
|
+
async verify(certificateId) {
|
|
1803
|
+
return this.http.get(`/verify/cert/${certificateId}`);
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
var WebhooksResource = class {
|
|
1807
|
+
constructor(http) {
|
|
1808
|
+
this.http = http;
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Create a new webhook.
|
|
1812
|
+
*/
|
|
1813
|
+
async create(request) {
|
|
1814
|
+
return this.http.post("/webhooks", {
|
|
1815
|
+
url: request.url,
|
|
1816
|
+
events: request.events,
|
|
1817
|
+
secret: request.secret
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* Get a webhook by ID.
|
|
1822
|
+
*/
|
|
1823
|
+
async get(webhookId) {
|
|
1824
|
+
return this.http.get(`/webhooks/${webhookId}`);
|
|
1825
|
+
}
|
|
1826
|
+
/**
|
|
1827
|
+
* List all webhooks.
|
|
1828
|
+
*/
|
|
1829
|
+
async list() {
|
|
1830
|
+
const response = await this.http.get("/webhooks");
|
|
1831
|
+
return response.webhooks || [];
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Update a webhook.
|
|
1835
|
+
*/
|
|
1836
|
+
async update(webhookId, request) {
|
|
1837
|
+
return this.http.patch(`/webhooks/${webhookId}`, request);
|
|
1838
|
+
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Delete a webhook.
|
|
1841
|
+
*/
|
|
1842
|
+
async delete(webhookId) {
|
|
1843
|
+
await this.http.delete(`/webhooks/${webhookId}`);
|
|
1844
|
+
}
|
|
1845
|
+
/**
|
|
1846
|
+
* Send a test event to a webhook.
|
|
1847
|
+
*/
|
|
1848
|
+
async test(webhookId) {
|
|
1849
|
+
return this.http.post(`/webhooks/${webhookId}/test`);
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1852
|
+
var ProofChain = class _ProofChain {
|
|
1853
|
+
constructor(options) {
|
|
1854
|
+
this.http = new HttpClient(options);
|
|
1855
|
+
this.documents = new DocumentsResource(this.http);
|
|
1856
|
+
this.events = new EventsResource(this.http);
|
|
1857
|
+
this.channels = new ChannelsResource(this.http);
|
|
1858
|
+
this.certificates = new CertificatesResource(this.http);
|
|
1859
|
+
this.webhooks = new WebhooksResource(this.http);
|
|
1860
|
+
this.vault = new VaultResource(this.http);
|
|
1861
|
+
this.search = new SearchResource(this.http);
|
|
1862
|
+
this.verifyResource = new VerifyResource(this.http);
|
|
1863
|
+
this.tenant = new TenantResource(this.http);
|
|
1864
|
+
this.passports = new PassportClient(this.http);
|
|
1865
|
+
this.wallets = new WalletClient(this.http);
|
|
1866
|
+
this.users = new EndUsersClient(this.http);
|
|
1867
|
+
this.rewards = new RewardsClient(this.http);
|
|
1868
|
+
this.quests = new QuestsClient(this.http);
|
|
1869
|
+
this.schemas = new SchemasClient(this.http);
|
|
1870
|
+
this.dataViews = new DataViewsClient(this.http);
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Create a client from environment variables.
|
|
1874
|
+
* Reads PROOFCHAIN_API_KEY and optionally PROOFCHAIN_BASE_URL.
|
|
1875
|
+
*/
|
|
1876
|
+
static fromEnv() {
|
|
1877
|
+
const env = typeof process !== "undefined" ? process.env : {};
|
|
1878
|
+
const apiKey = env.PROOFCHAIN_API_KEY;
|
|
1879
|
+
if (!apiKey) {
|
|
1880
|
+
throw new Error("PROOFCHAIN_API_KEY environment variable not set");
|
|
1881
|
+
}
|
|
1882
|
+
return new _ProofChain({
|
|
1883
|
+
apiKey,
|
|
1884
|
+
baseUrl: env.PROOFCHAIN_BASE_URL
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* Verify a document or event by its IPFS hash.
|
|
1889
|
+
*/
|
|
1890
|
+
async verify(ipfsHash) {
|
|
1891
|
+
return this.http.get(`/verify/${ipfsHash}`);
|
|
1892
|
+
}
|
|
1893
|
+
/**
|
|
1894
|
+
* Get information about the current tenant.
|
|
1895
|
+
*/
|
|
1896
|
+
async tenantInfo() {
|
|
1897
|
+
return this.http.get("/tenant/me");
|
|
1898
|
+
}
|
|
1899
|
+
/**
|
|
1900
|
+
* Get API usage statistics.
|
|
1901
|
+
*/
|
|
1902
|
+
async usage(period = "month") {
|
|
1903
|
+
return this.http.get("/tenant/usage", { period });
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1906
|
+
|
|
1907
|
+
// src/ingestion.ts
|
|
1908
|
+
var DEFAULT_INGEST_URL = "https://ingest.proofchain.co.za";
|
|
1909
|
+
var USER_AGENT2 = "proofchain-js/0.1.0";
|
|
1910
|
+
var IngestionClient = class {
|
|
1911
|
+
constructor(options) {
|
|
1912
|
+
this.apiKey = options.apiKey;
|
|
1913
|
+
this.ingestUrl = (options.ingestUrl || DEFAULT_INGEST_URL).replace(/\/$/, "");
|
|
1914
|
+
this.timeout = options.timeout || 3e4;
|
|
1915
|
+
}
|
|
1916
|
+
getHeaders() {
|
|
1917
|
+
return {
|
|
1918
|
+
"X-API-Key": this.apiKey,
|
|
1919
|
+
"Content-Type": "application/json",
|
|
1920
|
+
"User-Agent": USER_AGENT2
|
|
1921
|
+
};
|
|
1922
|
+
}
|
|
1923
|
+
async handleResponse(response) {
|
|
1924
|
+
const contentType = response.headers.get("content-type");
|
|
1925
|
+
const isJson = contentType?.includes("application/json");
|
|
1926
|
+
if (response.ok) {
|
|
1927
|
+
if (response.status === 204 || !isJson) {
|
|
1928
|
+
return {};
|
|
1929
|
+
}
|
|
1930
|
+
return response.json();
|
|
1931
|
+
}
|
|
1932
|
+
const body = isJson ? await response.json().catch(() => ({})) : {};
|
|
1933
|
+
const message = body.detail || body.message || `HTTP ${response.status}`;
|
|
1934
|
+
switch (response.status) {
|
|
1935
|
+
case 401:
|
|
1936
|
+
throw new AuthenticationError(message);
|
|
1937
|
+
case 422:
|
|
1938
|
+
case 400:
|
|
1939
|
+
throw new ValidationError(message, body.errors);
|
|
1940
|
+
case 429:
|
|
1941
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
1942
|
+
throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : void 0);
|
|
1943
|
+
default:
|
|
1944
|
+
if (response.status >= 500) {
|
|
1945
|
+
throw new ServerError(message, response.status);
|
|
1946
|
+
}
|
|
1947
|
+
throw new ProofChainError(message, response.status, body);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Ingest a single event using the high-performance Rust API.
|
|
1952
|
+
* Events are attested immediately upon ingestion.
|
|
1953
|
+
*/
|
|
1954
|
+
async ingest(request) {
|
|
1955
|
+
const controller = new AbortController();
|
|
1956
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
1957
|
+
try {
|
|
1958
|
+
const headers = this.getHeaders();
|
|
1959
|
+
if (request.schemaIds?.length) {
|
|
1960
|
+
headers["X-Schemas"] = request.schemaIds.join(",");
|
|
1961
|
+
}
|
|
1962
|
+
const response = await fetch(`${this.ingestUrl}/events/ingest`, {
|
|
1963
|
+
method: "POST",
|
|
1964
|
+
headers,
|
|
1965
|
+
body: JSON.stringify({
|
|
1966
|
+
user_id: request.userId,
|
|
1967
|
+
event_type: request.eventType,
|
|
1968
|
+
data: request.data || {},
|
|
1969
|
+
event_source: request.eventSource || "sdk"
|
|
1970
|
+
}),
|
|
1971
|
+
signal: controller.signal
|
|
1972
|
+
});
|
|
1973
|
+
const result = await this.handleResponse(response);
|
|
1974
|
+
return {
|
|
1975
|
+
eventId: result.event_id,
|
|
1976
|
+
certificateId: result.certificate_id,
|
|
1977
|
+
status: result.status,
|
|
1978
|
+
queuePosition: result.queue_position,
|
|
1979
|
+
estimatedConfirmation: result.estimated_confirmation
|
|
1980
|
+
};
|
|
1981
|
+
} catch (error) {
|
|
1982
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1983
|
+
throw new NetworkError("Request timed out");
|
|
1984
|
+
}
|
|
1985
|
+
throw error;
|
|
1986
|
+
} finally {
|
|
1987
|
+
clearTimeout(timeoutId);
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Ingest multiple events in a single request (up to 1000 events).
|
|
1992
|
+
* More efficient than individual calls for bulk data.
|
|
1993
|
+
*/
|
|
1994
|
+
async ingestBatch(request) {
|
|
1995
|
+
if (request.events.length > 1e3) {
|
|
1996
|
+
throw new ValidationError("Batch size cannot exceed 1000 events");
|
|
1997
|
+
}
|
|
1998
|
+
const controller = new AbortController();
|
|
1999
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout * 2);
|
|
2000
|
+
try {
|
|
2001
|
+
const response = await fetch(`${this.ingestUrl}/events/ingest/batch`, {
|
|
2002
|
+
method: "POST",
|
|
2003
|
+
headers: this.getHeaders(),
|
|
2004
|
+
body: JSON.stringify(
|
|
2005
|
+
request.events.map((e) => ({
|
|
2006
|
+
user_id: e.userId,
|
|
2007
|
+
event_type: e.eventType,
|
|
2008
|
+
data: e.data || {},
|
|
2009
|
+
event_source: e.eventSource || "sdk"
|
|
2010
|
+
}))
|
|
2011
|
+
),
|
|
2012
|
+
signal: controller.signal
|
|
2013
|
+
});
|
|
2014
|
+
const result = await this.handleResponse(response);
|
|
2015
|
+
return {
|
|
2016
|
+
totalEvents: result.total_events || result.total,
|
|
2017
|
+
queued: result.queued,
|
|
2018
|
+
failed: result.failed,
|
|
2019
|
+
results: (result.results || result.responses || []).map((r) => ({
|
|
2020
|
+
eventId: r.event_id,
|
|
2021
|
+
certificateId: r.certificate_id,
|
|
2022
|
+
status: r.status
|
|
2023
|
+
}))
|
|
2024
|
+
};
|
|
2025
|
+
} catch (error) {
|
|
2026
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2027
|
+
throw new NetworkError("Request timed out");
|
|
2028
|
+
}
|
|
2029
|
+
throw error;
|
|
2030
|
+
} finally {
|
|
2031
|
+
clearTimeout(timeoutId);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
/**
|
|
2035
|
+
* Get the status of an event by ID.
|
|
2036
|
+
*/
|
|
2037
|
+
async getEventStatus(eventId) {
|
|
2038
|
+
const controller = new AbortController();
|
|
2039
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2040
|
+
try {
|
|
2041
|
+
const response = await fetch(`${this.ingestUrl}/events/${eventId}/status`, {
|
|
2042
|
+
method: "GET",
|
|
2043
|
+
headers: this.getHeaders(),
|
|
2044
|
+
signal: controller.signal
|
|
2045
|
+
});
|
|
2046
|
+
return this.handleResponse(response);
|
|
2047
|
+
} finally {
|
|
2048
|
+
clearTimeout(timeoutId);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
};
|
|
342
2052
|
export {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
2053
|
+
AuthenticationError,
|
|
2054
|
+
AuthorizationError,
|
|
2055
|
+
CertificatesResource,
|
|
2056
|
+
ChannelsResource,
|
|
2057
|
+
DataViewsClient,
|
|
2058
|
+
DocumentsResource,
|
|
2059
|
+
EndUsersClient,
|
|
2060
|
+
EventsResource,
|
|
2061
|
+
IngestionClient,
|
|
2062
|
+
NetworkError,
|
|
2063
|
+
NotFoundError,
|
|
2064
|
+
PassportClient,
|
|
2065
|
+
ProofChain,
|
|
2066
|
+
ProofChainError,
|
|
2067
|
+
QuestsClient,
|
|
2068
|
+
RateLimitError,
|
|
2069
|
+
RewardsClient,
|
|
2070
|
+
SchemasClient,
|
|
2071
|
+
SearchResource,
|
|
2072
|
+
ServerError,
|
|
2073
|
+
TenantResource,
|
|
2074
|
+
TimeoutError,
|
|
2075
|
+
ValidationError,
|
|
2076
|
+
VaultResource,
|
|
2077
|
+
VerifyResource,
|
|
2078
|
+
WalletClient,
|
|
2079
|
+
WebhooksResource
|
|
347
2080
|
};
|