@proofchain/sdk 1.2.0 → 2.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.mjs CHANGED
@@ -1,347 +1,2090 @@
1
- // src/client.ts
2
- var AttestationClientError = class extends Error {
3
- constructor(message, status, body) {
1
+ // src/errors.ts
2
+ var ProofChainError = class extends Error {
3
+ constructor(message, statusCode, responseBody) {
4
4
  super(message);
5
- this.status = status;
6
- this.body = body;
7
- this.name = "AttestationClientError";
5
+ this.name = "ProofChainError";
6
+ this.statusCode = statusCode;
7
+ this.responseBody = responseBody;
8
8
  }
9
9
  };
10
- var AttestationClient = class {
11
- constructor(config) {
12
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
13
- this.accessToken = config.accessToken;
14
- this.timeout = config.timeout ?? 3e4;
15
- }
16
- // ============ Internal Methods ============
17
- async request(method, path, body, options) {
18
- const url = `${this.baseUrl}${path}`;
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
- const headers = {
22
- "Content-Type": "application/json",
23
- ...options?.headers
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 (this.accessToken) {
26
- headers["Authorization"] = `Bearer ${this.accessToken}`;
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
- body: body ? JSON.stringify(body) : void 0,
33
- signal: options?.signal ?? controller.signal
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
- const errorBody = await response.json().catch(() => null);
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.json();
196
+ return response.arrayBuffer();
45
197
  } catch (error) {
46
198
  clearTimeout(timeoutId);
47
- if (error instanceof AttestationClientError) throw error;
48
- throw new AttestationClientError(
49
- `Request failed: ${error.message}`,
50
- 0
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
- // ============ Auth Methods ============
55
- setAccessToken(token) {
56
- this.accessToken = token;
253
+ /**
254
+ * Get file details.
255
+ */
256
+ async get(fileId) {
257
+ return this.http.get(`/tenant/vault/files/${fileId}`);
57
258
  }
58
- clearAccessToken() {
59
- this.accessToken = void 0;
259
+ /**
260
+ * Download a file.
261
+ */
262
+ async download(fileId) {
263
+ return this.http.getRaw(`/tenant/vault/files/${fileId}/download`);
60
264
  }
61
- // ============ Health ============
62
- async health() {
63
- return this.request("GET", "/health");
265
+ /**
266
+ * Delete a file.
267
+ */
268
+ async delete(fileId) {
269
+ await this.http.delete(`/tenant/vault/files/${fileId}`);
64
270
  }
65
- // ============ Authentication ============
66
- async requestChallenge(walletAddress) {
67
- return this.request("POST", "/auth/web3/challenge", {
68
- wallet_address: walletAddress
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
- async verifySignature(walletAddress, signature, message) {
72
- const response = await this.request("POST", "/auth/web3/verify", {
73
- wallet_address: walletAddress,
74
- signature,
75
- message
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
- // ============ Events ============
83
- async createEvent(event) {
84
- return this.request("POST", "/events", event);
288
+ /**
289
+ * Delete a folder.
290
+ */
291
+ async deleteFolder(folderId) {
292
+ await this.http.delete(`/tenant/vault/folders/${folderId}`);
85
293
  }
86
- async getEvents(userId, options) {
87
- const params = new URLSearchParams();
88
- if (options?.limit) params.set("limit", options.limit.toString());
89
- if (options?.offset) params.set("offset", options.offset.toString());
90
- if (options?.eventType) params.set("event_type", options.eventType);
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
- async queryEvents(userId, query) {
99
- return this.request(
100
- "POST",
101
- `/data/events/${userId}/query`,
102
- query
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
- // ============ Merkle Tree ============
106
- async rebuildMerkleTree(userId) {
107
- return this.request("POST", `/merkle/rebuild/${userId}`);
360
+ };
361
+
362
+ // src/resources/verify.ts
363
+ var VerifyResource = class {
364
+ constructor(http) {
365
+ this.http = http;
108
366
  }
109
- async getMerkleRoot(userId) {
110
- return this.request("GET", `/merkle/root/${userId}`);
367
+ /**
368
+ * Verify a certificate by ID.
369
+ */
370
+ async certificate(certificateId) {
371
+ return this.http.get(`/verify/cert/${certificateId}`);
111
372
  }
112
- async getMerkleProof(userId, ipfsHash) {
113
- return this.request("GET", `/merkle/proof/${userId}/${ipfsHash}`);
373
+ /**
374
+ * Verify an event by IPFS hash.
375
+ */
376
+ async event(ipfsHash) {
377
+ return this.http.get(`/verify/event/${ipfsHash}`);
114
378
  }
115
- async verifyMerkleProof(leaf, proof, root) {
116
- return this.request("POST", "/merkle/verify", {
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
- // ============ Wallets ============
123
- async linkWallet(request) {
124
- return this.request("POST", "/wallet/link", request);
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
- async getWalletStatus(userId) {
127
- return this.request("GET", `/wallet/status/${userId}`);
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
- * List available quests for a user
132
- * @param userId - End user external ID
133
- * @param options - Filter options
446
+ * Get tenant context.
134
447
  */
135
- async getAvailableQuests(userId, options) {
136
- const params = new URLSearchParams();
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 a specific quest by ID with all steps
147
- * @param questId - Quest ID
452
+ * Get blockchain statistics.
148
453
  */
149
- async getQuest(questId) {
150
- return this.request("GET", `/quests/${questId}`);
454
+ async blockchainStats() {
455
+ return this.http.get("/tenant/blockchain/stats");
151
456
  }
152
457
  /**
153
- * Start a quest for a user
154
- * @param questId - Quest ID
155
- * @param userId - End user external ID
458
+ * Verify a certificate on the blockchain.
156
459
  */
157
- async startQuest(questId, userId) {
158
- return this.request(
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
- * Get user's progress on a specific quest
166
- * @param questId - Quest ID
167
- * @param userId - End user external ID
464
+ * List blockchain certificates.
168
465
  */
169
- async getQuestProgress(questId, userId) {
170
- return this.request(
171
- "GET",
172
- `/quests/${questId}/progress/${encodeURIComponent(userId)}`
173
- );
466
+ async blockchainCertificates(limit, offset) {
467
+ return this.http.get("/tenant/blockchain/certificates", {
468
+ limit,
469
+ offset
470
+ });
174
471
  }
175
472
  /**
176
- * Get all quest progress for a user
177
- * @param userId - End user external ID
178
- * @param status - Optional status filter
473
+ * Force batch settlement.
179
474
  */
180
- async getUserQuestProgress(userId, status) {
181
- const params = new URLSearchParams();
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
- * Complete or increment a quest step
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 completeQuestStep(questId, userId, stepIndex, options) {
197
- const params = new URLSearchParams();
198
- if (options?.count) params.set("count", options.count.toString());
199
- if (options?.value) params.set("value", options.value);
200
- const query = params.toString();
201
- return this.request(
202
- "POST",
203
- `/quests/${questId}/progress/${encodeURIComponent(userId)}/step/${stepIndex}/complete${query ? `?${query}` : ""}`,
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/contract.ts
210
- import { ethers } from "ethers";
211
- var ATTESTATION_REGISTRY_ABI = [
212
- // Read functions
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
- // ============ Read Functions ============
243
- async getRoot(wallet) {
244
- const [merkleRoot, eventCount, lastUpdated, latestIpfsHash] = await this.contract.getRoot(wallet);
245
- return {
246
- merkleRoot,
247
- eventCount,
248
- lastUpdated,
249
- latestIpfsHash
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
- async getHistoryCount(wallet) {
253
- return this.contract.getHistoryCount(wallet);
509
+ /**
510
+ * Get a passport by user ID
511
+ */
512
+ async get(userId) {
513
+ return this.http.get(`/passports/${encodeURIComponent(userId)}`);
254
514
  }
255
- async getHistoricalRoot(wallet, index) {
256
- const [merkleRoot, eventCount, timestamp] = await this.contract.getHistoricalRoot(wallet, index);
257
- return { merkleRoot, eventCount, timestamp };
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
- async verifyAttestation(wallet, leaf, proof) {
260
- return this.contract.verifyAttestation(wallet, leaf, proof);
523
+ /**
524
+ * Create a new passport for a user
525
+ */
526
+ async create(data) {
527
+ return this.http.post("/passports", data);
261
528
  }
262
- async computeLeaf(ipfsHash, eventType, timestamp) {
263
- return this.contract.computeLeaf(ipfsHash, eventType, timestamp);
529
+ /**
530
+ * Update a passport
531
+ */
532
+ async update(userId, data) {
533
+ return this.http.put(`/passports/${encodeURIComponent(userId)}`, data);
264
534
  }
265
- async getWalletByIpfsHash(ipfsHash) {
266
- return this.contract.getWalletByIpfsHash(ipfsHash);
535
+ /**
536
+ * Delete a passport
537
+ */
538
+ async delete(userId) {
539
+ await this.http.delete(`/passports/${encodeURIComponent(userId)}`);
267
540
  }
268
- async isAuthorizedUpdater(address) {
269
- return this.contract.authorizedUpdaters(address);
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
- async owner() {
272
- return this.contract.owner();
550
+ /**
551
+ * Level up a passport
552
+ */
553
+ async levelUp(userId) {
554
+ return this.http.post(`/passports/${encodeURIComponent(userId)}/level-up`, {});
273
555
  }
274
- // ============ Write Functions ============
275
- async updateRoot(wallet, newRoot, eventCount, latestIpfsHash) {
276
- if (!this.signer) {
277
- throw new Error("Signer required for write operations");
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
- async batchUpdateRoots(wallets, roots, eventCounts, ipfsHashes) {
282
- if (!this.signer) {
283
- throw new Error("Signer required for write operations");
284
- }
285
- return this.contract.batchUpdateRoots(wallets, roots, eventCounts, ipfsHashes);
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
- async setAuthorizedUpdater(updater, authorized) {
288
- if (!this.signer) {
289
- throw new Error("Signer required for write operations");
290
- }
291
- return this.contract.setAuthorizedUpdater(updater, authorized);
292
- }
293
- // ============ Event Listeners ============
294
- onRootUpdated(callback, filter) {
295
- const eventFilter = this.contract.filters.RootUpdated(filter?.wallet);
296
- this.contract.on(eventFilter, (wallet, newRoot, previousRoot, eventCount, latestIpfsHash) => {
297
- callback({
298
- wallet,
299
- newRoot,
300
- previousRoot,
301
- eventCount,
302
- latestIpfsHash
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
- removeAllListeners() {
307
- this.contract.removeAllListeners();
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
- // ============ Utilities ============
310
- static computeLeafOffchain(ipfsHash, eventType, timestamp) {
311
- return ethers.keccak256(
312
- ethers.solidityPacked(
313
- ["string", "string", "uint256"],
314
- [ipfsHash, eventType, timestamp]
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
- static verifyProofOffchain(leaf, proof, root) {
319
- let computedHash = leaf;
320
- for (const proofElement of proof) {
321
- if (computedHash < proofElement) {
322
- computedHash = ethers.keccak256(
323
- ethers.solidityPacked(["bytes32", "bytes32"], [computedHash, proofElement])
324
- );
325
- } else {
326
- computedHash = ethers.keccak256(
327
- ethers.solidityPacked(["bytes32", "bytes32"], [proofElement, computedHash])
328
- );
329
- }
330
- }
331
- return computedHash === root;
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
- // src/index.ts
336
- function createClient(baseUrl, accessToken) {
337
- return new AttestationClient({
338
- baseUrl,
339
- accessToken
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
+ * List all users who have wallets, grouped by user_id.
808
+ *
809
+ * @param limit - Maximum number of users to return (default 50)
810
+ * @param offset - Offset for pagination (default 0)
811
+ * @returns List of users with their wallets
812
+ */
813
+ async listUsersWithWallets(limit = 50, offset = 0) {
814
+ return this.http.get(`/wallets/users-with-wallets?limit=${limit}&offset=${offset}`);
815
+ }
816
+ // ---------------------------------------------------------------------------
817
+ // Dual Wallets (EOA + Smart Account)
818
+ // ---------------------------------------------------------------------------
819
+ /**
820
+ * Create dual wallets (EOA asset wallet + Smart Account) for a user
821
+ */
822
+ async createDual(data) {
823
+ return this.http.post("/wallets/dual", data);
824
+ }
825
+ /**
826
+ * Bulk create dual wallets for multiple users
827
+ */
828
+ async createDualBulk(userIds, network = "base-sepolia") {
829
+ return this.http.post("/wallets/dual/bulk", {
830
+ user_ids: userIds,
831
+ network
832
+ });
833
+ }
834
+ // ---------------------------------------------------------------------------
835
+ // Balances
836
+ // ---------------------------------------------------------------------------
837
+ /**
838
+ * Get wallet balance
839
+ */
840
+ async getBalance(walletId) {
841
+ return this.http.get(`/wallets/${walletId}/balance`);
842
+ }
843
+ /**
844
+ * Get comprehensive wallet information in a single call.
845
+ *
846
+ * Returns everything about a wallet:
847
+ * - Basic wallet details (address, type, network)
848
+ * - Token balances (native + ERC20)
849
+ * - NFT holdings with metadata
850
+ * - Recent activity (swaps, transfers)
851
+ *
852
+ * @param walletId - Wallet ID to query
853
+ * @param options - Control what data is included
854
+ */
855
+ async getInfo(walletId, options = {}) {
856
+ const params = new URLSearchParams();
857
+ if (options.includeBalances !== void 0) {
858
+ params.set("include_balances", String(options.includeBalances));
859
+ }
860
+ if (options.includeNfts !== void 0) {
861
+ params.set("include_nfts", String(options.includeNfts));
862
+ }
863
+ if (options.includeActivity !== void 0) {
864
+ params.set("include_activity", String(options.includeActivity));
865
+ }
866
+ const query = params.toString();
867
+ return this.http.get(
868
+ `/wallets/${walletId}/info${query ? `?${query}` : ""}`
869
+ );
870
+ }
871
+ /**
872
+ * Get comprehensive summary of all wallets for a user.
873
+ *
874
+ * Returns all wallets (EOA + Smart) with aggregated stats:
875
+ * - Total NFTs across all wallets
876
+ * - Total swaps executed
877
+ * - Token balances (optional)
878
+ *
879
+ * @param userId - User ID to query
880
+ * @param includeBalances - Include token balances (requires Alchemy)
881
+ */
882
+ async getUserSummary(userId, includeBalances = true) {
883
+ return this.http.get(
884
+ `/wallets/user/${encodeURIComponent(userId)}/summary?include_balances=${includeBalances}`
885
+ );
886
+ }
887
+ // ---------------------------------------------------------------------------
888
+ // Key Export
889
+ // ---------------------------------------------------------------------------
890
+ /**
891
+ * Export private key for an EOA wallet (requires acknowledgment)
892
+ */
893
+ async exportKey(walletId) {
894
+ return this.http.post(`/wallets/${walletId}/export-key`, {
895
+ acknowledge_warning: true
896
+ });
897
+ }
898
+ // ---------------------------------------------------------------------------
899
+ // Token Transfers
900
+ // ---------------------------------------------------------------------------
901
+ /**
902
+ * Transfer tokens from one address to another.
903
+ *
904
+ * @param request - Transfer details
905
+ * @returns Transaction result with hash and status
906
+ *
907
+ * @example
908
+ * ```typescript
909
+ * const result = await client.wallets.transfer({
910
+ * from_address: '0x123...',
911
+ * to_address: '0x456...',
912
+ * amount: '0.1',
913
+ * token: 'ETH',
914
+ * network: 'base-sepolia',
915
+ * });
916
+ * console.log('TX Hash:', result.tx_hash);
917
+ * ```
918
+ */
919
+ async transfer(request) {
920
+ return this.http.post("/wallets/transfer", request);
921
+ }
922
+ // ---------------------------------------------------------------------------
923
+ // Token Swaps
924
+ // ---------------------------------------------------------------------------
925
+ /**
926
+ * Get a swap quote
927
+ */
928
+ async getSwapQuote(request) {
929
+ return this.http.post("/wallets/swaps/quote", request);
930
+ }
931
+ /**
932
+ * Execute a token swap
933
+ */
934
+ async executeSwap(request) {
935
+ return this.http.post("/wallets/swaps/execute", request);
936
+ }
937
+ // ---------------------------------------------------------------------------
938
+ // NFTs
939
+ // ---------------------------------------------------------------------------
940
+ /**
941
+ * Get NFTs for a wallet
942
+ */
943
+ async getNFTs(walletId) {
944
+ return this.http.get(`/wallets/${walletId}/nfts`);
945
+ }
946
+ /**
947
+ * Get all NFTs for a user (across all wallets)
948
+ */
949
+ async getUserNFTs(userId) {
950
+ return this.http.get(`/wallets/user/${encodeURIComponent(userId)}/nfts`);
951
+ }
952
+ /**
953
+ * Add an NFT to wallet tracking
954
+ */
955
+ async addNFT(walletId, nft) {
956
+ return this.http.post(`/wallets/${walletId}/nfts`, nft);
957
+ }
958
+ };
959
+
960
+ // src/users.ts
961
+ var EndUsersClient = class {
962
+ constructor(http) {
963
+ this.http = http;
964
+ }
965
+ /**
966
+ * List end-users with pagination and filters
967
+ */
968
+ async list(options = {}) {
969
+ const params = new URLSearchParams();
970
+ if (options.page) params.append("page", options.page.toString());
971
+ if (options.page_size) params.append("page_size", options.page_size.toString());
972
+ if (options.search) params.append("search", options.search);
973
+ if (options.status) params.append("status", options.status);
974
+ if (options.segment) params.append("segment", options.segment);
975
+ if (options.has_wallet !== void 0) params.append("has_wallet", options.has_wallet.toString());
976
+ if (options.sort_by) params.append("sort_by", options.sort_by);
977
+ if (options.sort_order) params.append("sort_order", options.sort_order);
978
+ return this.http.get(`/end-users?${params.toString()}`);
979
+ }
980
+ /**
981
+ * Get an end-user by ID
982
+ */
983
+ async get(userId) {
984
+ return this.http.get(`/end-users/${userId}`);
985
+ }
986
+ /**
987
+ * Get an end-user by external ID
988
+ */
989
+ async getByExternalId(externalId) {
990
+ return this.http.get(`/end-users/external/${encodeURIComponent(externalId)}`);
991
+ }
992
+ /**
993
+ * Create an end-user manually
994
+ */
995
+ async create(data) {
996
+ return this.http.post("/end-users", data);
997
+ }
998
+ /**
999
+ * Update an end-user profile
1000
+ */
1001
+ async update(userId, data) {
1002
+ return this.http.patch(`/end-users/${userId}`, data);
1003
+ }
1004
+ /**
1005
+ * Delete an end-user
1006
+ */
1007
+ async delete(userId) {
1008
+ await this.http.delete(`/end-users/${userId}`);
1009
+ }
1010
+ /**
1011
+ * Link a wallet to an end-user
1012
+ */
1013
+ async linkWallet(userId, request) {
1014
+ return this.http.post(`/end-users/${userId}/wallet`, request);
1015
+ }
1016
+ /**
1017
+ * Unlink wallet from an end-user
1018
+ */
1019
+ async unlinkWallet(userId) {
1020
+ return this.http.delete(`/end-users/${userId}/wallet`);
1021
+ }
1022
+ /**
1023
+ * Get user activity/events
1024
+ */
1025
+ async getActivity(userId, options = {}) {
1026
+ const params = new URLSearchParams();
1027
+ if (options.page) params.append("page", options.page.toString());
1028
+ if (options.page_size) params.append("page_size", options.page_size.toString());
1029
+ if (options.event_type) params.append("event_type", options.event_type);
1030
+ return this.http.get(`/end-users/${userId}/activity?${params.toString()}`);
1031
+ }
1032
+ /**
1033
+ * Add points to a user
1034
+ */
1035
+ async addPoints(userId, points, reason) {
1036
+ return this.http.post(`/end-users/${userId}/points`, { points, reason });
1037
+ }
1038
+ /**
1039
+ * Add a segment to a user
1040
+ */
1041
+ async addSegment(userId, segment) {
1042
+ return this.http.post(`/end-users/${userId}/segments`, { segment });
1043
+ }
1044
+ /**
1045
+ * Remove a segment from a user
1046
+ */
1047
+ async removeSegment(userId, segment) {
1048
+ return this.http.delete(`/end-users/${userId}/segments/${encodeURIComponent(segment)}`);
1049
+ }
1050
+ /**
1051
+ * Merge two users (moves all data from source to target)
1052
+ */
1053
+ async merge(request) {
1054
+ return this.http.post("/end-users/merge", request);
1055
+ }
1056
+ /**
1057
+ * Export users as CSV
1058
+ */
1059
+ async export(options = {}) {
1060
+ const params = new URLSearchParams();
1061
+ if (options.segment) params.append("segment", options.segment);
1062
+ if (options.format) params.append("format", options.format);
1063
+ const response = await fetch(`/end-users/export?${params.toString()}`, {
1064
+ headers: { "Accept": "text/csv" }
1065
+ });
1066
+ return response.blob();
1067
+ }
1068
+ };
1069
+
1070
+ // src/rewards.ts
1071
+ var RewardsClient = class {
1072
+ constructor(http) {
1073
+ this.http = http;
1074
+ }
1075
+ // ---------------------------------------------------------------------------
1076
+ // Reward Definitions
1077
+ // ---------------------------------------------------------------------------
1078
+ /**
1079
+ * List reward definitions
1080
+ */
1081
+ async listDefinitions(options = {}) {
1082
+ const params = new URLSearchParams();
1083
+ if (options.is_active !== void 0) params.append("is_active", options.is_active.toString());
1084
+ if (options.reward_type) params.append("reward_type", options.reward_type);
1085
+ return this.http.get(`/rewards/definitions?${params.toString()}`);
1086
+ }
1087
+ /**
1088
+ * Get a reward definition by ID
1089
+ */
1090
+ async getDefinition(definitionId) {
1091
+ return this.http.get(`/rewards/definitions/${definitionId}`);
1092
+ }
1093
+ /**
1094
+ * Create a reward definition
1095
+ */
1096
+ async createDefinition(data) {
1097
+ return this.http.post("/rewards/definitions", data);
1098
+ }
1099
+ /**
1100
+ * Update a reward definition
1101
+ */
1102
+ async updateDefinition(definitionId, data) {
1103
+ return this.http.patch(`/rewards/definitions/${definitionId}`, data);
1104
+ }
1105
+ /**
1106
+ * Delete a reward definition
1107
+ */
1108
+ async deleteDefinition(definitionId) {
1109
+ await this.http.delete(`/rewards/definitions/${definitionId}`);
1110
+ }
1111
+ /**
1112
+ * Activate a reward definition
1113
+ */
1114
+ async activateDefinition(definitionId) {
1115
+ return this.http.post(`/rewards/definitions/${definitionId}/activate`, {});
1116
+ }
1117
+ /**
1118
+ * Deactivate a reward definition
1119
+ */
1120
+ async deactivateDefinition(definitionId) {
1121
+ return this.http.post(`/rewards/definitions/${definitionId}/deactivate`, {});
1122
+ }
1123
+ // ---------------------------------------------------------------------------
1124
+ // Earned Rewards
1125
+ // ---------------------------------------------------------------------------
1126
+ /**
1127
+ * List earned rewards
1128
+ */
1129
+ async listEarned(options = {}) {
1130
+ const params = new URLSearchParams();
1131
+ if (options.user_id) params.append("user_id", options.user_id);
1132
+ if (options.definition_id) params.append("definition_id", options.definition_id);
1133
+ if (options.status) params.append("status", options.status);
1134
+ if (options.limit) params.append("limit", options.limit.toString());
1135
+ if (options.offset) params.append("offset", options.offset.toString());
1136
+ return this.http.get(`/rewards/earned?${params.toString()}`);
1137
+ }
1138
+ /**
1139
+ * Get earned rewards for a user
1140
+ */
1141
+ async getUserRewards(userId) {
1142
+ return this.http.get(`/rewards/earned/user/${userId}`);
1143
+ }
1144
+ /**
1145
+ * Manually award rewards to users
1146
+ */
1147
+ async awardManual(request) {
1148
+ return this.http.post("/rewards/award", request);
1149
+ }
1150
+ /**
1151
+ * Distribute pending rewards (mint NFTs, transfer tokens)
1152
+ */
1153
+ async distributePending(earnedRewardId) {
1154
+ return this.http.post(`/rewards/earned/${earnedRewardId}/distribute`, {});
1155
+ }
1156
+ // ---------------------------------------------------------------------------
1157
+ // Reward Assets
1158
+ // ---------------------------------------------------------------------------
1159
+ /**
1160
+ * Upload an asset for a reward (image, metadata JSON)
1161
+ */
1162
+ async uploadAsset(definitionId, file, assetType) {
1163
+ const formData = new FormData();
1164
+ formData.append("file", file);
1165
+ formData.append("asset_type", assetType);
1166
+ return this.http.requestMultipart(
1167
+ `/rewards/definitions/${definitionId}/assets`,
1168
+ formData
1169
+ );
1170
+ }
1171
+ /**
1172
+ * List assets for a reward definition
1173
+ */
1174
+ async listAssets(definitionId) {
1175
+ return this.http.get(`/rewards/definitions/${definitionId}/assets`);
1176
+ }
1177
+ };
1178
+
1179
+ // src/quests.ts
1180
+ var QuestsClient = class {
1181
+ constructor(http) {
1182
+ this.http = http;
1183
+ }
1184
+ // ---------------------------------------------------------------------------
1185
+ // Quest CRUD
1186
+ // ---------------------------------------------------------------------------
1187
+ /**
1188
+ * List quests
1189
+ */
1190
+ async list(options = {}) {
1191
+ const params = new URLSearchParams();
1192
+ if (options.status) params.append("status", options.status);
1193
+ if (options.category) params.append("category", options.category);
1194
+ if (options.is_public !== void 0) params.append("is_public", options.is_public.toString());
1195
+ if (options.is_featured !== void 0) params.append("is_featured", options.is_featured.toString());
1196
+ if (options.limit) params.append("limit", options.limit.toString());
1197
+ if (options.offset) params.append("offset", options.offset.toString());
1198
+ return this.http.get(`/quests?${params.toString()}`);
1199
+ }
1200
+ /**
1201
+ * Get a quest by ID
1202
+ */
1203
+ async get(questId) {
1204
+ return this.http.get(`/quests/${questId}`);
1205
+ }
1206
+ /**
1207
+ * Get a quest by slug
1208
+ */
1209
+ async getBySlug(slug) {
1210
+ return this.http.get(`/quests/slug/${encodeURIComponent(slug)}`);
1211
+ }
1212
+ /**
1213
+ * Create a quest
1214
+ */
1215
+ async create(data) {
1216
+ return this.http.post("/quests", data);
1217
+ }
1218
+ /**
1219
+ * Update a quest
1220
+ */
1221
+ async update(questId, data) {
1222
+ return this.http.put(`/quests/${questId}`, data);
1223
+ }
1224
+ /**
1225
+ * Delete a quest
1226
+ */
1227
+ async delete(questId) {
1228
+ await this.http.delete(`/quests/${questId}`);
1229
+ }
1230
+ // ---------------------------------------------------------------------------
1231
+ // Quest Status
1232
+ // ---------------------------------------------------------------------------
1233
+ /**
1234
+ * Activate a quest
1235
+ */
1236
+ async activate(questId) {
1237
+ return this.http.post(`/quests/${questId}/activate`, {});
1238
+ }
1239
+ /**
1240
+ * Pause a quest
1241
+ */
1242
+ async pause(questId) {
1243
+ return this.http.post(`/quests/${questId}/pause`, {});
1244
+ }
1245
+ /**
1246
+ * Archive a quest
1247
+ */
1248
+ async archive(questId) {
1249
+ return this.http.post(`/quests/${questId}/archive`, {});
1250
+ }
1251
+ // ---------------------------------------------------------------------------
1252
+ // User Progress
1253
+ // ---------------------------------------------------------------------------
1254
+ /**
1255
+ * Get quest with user progress
1256
+ */
1257
+ async getWithProgress(questId, userId) {
1258
+ return this.http.get(`/quests/${questId}/progress/${encodeURIComponent(userId)}`);
1259
+ }
1260
+ /**
1261
+ * List quests with progress for a user
1262
+ */
1263
+ async listWithProgress(userId, options = {}) {
1264
+ const params = new URLSearchParams();
1265
+ params.append("user_id", userId);
1266
+ if (options.status) params.append("status", options.status);
1267
+ if (options.category) params.append("category", options.category);
1268
+ return this.http.get(`/quests/with-progress?${params.toString()}`);
1269
+ }
1270
+ /**
1271
+ * Start a quest for a user
1272
+ */
1273
+ async startQuest(questId, userId) {
1274
+ return this.http.post(`/quests/${questId}/start`, { user_id: userId });
1275
+ }
1276
+ /**
1277
+ * Get user's progress on a quest
1278
+ */
1279
+ async getUserProgress(questId, userId) {
1280
+ return this.http.get(`/quests/${questId}/progress/${encodeURIComponent(userId)}`);
1281
+ }
1282
+ /**
1283
+ * Complete a step manually
1284
+ */
1285
+ async completeStep(questId, userId, stepId) {
1286
+ return this.http.post(`/quests/${questId}/steps/${stepId}/complete`, {
1287
+ user_id: userId
1288
+ });
1289
+ }
1290
+ /**
1291
+ * Get all quest progress for a user
1292
+ */
1293
+ async getAllUserProgress(userId) {
1294
+ return this.http.get(`/quests/user/${encodeURIComponent(userId)}/progress`);
1295
+ }
1296
+ // ---------------------------------------------------------------------------
1297
+ // Quest Steps
1298
+ // ---------------------------------------------------------------------------
1299
+ /**
1300
+ * Add a step to a quest
1301
+ */
1302
+ async addStep(questId, step) {
1303
+ return this.http.post(`/quests/${questId}/steps`, step);
1304
+ }
1305
+ /**
1306
+ * Update a step
1307
+ */
1308
+ async updateStep(questId, stepId, data) {
1309
+ return this.http.put(`/quests/${questId}/steps/${stepId}`, data);
1310
+ }
1311
+ /**
1312
+ * Delete a step
1313
+ */
1314
+ async deleteStep(questId, stepId) {
1315
+ await this.http.delete(`/quests/${questId}/steps/${stepId}`);
1316
+ }
1317
+ /**
1318
+ * Reorder steps
1319
+ */
1320
+ async reorderSteps(questId, stepIds) {
1321
+ return this.http.post(`/quests/${questId}/steps/reorder`, { step_ids: stepIds });
1322
+ }
1323
+ };
1324
+
1325
+ // src/schemas.ts
1326
+ var SchemasClient = class {
1327
+ constructor(http) {
1328
+ this.http = http;
1329
+ }
1330
+ /**
1331
+ * List schemas
1332
+ */
1333
+ async list(options = {}) {
1334
+ const params = new URLSearchParams();
1335
+ if (options.status) params.append("status", options.status);
1336
+ if (options.search) params.append("search", options.search);
1337
+ if (options.limit) params.append("limit", options.limit.toString());
1338
+ if (options.offset) params.append("offset", options.offset.toString());
1339
+ return this.http.get(`/schemas?${params.toString()}`);
1340
+ }
1341
+ /**
1342
+ * Get a schema by name and optional version
1343
+ */
1344
+ async get(name, version) {
1345
+ const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/schemas/${encodeURIComponent(name)}`;
1346
+ return this.http.get(path);
1347
+ }
1348
+ /**
1349
+ * Create a schema from YAML content
1350
+ *
1351
+ * Example YAML:
1352
+ * ```yaml
1353
+ * name: my_event
1354
+ * version: "1.0"
1355
+ * description: My custom event schema
1356
+ *
1357
+ * fields:
1358
+ * user_id:
1359
+ * type: string
1360
+ * required: true
1361
+ * amount:
1362
+ * type: number
1363
+ * min: 0
1364
+ * status:
1365
+ * type: enum
1366
+ * values: [pending, completed, failed]
1367
+ * ```
1368
+ */
1369
+ async create(yamlContent) {
1370
+ return this.http.post("/schemas", { yaml_content: yamlContent });
1371
+ }
1372
+ /**
1373
+ * Update a schema (creates new version)
1374
+ */
1375
+ async update(name, yamlContent) {
1376
+ return this.http.put(`/schemas/${encodeURIComponent(name)}`, {
1377
+ yaml_content: yamlContent
1378
+ });
1379
+ }
1380
+ /**
1381
+ * Delete a schema
1382
+ */
1383
+ async delete(name, version) {
1384
+ const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/schemas/${encodeURIComponent(name)}`;
1385
+ await this.http.delete(path);
1386
+ }
1387
+ /**
1388
+ * Activate a schema (make it available for validation)
1389
+ */
1390
+ async activate(name, version) {
1391
+ const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}/activate` : `/schemas/${encodeURIComponent(name)}/activate`;
1392
+ return this.http.post(path, {});
1393
+ }
1394
+ /**
1395
+ * Deprecate a schema
1396
+ */
1397
+ async deprecate(name, version) {
1398
+ const path = version ? `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}/deprecate` : `/schemas/${encodeURIComponent(name)}/deprecate`;
1399
+ return this.http.post(path, {});
1400
+ }
1401
+ /**
1402
+ * Set a schema as the default for its name
1403
+ */
1404
+ async setDefault(name, version) {
1405
+ return this.http.post(
1406
+ `/schemas/${encodeURIComponent(name)}/${encodeURIComponent(version)}/set-default`,
1407
+ {}
1408
+ );
1409
+ }
1410
+ /**
1411
+ * Validate data against a schema
1412
+ */
1413
+ async validate(request) {
1414
+ return this.http.post("/schemas/validate", request);
1415
+ }
1416
+ /**
1417
+ * Validate data against multiple schemas
1418
+ */
1419
+ async validateMultiple(schemaNames, data) {
1420
+ return this.http.post("/schemas/validate/batch", {
1421
+ schema_names: schemaNames,
1422
+ data
1423
+ });
1424
+ }
1425
+ /**
1426
+ * Get schema usage statistics
1427
+ */
1428
+ async getUsageStats(name) {
1429
+ return this.http.get(`/schemas/${encodeURIComponent(name)}/stats`);
1430
+ }
1431
+ /**
1432
+ * Clone a schema with a new name
1433
+ */
1434
+ async clone(sourceName, newName, newVersion) {
1435
+ return this.http.post(`/schemas/${encodeURIComponent(sourceName)}/clone`, {
1436
+ new_name: newName,
1437
+ new_version: newVersion
1438
+ });
1439
+ }
1440
+ };
1441
+
1442
+ // src/dataviews.ts
1443
+ var DataViewsClient = class {
1444
+ constructor(http) {
1445
+ this.http = http;
1446
+ }
1447
+ /**
1448
+ * List all available data views.
1449
+ * Returns own views, public views from other tenants, and builtin views.
1450
+ */
1451
+ async list() {
1452
+ return this.http.get("/data-mesh/views");
1453
+ }
1454
+ /**
1455
+ * Get detailed information about a specific data view.
1456
+ */
1457
+ async get(viewName) {
1458
+ return this.http.get(`/data-mesh/views/custom/${viewName}`);
1459
+ }
1460
+ /**
1461
+ * Create a new custom data view.
1462
+ *
1463
+ * @example
1464
+ * ```typescript
1465
+ * const view = await client.dataViews.create({
1466
+ * name: 'engagement_score',
1467
+ * display_name: 'User Engagement Score',
1468
+ * description: 'Weighted score based on user activity',
1469
+ * view_type: 'multi-computation',
1470
+ * computation: [
1471
+ * {
1472
+ * type: 'score',
1473
+ * name: 'activity_score',
1474
+ * event_types: ['page_view', 'purchase'],
1475
+ * event_weights: { page_view: 1, purchase: 10 },
1476
+ * max_score: 1000
1477
+ * },
1478
+ * {
1479
+ * type: 'tier',
1480
+ * name: 'loyalty_tier',
1481
+ * score_source: 'activity_score',
1482
+ * tiers: [
1483
+ * { name: 'Bronze', min: 0, max: 100 },
1484
+ * { name: 'Silver', min: 100, max: 500 },
1485
+ * { name: 'Gold', min: 500, max: 1000 }
1486
+ * ]
1487
+ * }
1488
+ * ]
1489
+ * });
1490
+ * ```
1491
+ */
1492
+ async create(request) {
1493
+ return this.http.post("/data-mesh/views/custom", request);
1494
+ }
1495
+ /**
1496
+ * Update an existing data view.
1497
+ */
1498
+ async update(viewName, request) {
1499
+ return this.http.patch(`/data-mesh/views/custom/${viewName}`, request);
1500
+ }
1501
+ /**
1502
+ * Delete a data view.
1503
+ */
1504
+ async delete(viewName) {
1505
+ await this.http.delete(`/data-mesh/views/custom/${viewName}`);
1506
+ }
1507
+ /**
1508
+ * Execute a data view for a specific user.
1509
+ *
1510
+ * The identifier can be either:
1511
+ * - A wallet address (0x...) - queries web3-bound events
1512
+ * - A user_id - queries all events for that user
1513
+ *
1514
+ * @example
1515
+ * ```typescript
1516
+ * // By user ID
1517
+ * const result = await client.dataViews.execute('user-123', 'fan_score');
1518
+ *
1519
+ * // By wallet address
1520
+ * const result = await client.dataViews.execute('0x123...abc', 'fan_score');
1521
+ *
1522
+ * console.log('Data:', result.data);
1523
+ * console.log('Events processed:', result.total_events);
1524
+ * ```
1525
+ */
1526
+ async execute(identifier, viewName) {
1527
+ return this.http.get(
1528
+ `/data-mesh/views/${identifier}/custom/${viewName}`
1529
+ );
1530
+ }
1531
+ /**
1532
+ * Preview a data view computation without saving it.
1533
+ * Useful for testing computation configurations before creating a view.
1534
+ *
1535
+ * @example
1536
+ * ```typescript
1537
+ * const preview = await client.dataViews.preview({
1538
+ * wallet_address: '0x123...',
1539
+ * computation: {
1540
+ * type: 'score',
1541
+ * event_types: ['purchase', 'login'],
1542
+ * event_weights: { purchase: 10, login: 1 },
1543
+ * max_score: 1000
1544
+ * },
1545
+ * time_window_days: 30
1546
+ * });
1547
+ * ```
1548
+ */
1549
+ async preview(request) {
1550
+ return this.http.post("/data-mesh/views/preview", request);
1551
+ }
1552
+ /**
1553
+ * Get the fan profile view for a wallet.
1554
+ * This is a builtin view that aggregates user activity into a profile.
1555
+ */
1556
+ async getFanProfile(walletAddress) {
1557
+ return this.http.get(`/data-mesh/views/${walletAddress}/fan-profile`);
1558
+ }
1559
+ /**
1560
+ * Get the activity summary view for a wallet.
1561
+ * This is a builtin view that summarizes user activity over time.
1562
+ */
1563
+ async getActivitySummary(walletAddress, days = 30) {
1564
+ return this.http.get(
1565
+ `/data-mesh/views/${walletAddress}/activity-summary`,
1566
+ { days }
1567
+ );
1568
+ }
1569
+ /**
1570
+ * Get event metadata including available event types and their counts.
1571
+ * Useful for building dynamic UIs that show available event types.
1572
+ */
1573
+ async getEventMetadata() {
1574
+ return this.http.get("/data-mesh/event-metadata");
1575
+ }
1576
+ /**
1577
+ * Get available view templates for creating new views.
1578
+ * Templates provide pre-configured computation patterns.
1579
+ */
1580
+ async getTemplates() {
1581
+ const response = await this.http.get("/data-mesh/views/templates");
1582
+ return response.templates || [];
1583
+ }
1584
+ };
1585
+
1586
+ // src/client.ts
1587
+ var DocumentsResource = class {
1588
+ constructor(http) {
1589
+ this.http = http;
1590
+ }
1591
+ /**
1592
+ * Attest a document file.
1593
+ */
1594
+ async attest(request) {
1595
+ const formData = new FormData();
1596
+ if (request.file instanceof Blob) {
1597
+ formData.append("file", request.file, request.filename || "document");
1598
+ } else if (request.file instanceof ArrayBuffer) {
1599
+ const blob = new Blob([request.file]);
1600
+ formData.append("file", blob, request.filename || "document");
1601
+ } else if (typeof Buffer !== "undefined" && Buffer.isBuffer(request.file)) {
1602
+ const uint8 = new Uint8Array(request.file);
1603
+ const blob = new Blob([uint8]);
1604
+ formData.append("file", blob, request.filename || "document");
1605
+ }
1606
+ formData.append("user_id", request.userId);
1607
+ formData.append("event_type", request.eventType || "document_uploaded");
1608
+ if (request.metadata) {
1609
+ formData.append("metadata", JSON.stringify(request.metadata));
1610
+ }
1611
+ if (request.encrypt) {
1612
+ formData.append("encrypt", "1");
1613
+ }
1614
+ return this.http.requestMultipart("/tenant/documents", formData);
1615
+ }
1616
+ /**
1617
+ * Get a document by its IPFS hash.
1618
+ */
1619
+ async get(ipfsHash) {
1620
+ return this.http.get(`/tenant/events/by-hash/${ipfsHash}`);
1621
+ }
1622
+ };
1623
+ var EventsResource = class {
1624
+ constructor(http) {
1625
+ this.http = http;
1626
+ }
1627
+ /**
1628
+ * Create a new attestation event.
1629
+ */
1630
+ async create(request) {
1631
+ return this.http.post("/tenant/events", {
1632
+ event_type: request.eventType,
1633
+ user_id: request.userId,
1634
+ event_source: request.source || "api",
1635
+ data: request.data || {}
1636
+ });
1637
+ }
1638
+ /**
1639
+ * Get an event by ID.
1640
+ */
1641
+ async get(eventId) {
1642
+ return this.http.get(`/tenant/events/${eventId}`);
1643
+ }
1644
+ /**
1645
+ * List events with optional filters.
1646
+ */
1647
+ async list(request = {}) {
1648
+ const response = await this.http.get("/tenant/events", {
1649
+ user_id: request.userId,
1650
+ event_type: request.eventType,
1651
+ status: request.status,
1652
+ start_date: request.startDate,
1653
+ end_date: request.endDate,
1654
+ limit: request.limit,
1655
+ offset: request.offset
1656
+ });
1657
+ return response.events || [];
1658
+ }
1659
+ /**
1660
+ * Search events by query.
1661
+ */
1662
+ async search(request) {
1663
+ return this.http.post("/search", {
1664
+ query: request.query,
1665
+ user_id: request.userId,
1666
+ event_type: request.eventType,
1667
+ start_date: request.startDate,
1668
+ end_date: request.endDate,
1669
+ limit: request.limit,
1670
+ page: request.page
1671
+ });
1672
+ }
1673
+ /**
1674
+ * Get an event by its IPFS hash.
1675
+ */
1676
+ async byHash(ipfsHash) {
1677
+ return this.http.get(`/tenant/events/by-hash/${ipfsHash}`);
1678
+ }
1679
+ /**
1680
+ * Create multiple events in a batch.
1681
+ *
1682
+ * Note: For high-throughput ingestion, use the IngestionClient instead.
1683
+ * This method is a convenience wrapper that creates events sequentially.
1684
+ *
1685
+ * @param events - Array of event requests
1686
+ * @returns Array of created events
1687
+ */
1688
+ async createBatch(events) {
1689
+ const results = [];
1690
+ for (const event of events) {
1691
+ const created = await this.create(event);
1692
+ results.push(created);
1693
+ }
1694
+ return results;
1695
+ }
1696
+ };
1697
+ var ChannelsResource = class {
1698
+ constructor(http) {
1699
+ this.http = http;
1700
+ }
1701
+ /**
1702
+ * Create a new state channel.
1703
+ */
1704
+ async create(request) {
1705
+ return this.http.post("/channels", {
1706
+ name: request.name,
1707
+ description: request.description
1708
+ });
1709
+ }
1710
+ /**
1711
+ * Get a channel by ID.
1712
+ */
1713
+ async get(channelId) {
1714
+ return this.http.get(`/channels/${channelId}`);
1715
+ }
1716
+ /**
1717
+ * Get detailed status of a channel.
1718
+ */
1719
+ async status(channelId) {
1720
+ return this.http.get(`/channels/${channelId}/status`);
1721
+ }
1722
+ /**
1723
+ * List all channels.
1724
+ */
1725
+ async list(limit = 50, offset = 0) {
1726
+ const response = await this.http.get("/channels", {
1727
+ limit,
1728
+ offset
1729
+ });
1730
+ return response.channels || [];
1731
+ }
1732
+ /**
1733
+ * Stream an event to a channel.
1734
+ */
1735
+ async stream(channelId, request) {
1736
+ return this.http.post(`/channels/${channelId}/stream`, {
1737
+ event_type: request.eventType,
1738
+ user_id: request.userId,
1739
+ event_source: request.source || "sdk",
1740
+ data: request.data
1741
+ });
1742
+ }
1743
+ /**
1744
+ * Stream multiple events in a single request.
1745
+ */
1746
+ async streamBatch(channelId, events) {
1747
+ return this.http.post(`/channels/${channelId}/stream/batch`, {
1748
+ events
1749
+ });
1750
+ }
1751
+ /**
1752
+ * Settle a channel on-chain.
1753
+ */
1754
+ async settle(channelId) {
1755
+ return this.http.post(`/channels/${channelId}/settle`);
1756
+ }
1757
+ /**
1758
+ * Close a channel.
1759
+ */
1760
+ async close(channelId) {
1761
+ return this.http.post(`/channels/${channelId}/close`);
1762
+ }
1763
+ };
1764
+ var CertificatesResource = class {
1765
+ constructor(http) {
1766
+ this.http = http;
1767
+ }
1768
+ /**
1769
+ * Issue a new certificate.
1770
+ */
1771
+ async issue(request) {
1772
+ return this.http.post("/certificates", {
1773
+ recipient_name: request.recipientName,
1774
+ recipient_email: request.recipientEmail,
1775
+ title: request.title,
1776
+ description: request.description,
1777
+ metadata: request.metadata,
1778
+ expires_at: request.expiresAt
1779
+ });
1780
+ }
1781
+ /**
1782
+ * Get a certificate by ID.
1783
+ */
1784
+ async get(certificateId) {
1785
+ return this.http.get(`/certificates/${certificateId}`);
1786
+ }
1787
+ /**
1788
+ * List certificates.
1789
+ */
1790
+ async list(request = {}) {
1791
+ const response = await this.http.get(
1792
+ "/certificates",
1793
+ {
1794
+ recipient_email: request.recipientEmail,
1795
+ limit: request.limit,
1796
+ offset: request.offset
1797
+ }
1798
+ );
1799
+ return response.certificates || [];
1800
+ }
1801
+ /**
1802
+ * Revoke a certificate.
1803
+ */
1804
+ async revoke(certificateId, reason) {
1805
+ return this.http.post(`/certificates/${certificateId}/revoke`, {
1806
+ reason
1807
+ });
1808
+ }
1809
+ /**
1810
+ * Verify a certificate.
1811
+ */
1812
+ async verify(certificateId) {
1813
+ return this.http.get(`/verify/cert/${certificateId}`);
1814
+ }
1815
+ };
1816
+ var WebhooksResource = class {
1817
+ constructor(http) {
1818
+ this.http = http;
1819
+ }
1820
+ /**
1821
+ * Create a new webhook.
1822
+ */
1823
+ async create(request) {
1824
+ return this.http.post("/webhooks", {
1825
+ url: request.url,
1826
+ events: request.events,
1827
+ secret: request.secret
1828
+ });
1829
+ }
1830
+ /**
1831
+ * Get a webhook by ID.
1832
+ */
1833
+ async get(webhookId) {
1834
+ return this.http.get(`/webhooks/${webhookId}`);
1835
+ }
1836
+ /**
1837
+ * List all webhooks.
1838
+ */
1839
+ async list() {
1840
+ const response = await this.http.get("/webhooks");
1841
+ return response.webhooks || [];
1842
+ }
1843
+ /**
1844
+ * Update a webhook.
1845
+ */
1846
+ async update(webhookId, request) {
1847
+ return this.http.patch(`/webhooks/${webhookId}`, request);
1848
+ }
1849
+ /**
1850
+ * Delete a webhook.
1851
+ */
1852
+ async delete(webhookId) {
1853
+ await this.http.delete(`/webhooks/${webhookId}`);
1854
+ }
1855
+ /**
1856
+ * Send a test event to a webhook.
1857
+ */
1858
+ async test(webhookId) {
1859
+ return this.http.post(`/webhooks/${webhookId}/test`);
1860
+ }
1861
+ };
1862
+ var ProofChain = class _ProofChain {
1863
+ constructor(options) {
1864
+ this.http = new HttpClient(options);
1865
+ this.documents = new DocumentsResource(this.http);
1866
+ this.events = new EventsResource(this.http);
1867
+ this.channels = new ChannelsResource(this.http);
1868
+ this.certificates = new CertificatesResource(this.http);
1869
+ this.webhooks = new WebhooksResource(this.http);
1870
+ this.vault = new VaultResource(this.http);
1871
+ this.search = new SearchResource(this.http);
1872
+ this.verifyResource = new VerifyResource(this.http);
1873
+ this.tenant = new TenantResource(this.http);
1874
+ this.passports = new PassportClient(this.http);
1875
+ this.wallets = new WalletClient(this.http);
1876
+ this.users = new EndUsersClient(this.http);
1877
+ this.rewards = new RewardsClient(this.http);
1878
+ this.quests = new QuestsClient(this.http);
1879
+ this.schemas = new SchemasClient(this.http);
1880
+ this.dataViews = new DataViewsClient(this.http);
1881
+ }
1882
+ /**
1883
+ * Create a client from environment variables.
1884
+ * Reads PROOFCHAIN_API_KEY and optionally PROOFCHAIN_BASE_URL.
1885
+ */
1886
+ static fromEnv() {
1887
+ const env = typeof process !== "undefined" ? process.env : {};
1888
+ const apiKey = env.PROOFCHAIN_API_KEY;
1889
+ if (!apiKey) {
1890
+ throw new Error("PROOFCHAIN_API_KEY environment variable not set");
1891
+ }
1892
+ return new _ProofChain({
1893
+ apiKey,
1894
+ baseUrl: env.PROOFCHAIN_BASE_URL
1895
+ });
1896
+ }
1897
+ /**
1898
+ * Verify a document or event by its IPFS hash.
1899
+ */
1900
+ async verify(ipfsHash) {
1901
+ return this.http.get(`/verify/${ipfsHash}`);
1902
+ }
1903
+ /**
1904
+ * Get information about the current tenant.
1905
+ */
1906
+ async tenantInfo() {
1907
+ return this.http.get("/tenant/me");
1908
+ }
1909
+ /**
1910
+ * Get API usage statistics.
1911
+ */
1912
+ async usage(period = "month") {
1913
+ return this.http.get("/tenant/usage", { period });
1914
+ }
1915
+ };
1916
+
1917
+ // src/ingestion.ts
1918
+ var DEFAULT_INGEST_URL = "https://ingest.proofchain.co.za";
1919
+ var USER_AGENT2 = "proofchain-js/0.1.0";
1920
+ var IngestionClient = class {
1921
+ constructor(options) {
1922
+ this.apiKey = options.apiKey;
1923
+ this.ingestUrl = (options.ingestUrl || DEFAULT_INGEST_URL).replace(/\/$/, "");
1924
+ this.timeout = options.timeout || 3e4;
1925
+ }
1926
+ getHeaders() {
1927
+ return {
1928
+ "X-API-Key": this.apiKey,
1929
+ "Content-Type": "application/json",
1930
+ "User-Agent": USER_AGENT2
1931
+ };
1932
+ }
1933
+ async handleResponse(response) {
1934
+ const contentType = response.headers.get("content-type");
1935
+ const isJson = contentType?.includes("application/json");
1936
+ if (response.ok) {
1937
+ if (response.status === 204 || !isJson) {
1938
+ return {};
1939
+ }
1940
+ return response.json();
1941
+ }
1942
+ const body = isJson ? await response.json().catch(() => ({})) : {};
1943
+ const message = body.detail || body.message || `HTTP ${response.status}`;
1944
+ switch (response.status) {
1945
+ case 401:
1946
+ throw new AuthenticationError(message);
1947
+ case 422:
1948
+ case 400:
1949
+ throw new ValidationError(message, body.errors);
1950
+ case 429:
1951
+ const retryAfter = response.headers.get("Retry-After");
1952
+ throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : void 0);
1953
+ default:
1954
+ if (response.status >= 500) {
1955
+ throw new ServerError(message, response.status);
1956
+ }
1957
+ throw new ProofChainError(message, response.status, body);
1958
+ }
1959
+ }
1960
+ /**
1961
+ * Ingest a single event using the high-performance Rust API.
1962
+ * Events are attested immediately upon ingestion.
1963
+ */
1964
+ async ingest(request) {
1965
+ const controller = new AbortController();
1966
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1967
+ try {
1968
+ const headers = this.getHeaders();
1969
+ if (request.schemaIds?.length) {
1970
+ headers["X-Schemas"] = request.schemaIds.join(",");
1971
+ }
1972
+ const response = await fetch(`${this.ingestUrl}/events/ingest`, {
1973
+ method: "POST",
1974
+ headers,
1975
+ body: JSON.stringify({
1976
+ user_id: request.userId,
1977
+ event_type: request.eventType,
1978
+ data: request.data || {},
1979
+ event_source: request.eventSource || "sdk"
1980
+ }),
1981
+ signal: controller.signal
1982
+ });
1983
+ const result = await this.handleResponse(response);
1984
+ return {
1985
+ eventId: result.event_id,
1986
+ certificateId: result.certificate_id,
1987
+ status: result.status,
1988
+ queuePosition: result.queue_position,
1989
+ estimatedConfirmation: result.estimated_confirmation
1990
+ };
1991
+ } catch (error) {
1992
+ if (error instanceof Error && error.name === "AbortError") {
1993
+ throw new NetworkError("Request timed out");
1994
+ }
1995
+ throw error;
1996
+ } finally {
1997
+ clearTimeout(timeoutId);
1998
+ }
1999
+ }
2000
+ /**
2001
+ * Ingest multiple events in a single request (up to 1000 events).
2002
+ * More efficient than individual calls for bulk data.
2003
+ */
2004
+ async ingestBatch(request) {
2005
+ if (request.events.length > 1e3) {
2006
+ throw new ValidationError("Batch size cannot exceed 1000 events");
2007
+ }
2008
+ const controller = new AbortController();
2009
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout * 2);
2010
+ try {
2011
+ const response = await fetch(`${this.ingestUrl}/events/ingest/batch`, {
2012
+ method: "POST",
2013
+ headers: this.getHeaders(),
2014
+ body: JSON.stringify(
2015
+ request.events.map((e) => ({
2016
+ user_id: e.userId,
2017
+ event_type: e.eventType,
2018
+ data: e.data || {},
2019
+ event_source: e.eventSource || "sdk"
2020
+ }))
2021
+ ),
2022
+ signal: controller.signal
2023
+ });
2024
+ const result = await this.handleResponse(response);
2025
+ return {
2026
+ totalEvents: result.total_events || result.total,
2027
+ queued: result.queued,
2028
+ failed: result.failed,
2029
+ results: (result.results || result.responses || []).map((r) => ({
2030
+ eventId: r.event_id,
2031
+ certificateId: r.certificate_id,
2032
+ status: r.status
2033
+ }))
2034
+ };
2035
+ } catch (error) {
2036
+ if (error instanceof Error && error.name === "AbortError") {
2037
+ throw new NetworkError("Request timed out");
2038
+ }
2039
+ throw error;
2040
+ } finally {
2041
+ clearTimeout(timeoutId);
2042
+ }
2043
+ }
2044
+ /**
2045
+ * Get the status of an event by ID.
2046
+ */
2047
+ async getEventStatus(eventId) {
2048
+ const controller = new AbortController();
2049
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2050
+ try {
2051
+ const response = await fetch(`${this.ingestUrl}/events/${eventId}/status`, {
2052
+ method: "GET",
2053
+ headers: this.getHeaders(),
2054
+ signal: controller.signal
2055
+ });
2056
+ return this.handleResponse(response);
2057
+ } finally {
2058
+ clearTimeout(timeoutId);
2059
+ }
2060
+ }
2061
+ };
342
2062
  export {
343
- AttestationClient,
344
- AttestationClientError,
345
- AttestationRegistryContract,
346
- createClient
2063
+ AuthenticationError,
2064
+ AuthorizationError,
2065
+ CertificatesResource,
2066
+ ChannelsResource,
2067
+ DataViewsClient,
2068
+ DocumentsResource,
2069
+ EndUsersClient,
2070
+ EventsResource,
2071
+ IngestionClient,
2072
+ NetworkError,
2073
+ NotFoundError,
2074
+ PassportClient,
2075
+ ProofChain,
2076
+ ProofChainError,
2077
+ QuestsClient,
2078
+ RateLimitError,
2079
+ RewardsClient,
2080
+ SchemasClient,
2081
+ SearchResource,
2082
+ ServerError,
2083
+ TenantResource,
2084
+ TimeoutError,
2085
+ ValidationError,
2086
+ VaultResource,
2087
+ VerifyResource,
2088
+ WalletClient,
2089
+ WebhooksResource
347
2090
  };