@hauska-sdk/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +263 -0
- package/dist/CNSSDK.d.ts +115 -0
- package/dist/CNSSDK.d.ts.map +1 -0
- package/dist/CNSSDK.js +389 -0
- package/dist/CNSSDK.js.map +1 -0
- package/dist/EventAnchoringService.d.ts +58 -0
- package/dist/EventAnchoringService.d.ts.map +1 -0
- package/dist/EventAnchoringService.js +84 -0
- package/dist/EventAnchoringService.js.map +1 -0
- package/dist/errors.d.ts +160 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +202 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +39 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types.d.ts +181 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/docs/api-reference.md +433 -0
- package/docs/examples.md +362 -0
- package/docs/getting-started.md +265 -0
- package/docs/troubleshooting.md +398 -0
- package/package.json +74 -0
package/dist/CNSSDK.js
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hauska-sdk/core
|
|
3
|
+
* Unified CNS SDK - Main entry point
|
|
4
|
+
*/
|
|
5
|
+
import { WalletManager } from "@hauska-sdk/wallet";
|
|
6
|
+
import { PaymentSDK } from "@hauska-sdk/payment";
|
|
7
|
+
import { VDASDK } from "@hauska-sdk/vda";
|
|
8
|
+
import { RetrievalSDK } from "@hauska-sdk/retrieval";
|
|
9
|
+
import { ConfigurationError, WalletError, ErrorCodes } from "./errors";
|
|
10
|
+
/**
|
|
11
|
+
* Unified CNS SDK
|
|
12
|
+
*
|
|
13
|
+
* Main entry point for all CNS Protocol functionality:
|
|
14
|
+
* - Payment processing (x402 protocol)
|
|
15
|
+
* - VDA management (Verified Digital Assets)
|
|
16
|
+
* - Document retrieval (IPFS with gated access)
|
|
17
|
+
* - Wallet management (automatic wallet creation)
|
|
18
|
+
*/
|
|
19
|
+
export class CNSSDK {
|
|
20
|
+
config;
|
|
21
|
+
walletManager;
|
|
22
|
+
paymentSDK;
|
|
23
|
+
vdaSDK;
|
|
24
|
+
retrievalSDK;
|
|
25
|
+
anchoring;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.config = config;
|
|
28
|
+
this.initialize();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Initialize all SDK modules
|
|
32
|
+
*/
|
|
33
|
+
initialize() {
|
|
34
|
+
try {
|
|
35
|
+
this.log("info", "Initializing CNS SDK");
|
|
36
|
+
// Validate required configuration
|
|
37
|
+
if (!this.config.vda) {
|
|
38
|
+
throw new ConfigurationError("VDA configuration is required", ErrorCodes.CONFIG_MISSING_REQUIRED, { context: { config: "vda" } });
|
|
39
|
+
}
|
|
40
|
+
if (!this.config.retrieval) {
|
|
41
|
+
throw new ConfigurationError("Retrieval configuration is required", ErrorCodes.CONFIG_MISSING_REQUIRED, { context: { config: "retrieval" } });
|
|
42
|
+
}
|
|
43
|
+
// Initialize wallet manager (shared across all modules)
|
|
44
|
+
if (this.config.walletManager) {
|
|
45
|
+
this.walletManager = this.config.walletManager;
|
|
46
|
+
this.log("info", "Using provided wallet manager");
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.walletManager = new WalletManager();
|
|
50
|
+
this.log("info", "Created new wallet manager");
|
|
51
|
+
}
|
|
52
|
+
// Initialize Payment SDK
|
|
53
|
+
this.paymentSDK = new PaymentSDK({
|
|
54
|
+
...this.config.payment,
|
|
55
|
+
walletManager: this.walletManager,
|
|
56
|
+
});
|
|
57
|
+
this.log("info", "Payment SDK initialized");
|
|
58
|
+
this.metrics("payment_sdk_initialized");
|
|
59
|
+
// Initialize VDA SDK
|
|
60
|
+
if (!this.config.vda.storageAdapter) {
|
|
61
|
+
throw new ConfigurationError("VDA storage adapter is required", ErrorCodes.CONFIG_STORAGE_NOT_CONFIGURED, { context: { config: "vda.storageAdapter" } });
|
|
62
|
+
}
|
|
63
|
+
this.vdaSDK = new VDASDK({
|
|
64
|
+
...this.config.vda,
|
|
65
|
+
walletManager: this.walletManager,
|
|
66
|
+
logHook: this.config.logHook,
|
|
67
|
+
});
|
|
68
|
+
this.log("info", "VDA SDK initialized");
|
|
69
|
+
this.metrics("vda_sdk_initialized");
|
|
70
|
+
// Initialize Retrieval SDK (requires VDA SDK)
|
|
71
|
+
// Provide either ipfsAdapter (production) or pinata (dev/legacy)
|
|
72
|
+
if (!this.config.retrieval.ipfsAdapter && !this.config.retrieval.pinata) {
|
|
73
|
+
throw new ConfigurationError("Retrieval SDK requires either ipfsAdapter (production) or pinata (dev/legacy)", ErrorCodes.CONFIG_PINATA_NOT_CONFIGURED);
|
|
74
|
+
}
|
|
75
|
+
this.retrievalSDK = new RetrievalSDK({
|
|
76
|
+
...this.config.retrieval,
|
|
77
|
+
vdaSdk: this.vdaSDK,
|
|
78
|
+
logHook: this.config.logHook,
|
|
79
|
+
});
|
|
80
|
+
this.log("info", "Retrieval SDK initialized");
|
|
81
|
+
this.metrics("retrieval_sdk_initialized");
|
|
82
|
+
// Wire in optional event anchoring service
|
|
83
|
+
this.anchoring = this.config.anchoring;
|
|
84
|
+
this.log("info", "CNS SDK initialization complete");
|
|
85
|
+
this.metrics("cns_sdk_initialized");
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.log("error", "Failed to initialize CNS SDK", { error });
|
|
89
|
+
if (error instanceof ConfigurationError) {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
throw new ConfigurationError(`SDK initialization failed: ${error instanceof Error ? error.message : String(error)}`, ErrorCodes.CONFIG_INVALID_VALUE, { cause: error instanceof Error ? error : undefined });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get or create a wallet for a user
|
|
97
|
+
*
|
|
98
|
+
* @param options - Wallet options
|
|
99
|
+
* @returns Wallet instance
|
|
100
|
+
*/
|
|
101
|
+
async getOrCreateWallet(options) {
|
|
102
|
+
try {
|
|
103
|
+
this.log("info", "Getting or creating wallet", { userId: options.userId });
|
|
104
|
+
if (!options.userId) {
|
|
105
|
+
throw new WalletError("User ID is required", ErrorCodes.WALLET_NOT_FOUND, {
|
|
106
|
+
context: { userId: options.userId },
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const wallet = await this.walletManager.getOrCreateWallet(options.userId, options.password);
|
|
110
|
+
this.log("info", "Wallet retrieved/created", {
|
|
111
|
+
address: wallet.address,
|
|
112
|
+
userId: options.userId,
|
|
113
|
+
});
|
|
114
|
+
this.metrics("wallet_retrieved_or_created", { userId: options.userId });
|
|
115
|
+
return wallet;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
this.log("error", "Failed to get or create wallet", {
|
|
119
|
+
userId: options.userId,
|
|
120
|
+
error,
|
|
121
|
+
});
|
|
122
|
+
if (error instanceof WalletError) {
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
throw new WalletError(`Failed to get or create wallet: ${error instanceof Error ? error.message : String(error)}`, ErrorCodes.WALLET_CREATION_FAILED, {
|
|
126
|
+
context: { userId: options.userId },
|
|
127
|
+
cause: error instanceof Error ? error : undefined,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Purchase and mint a VDA in a single operation
|
|
133
|
+
*
|
|
134
|
+
* This method:
|
|
135
|
+
* 1. Gets or creates a wallet for the user
|
|
136
|
+
* 2. Processes the payment
|
|
137
|
+
* 3. Records the payment
|
|
138
|
+
* 4. Mints the VDA
|
|
139
|
+
*
|
|
140
|
+
* @param options - Purchase and mint options
|
|
141
|
+
* @returns Object containing payment record and VDA
|
|
142
|
+
*/
|
|
143
|
+
async purchaseAndMintVDA(options) {
|
|
144
|
+
this.log("info", "Starting purchase and mint VDA flow", {
|
|
145
|
+
amount: options.amount,
|
|
146
|
+
currency: options.currency,
|
|
147
|
+
method: options.method,
|
|
148
|
+
});
|
|
149
|
+
// 1. Get or create wallet
|
|
150
|
+
const wallet = await this.getOrCreateWallet(options.wallet);
|
|
151
|
+
const ownerWallet = options.vdaParams.ownerWallet || wallet.address;
|
|
152
|
+
// 2. Process payment (if crypto, verify; if fiat, record)
|
|
153
|
+
let payment;
|
|
154
|
+
if (options.method === "crypto") {
|
|
155
|
+
// For crypto payments, we expect a proof to be provided
|
|
156
|
+
// In a real flow, the user would make the payment and provide proof
|
|
157
|
+
// For now, we'll create a payment record that needs verification
|
|
158
|
+
payment = await this.paymentSDK.recordPayment({
|
|
159
|
+
resourceId: `payment-${Date.now()}`,
|
|
160
|
+
amount: options.amount,
|
|
161
|
+
currency: options.currency,
|
|
162
|
+
method: "crypto",
|
|
163
|
+
fromAddress: wallet.address,
|
|
164
|
+
toAddress: this.config.payment?.blockchain?.facilitatorWallet || "",
|
|
165
|
+
verified: false, // Will be verified when proof is provided
|
|
166
|
+
metadata: options.paymentMetadata,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// For fiat payments, record the payment
|
|
171
|
+
payment = await this.paymentSDK.recordPayment({
|
|
172
|
+
resourceId: `payment-${Date.now()}`,
|
|
173
|
+
amount: options.amount,
|
|
174
|
+
currency: options.currency,
|
|
175
|
+
method: "fiat",
|
|
176
|
+
paymentIntentId: `intent-${Date.now()}`, // Would come from Circle API
|
|
177
|
+
toAddress: this.config.payment?.blockchain?.facilitatorWallet || "",
|
|
178
|
+
verified: true, // Fiat payments are verified by provider
|
|
179
|
+
metadata: options.paymentMetadata,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
this.log("info", "Payment recorded", { paymentId: payment.resourceId });
|
|
183
|
+
// 3. Mint VDA
|
|
184
|
+
const vda = await this.vdaSDK.mint({
|
|
185
|
+
assetType: options.vdaParams.assetType,
|
|
186
|
+
ownerWallet,
|
|
187
|
+
spoke: options.vdaParams.spoke,
|
|
188
|
+
address: options.vdaParams.address,
|
|
189
|
+
legalDesc: options.vdaParams.legalDesc,
|
|
190
|
+
patientId: options.vdaParams.patientId,
|
|
191
|
+
api14: options.vdaParams.api14,
|
|
192
|
+
...options.vdaMetadata,
|
|
193
|
+
});
|
|
194
|
+
this.log("info", "VDA minted", { vdaId: vda.id });
|
|
195
|
+
// Auto-emit audit events
|
|
196
|
+
await this.anchoring?.anchor({
|
|
197
|
+
assetId: vda.id,
|
|
198
|
+
eventType: "payment.verified",
|
|
199
|
+
payload: { amount: options.amount, currency: options.currency, method: options.method },
|
|
200
|
+
timestamp: new Date(),
|
|
201
|
+
actorWallet: ownerWallet,
|
|
202
|
+
});
|
|
203
|
+
await this.anchoring?.anchor({
|
|
204
|
+
assetId: vda.id,
|
|
205
|
+
eventType: "vda.minted",
|
|
206
|
+
payload: { assetType: vda.metadata.assetType, spoke: vda.metadata.spoke },
|
|
207
|
+
timestamp: new Date(),
|
|
208
|
+
actorWallet: ownerWallet,
|
|
209
|
+
});
|
|
210
|
+
return {
|
|
211
|
+
payment,
|
|
212
|
+
vda,
|
|
213
|
+
wallet: { address: wallet.address },
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Create a data room (VDA + optional document + optional access pass)
|
|
218
|
+
*
|
|
219
|
+
* This method:
|
|
220
|
+
* 1. Gets or creates a wallet for the owner
|
|
221
|
+
* 2. Mints a VDA for the data room
|
|
222
|
+
* 3. Optionally uploads a document to IPFS
|
|
223
|
+
* 4. Optionally creates an access pass
|
|
224
|
+
*
|
|
225
|
+
* @param options - Data room creation options
|
|
226
|
+
* @returns Object containing VDA, document (if uploaded), and access pass (if created)
|
|
227
|
+
*/
|
|
228
|
+
async createDataRoom(options) {
|
|
229
|
+
this.log("info", "Creating data room", {
|
|
230
|
+
assetType: options.vdaParams.assetType,
|
|
231
|
+
spoke: options.vdaParams.spoke,
|
|
232
|
+
});
|
|
233
|
+
// 1. Get or create wallet for owner
|
|
234
|
+
const ownerWallet = await this.getOrCreateWallet(options.ownerWallet);
|
|
235
|
+
let document;
|
|
236
|
+
let documentCid;
|
|
237
|
+
// 2. Upload document first (if provided) to get CID
|
|
238
|
+
if (options.document) {
|
|
239
|
+
// Upload document with temporary VDA ID (will be updated after VDA creation)
|
|
240
|
+
document = await this.retrievalSDK.uploadDocument(options.document.content, {
|
|
241
|
+
encrypt: options.document.encrypt !== false, // Default to true
|
|
242
|
+
metadata: {
|
|
243
|
+
name: options.document.name || "document",
|
|
244
|
+
keyvalues: {
|
|
245
|
+
spoke: options.vdaParams.spoke,
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
spoke: options.vdaParams.spoke,
|
|
249
|
+
});
|
|
250
|
+
documentCid = document.cid;
|
|
251
|
+
this.log("info", "Document uploaded", { cid: documentCid });
|
|
252
|
+
}
|
|
253
|
+
// 3. Mint VDA for data room (with CID if document was uploaded)
|
|
254
|
+
const vda = await this.vdaSDK.mint({
|
|
255
|
+
assetType: options.vdaParams.assetType,
|
|
256
|
+
ownerWallet: ownerWallet.address,
|
|
257
|
+
spoke: options.vdaParams.spoke,
|
|
258
|
+
address: options.vdaParams.address,
|
|
259
|
+
legalDesc: options.vdaParams.legalDesc,
|
|
260
|
+
patientId: options.vdaParams.patientId,
|
|
261
|
+
api14: options.vdaParams.api14,
|
|
262
|
+
ipfsCid: documentCid, // Link VDA to document CID
|
|
263
|
+
});
|
|
264
|
+
this.log("info", "Data room VDA minted", { vdaId: vda.id, ipfsCid: documentCid });
|
|
265
|
+
let accessPass;
|
|
266
|
+
// 4. Create access pass if requested
|
|
267
|
+
if (options.accessPass) {
|
|
268
|
+
const recipientWallet = await this.getOrCreateWallet(options.accessPass.recipientWallet);
|
|
269
|
+
accessPass = await this.vdaSDK.createAccessPass({
|
|
270
|
+
grantorWallet: ownerWallet.address,
|
|
271
|
+
recipientWallet: recipientWallet.address,
|
|
272
|
+
accessibleVDAs: [vda.id],
|
|
273
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
274
|
+
permissions: options.accessPass.permissions,
|
|
275
|
+
expiry: options.accessPass.expiry,
|
|
276
|
+
spoke: options.vdaParams.spoke,
|
|
277
|
+
address: options.vdaParams.address,
|
|
278
|
+
legalDesc: options.vdaParams.legalDesc,
|
|
279
|
+
patientId: options.vdaParams.patientId,
|
|
280
|
+
api14: options.vdaParams.api14,
|
|
281
|
+
});
|
|
282
|
+
this.log("info", "Access pass created", { accessPassId: accessPass.id });
|
|
283
|
+
}
|
|
284
|
+
// Auto-emit audit events
|
|
285
|
+
await this.anchoring?.anchor({
|
|
286
|
+
assetId: vda.id,
|
|
287
|
+
eventType: "asset.created",
|
|
288
|
+
payload: {
|
|
289
|
+
assetType: vda.metadata.assetType,
|
|
290
|
+
spoke: vda.metadata.spoke,
|
|
291
|
+
ipfsCid: documentCid,
|
|
292
|
+
},
|
|
293
|
+
timestamp: new Date(),
|
|
294
|
+
actorWallet: ownerWallet.address,
|
|
295
|
+
});
|
|
296
|
+
if (accessPass) {
|
|
297
|
+
await this.anchoring?.anchor({
|
|
298
|
+
assetId: vda.id,
|
|
299
|
+
eventType: "access_pass.created",
|
|
300
|
+
payload: { accessPassId: accessPass.id, permissions: options.accessPass.permissions },
|
|
301
|
+
timestamp: new Date(),
|
|
302
|
+
actorWallet: ownerWallet.address,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
vda,
|
|
307
|
+
document,
|
|
308
|
+
accessPass,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Retrieve a document with access verification
|
|
313
|
+
*
|
|
314
|
+
* This method:
|
|
315
|
+
* 1. Gets or creates a wallet for the requester
|
|
316
|
+
* 2. Verifies access to the document (VDA ownership or access pass)
|
|
317
|
+
* 3. Retrieves the document from IPFS
|
|
318
|
+
* 4. Optionally decrypts and watermarks the document
|
|
319
|
+
*
|
|
320
|
+
* @param options - Document retrieval options
|
|
321
|
+
* @returns Document content as Buffer
|
|
322
|
+
*/
|
|
323
|
+
async retrieveDocument(options) {
|
|
324
|
+
this.log("info", "Retrieving document", { cid: options.cid });
|
|
325
|
+
// 1. Get or create wallet
|
|
326
|
+
const wallet = await this.getOrCreateWallet(options.wallet);
|
|
327
|
+
// 2. Retrieve document with full access control
|
|
328
|
+
const documentResult = await this.retrievalSDK.retrieveDocument(options.cid, wallet.address, {
|
|
329
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
330
|
+
requiredPermissions: (options.requiredPermissions || ["view"]),
|
|
331
|
+
decrypt: options.decrypt || false,
|
|
332
|
+
watermark: options.watermark || false,
|
|
333
|
+
});
|
|
334
|
+
this.log("info", "Document retrieved", {
|
|
335
|
+
cid: options.cid,
|
|
336
|
+
size: documentResult.content.length,
|
|
337
|
+
});
|
|
338
|
+
// Auto-emit audit event
|
|
339
|
+
await this.anchoring?.anchor({
|
|
340
|
+
assetId: options.cid,
|
|
341
|
+
eventType: "document.retrieved",
|
|
342
|
+
payload: { cid: options.cid, size: documentResult.content.length },
|
|
343
|
+
timestamp: new Date(),
|
|
344
|
+
actorWallet: wallet.address,
|
|
345
|
+
});
|
|
346
|
+
return documentResult.content;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Get the underlying Payment SDK instance
|
|
350
|
+
*/
|
|
351
|
+
getPaymentSDK() {
|
|
352
|
+
return this.paymentSDK;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Get the underlying VDA SDK instance
|
|
356
|
+
*/
|
|
357
|
+
getVDASDK() {
|
|
358
|
+
return this.vdaSDK;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Get the underlying Retrieval SDK instance
|
|
362
|
+
*/
|
|
363
|
+
getRetrievalSDK() {
|
|
364
|
+
return this.retrievalSDK;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Get the wallet manager instance
|
|
368
|
+
*/
|
|
369
|
+
getWalletManager() {
|
|
370
|
+
return this.walletManager;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Log a message using the configured log hook
|
|
374
|
+
*/
|
|
375
|
+
log(level, message, data) {
|
|
376
|
+
if (this.config.logHook) {
|
|
377
|
+
this.config.logHook(level, message, data);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Emit a metrics event using the configured metrics hook
|
|
382
|
+
*/
|
|
383
|
+
metrics(event, data) {
|
|
384
|
+
if (this.config.metricsHook) {
|
|
385
|
+
this.config.metricsHook(event, data);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=CNSSDK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CNSSDK.js","sourceRoot":"","sources":["../src/CNSSDK.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hauska-sdk/core
|
|
3
|
+
* EventAnchoringService — append-only immutable audit trail with hash chaining.
|
|
4
|
+
*
|
|
5
|
+
* Each event is linked to the previous event for the same assetId via a SHA-256
|
|
6
|
+
* hash chain. verifyChain() detects any post-write tampering by recomputing all
|
|
7
|
+
* hashes. The first event in a chain uses 'GENESIS' as its prev_hash.
|
|
8
|
+
*/
|
|
9
|
+
export type AuditEventType = "asset.created" | "vda.minted" | "access_pass.created" | "access_pass.revoked" | "document.retrieved" | "payment.verified";
|
|
10
|
+
export interface AuditEvent {
|
|
11
|
+
assetId: string;
|
|
12
|
+
eventType: AuditEventType;
|
|
13
|
+
payload: Record<string, unknown>;
|
|
14
|
+
timestamp: Date;
|
|
15
|
+
actorWallet?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface EventLogRow {
|
|
18
|
+
id: number;
|
|
19
|
+
asset_id: string;
|
|
20
|
+
event_type: string;
|
|
21
|
+
payload_json: Record<string, unknown>;
|
|
22
|
+
actor_wallet?: string;
|
|
23
|
+
timestamp: Date;
|
|
24
|
+
prev_hash: string;
|
|
25
|
+
event_hash: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Minimal storage interface required by EventAnchoringService.
|
|
29
|
+
* Implement with PostgreSQL for production; use InMemoryEventLogStorage for tests.
|
|
30
|
+
*/
|
|
31
|
+
export interface EventLogStorage {
|
|
32
|
+
/** Insert a new row and return it with its assigned id. */
|
|
33
|
+
insert(row: Omit<EventLogRow, "id">): Promise<EventLogRow>;
|
|
34
|
+
/** Return the most-recently inserted row for the given assetId, or null. */
|
|
35
|
+
getLastForAsset(assetId: string): Promise<EventLogRow | null>;
|
|
36
|
+
/** Return all rows for the given assetId ordered by timestamp ascending. */
|
|
37
|
+
getByAsset(assetId: string): Promise<EventLogRow[]>;
|
|
38
|
+
}
|
|
39
|
+
export declare function computeEventHash(prevHash: string, eventType: string, assetId: string, timestamp: Date, payload: Record<string, unknown>): string;
|
|
40
|
+
export declare class EventAnchoringService {
|
|
41
|
+
private readonly storage;
|
|
42
|
+
constructor(storage: EventLogStorage);
|
|
43
|
+
/**
|
|
44
|
+
* Anchor an audit event. Computes the hash chain link and persists the row.
|
|
45
|
+
* @returns The event_hash of the stored row (useful for correlation).
|
|
46
|
+
*/
|
|
47
|
+
anchor(event: AuditEvent): Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Return audit history for an asset, ordered by timestamp ascending.
|
|
50
|
+
*/
|
|
51
|
+
getHistory(assetId: string): Promise<AuditEvent[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Walk the stored chain for assetId and recompute every hash.
|
|
54
|
+
* Returns false if any row has been modified since insertion.
|
|
55
|
+
*/
|
|
56
|
+
verifyChain(assetId: string): Promise<boolean>;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=EventAnchoringService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventAnchoringService.d.ts","sourceRoot":"","sources":["../src/EventAnchoringService.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,MAAM,cAAc,GACtB,eAAe,GACf,YAAY,GACZ,qBAAqB,GACrB,qBAAqB,GACrB,oBAAoB,GACpB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,cAAc,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3D,4EAA4E;IAC5E,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9D,4EAA4E;IAC5E,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CACrD;AAMD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,IAAI,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAUR;AAMD,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,eAAe;IAErD;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BhD;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAWxD;;;OAGG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAuBrD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hauska-sdk/core
|
|
3
|
+
* EventAnchoringService — append-only immutable audit trail with hash chaining.
|
|
4
|
+
*
|
|
5
|
+
* Each event is linked to the previous event for the same assetId via a SHA-256
|
|
6
|
+
* hash chain. verifyChain() detects any post-write tampering by recomputing all
|
|
7
|
+
* hashes. The first event in a chain uses 'GENESIS' as its prev_hash.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from "crypto";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Hash computation (deterministic, sorted-key payload serialisation)
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
export function computeEventHash(prevHash, eventType, assetId, timestamp, payload) {
|
|
14
|
+
const content = [
|
|
15
|
+
prevHash,
|
|
16
|
+
eventType,
|
|
17
|
+
assetId,
|
|
18
|
+
timestamp.toISOString(),
|
|
19
|
+
JSON.stringify(payload, Object.keys(payload).sort()),
|
|
20
|
+
].join("|");
|
|
21
|
+
return createHash("sha256").update(content).digest("hex");
|
|
22
|
+
}
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// EventAnchoringService
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
export class EventAnchoringService {
|
|
27
|
+
storage;
|
|
28
|
+
constructor(storage) {
|
|
29
|
+
this.storage = storage;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Anchor an audit event. Computes the hash chain link and persists the row.
|
|
33
|
+
* @returns The event_hash of the stored row (useful for correlation).
|
|
34
|
+
*/
|
|
35
|
+
async anchor(event) {
|
|
36
|
+
const timestamp = event.timestamp ?? new Date();
|
|
37
|
+
const prev = await this.storage.getLastForAsset(event.assetId);
|
|
38
|
+
const prevHash = prev?.event_hash ?? "GENESIS";
|
|
39
|
+
const eventHash = computeEventHash(prevHash, event.eventType, event.assetId, timestamp, event.payload);
|
|
40
|
+
await this.storage.insert({
|
|
41
|
+
asset_id: event.assetId,
|
|
42
|
+
event_type: event.eventType,
|
|
43
|
+
payload_json: event.payload,
|
|
44
|
+
actor_wallet: event.actorWallet,
|
|
45
|
+
timestamp,
|
|
46
|
+
prev_hash: prevHash,
|
|
47
|
+
event_hash: eventHash,
|
|
48
|
+
});
|
|
49
|
+
return eventHash;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Return audit history for an asset, ordered by timestamp ascending.
|
|
53
|
+
*/
|
|
54
|
+
async getHistory(assetId) {
|
|
55
|
+
const rows = await this.storage.getByAsset(assetId);
|
|
56
|
+
return rows.map((row) => ({
|
|
57
|
+
assetId: row.asset_id,
|
|
58
|
+
eventType: row.event_type,
|
|
59
|
+
payload: row.payload_json,
|
|
60
|
+
timestamp: row.timestamp,
|
|
61
|
+
actorWallet: row.actor_wallet,
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Walk the stored chain for assetId and recompute every hash.
|
|
66
|
+
* Returns false if any row has been modified since insertion.
|
|
67
|
+
*/
|
|
68
|
+
async verifyChain(assetId) {
|
|
69
|
+
const rows = await this.storage.getByAsset(assetId);
|
|
70
|
+
if (rows.length === 0)
|
|
71
|
+
return true;
|
|
72
|
+
for (let i = 0; i < rows.length; i++) {
|
|
73
|
+
const row = rows[i];
|
|
74
|
+
const expectedPrevHash = i === 0 ? "GENESIS" : rows[i - 1].event_hash;
|
|
75
|
+
if (row.prev_hash !== expectedPrevHash)
|
|
76
|
+
return false;
|
|
77
|
+
const expectedHash = computeEventHash(row.prev_hash, row.event_type, row.asset_id, row.timestamp, row.payload_json);
|
|
78
|
+
if (row.event_hash !== expectedHash)
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=EventAnchoringService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventAnchoringService.js","sourceRoot":"","sources":["../src/EventAnchoringService.ts"],"names":[],"mappings":"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"}
|