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