@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/dist/index.mjs CHANGED
@@ -1,347 +1,2080 @@
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
+ // 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
- AttestationClient,
344
- AttestationClientError,
345
- AttestationRegistryContract,
346
- createClient
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
  };