@hardkas/artifacts 0.2.2-alpha → 0.3.0-alpha

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +137 -16
  2. package/dist/index.js +266 -84
  3. package/package.json +3 -3
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { ArtifactType, NetworkId, ExecutionMode, ContentHash, WorkflowId, ArtifactId, LineageId, EventSequence, KaspaAddress, TxId, EventEnvelope } from '@hardkas/core';
1
+ import { ArtifactType, NetworkId, ExecutionMode, ContentHash, WorkflowId, ArtifactId, LineageId, EventSequence, TxId, KaspaAddress, CorruptionCode, CorruptionSeverity, EventEnvelope } from '@hardkas/core';
2
2
  import { z } from 'zod';
3
3
  import { TxOutput, Utxo, TxPlan as TxPlan$1 } from '@hardkas/tx-builder';
4
4
 
5
- declare const HARDKAS_VERSION = "0.2.2-alpha";
5
+ declare const HARDKAS_VERSION = "0.3.0-alpha";
6
6
  declare const ARTIFACT_SCHEMAS: {
7
7
  readonly LOCALNET_STATE: "hardkas.localnetState.v1";
8
8
  readonly REAL_ACCOUNT_STORE: "hardkas.realAccountStore.v1";
@@ -42,6 +42,7 @@ declare const BaseArtifactSchema: z.ZodObject<{
42
42
  schema: z.ZodString;
43
43
  hardkasVersion: z.ZodString;
44
44
  version: z.ZodLiteral<"1.0.0-alpha">;
45
+ hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
45
46
  networkId: z.ZodEnum<["mainnet", "testnet-10", "testnet-11", "testnet-12", "simnet", "simnet-1", "devnet"]>;
46
47
  mode: z.ZodEnum<["simulated", "real", "readonly"]>;
47
48
  contentHash: z.ZodOptional<z.ZodString>;
@@ -72,6 +73,7 @@ declare const BaseArtifactSchema: z.ZodObject<{
72
73
  networkId: "mainnet" | "testnet-10" | "testnet-11" | "testnet-12" | "simnet" | "simnet-1" | "devnet";
73
74
  mode: "simulated" | "real" | "readonly";
74
75
  createdAt: string;
76
+ hashVersion?: string | number | undefined;
75
77
  contentHash?: string | undefined;
76
78
  lineage?: {
77
79
  artifactId: string;
@@ -87,6 +89,7 @@ declare const BaseArtifactSchema: z.ZodObject<{
87
89
  networkId: "mainnet" | "testnet-10" | "testnet-11" | "testnet-12" | "simnet" | "simnet-1" | "devnet";
88
90
  mode: "simulated" | "real" | "readonly";
89
91
  createdAt: string;
92
+ hashVersion?: string | number | undefined;
90
93
  contentHash?: string | undefined;
91
94
  lineage?: {
92
95
  artifactId: string;
@@ -112,6 +115,7 @@ declare const AccountRefSchema: z.ZodObject<{
112
115
  declare const TxPlanSchema: z.ZodObject<{
113
116
  hardkasVersion: z.ZodString;
114
117
  version: z.ZodLiteral<"1.0.0-alpha">;
118
+ hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
115
119
  contentHash: z.ZodOptional<z.ZodString>;
116
120
  createdAt: z.ZodString;
117
121
  lineage: z.ZodOptional<z.ZodObject<{
@@ -245,6 +249,7 @@ declare const TxPlanSchema: z.ZodObject<{
245
249
  address: string;
246
250
  amountSompi: string;
247
251
  }[];
252
+ hashVersion?: string | number | undefined;
248
253
  contentHash?: string | undefined;
249
254
  lineage?: {
250
255
  artifactId: string;
@@ -290,6 +295,7 @@ declare const TxPlanSchema: z.ZodObject<{
290
295
  address: string;
291
296
  amountSompi: string;
292
297
  }[];
298
+ hashVersion?: string | number | undefined;
293
299
  contentHash?: string | undefined;
294
300
  lineage?: {
295
301
  artifactId: string;
@@ -374,6 +380,7 @@ declare const LocalnetUtxoSchemaV2: z.ZodObject<{
374
380
  declare const SnapshotSchema: z.ZodObject<{
375
381
  hardkasVersion: z.ZodString;
376
382
  version: z.ZodLiteral<"1.0.0-alpha">;
383
+ hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
377
384
  networkId: z.ZodEnum<["mainnet", "testnet-10", "testnet-11", "testnet-12", "simnet", "simnet-1", "devnet"]>;
378
385
  mode: z.ZodEnum<["simulated", "real", "readonly"]>;
379
386
  contentHash: z.ZodOptional<z.ZodString>;
@@ -452,6 +459,7 @@ declare const SnapshotSchema: z.ZodObject<{
452
459
  spent: boolean;
453
460
  createdAtDaaScore: string;
454
461
  }[];
462
+ hashVersion?: string | number | undefined;
455
463
  contentHash?: string | undefined;
456
464
  lineage?: {
457
465
  artifactId: string;
@@ -483,6 +491,7 @@ declare const SnapshotSchema: z.ZodObject<{
483
491
  spent: boolean;
484
492
  createdAtDaaScore: string;
485
493
  }[];
494
+ hashVersion?: string | number | undefined;
486
495
  contentHash?: string | undefined;
487
496
  lineage?: {
488
497
  artifactId: string;
@@ -499,6 +508,7 @@ declare const SnapshotSchema: z.ZodObject<{
499
508
  declare const TxReceiptSchema: z.ZodObject<{
500
509
  hardkasVersion: z.ZodString;
501
510
  version: z.ZodLiteral<"1.0.0-alpha">;
511
+ hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
502
512
  contentHash: z.ZodOptional<z.ZodString>;
503
513
  createdAt: z.ZodString;
504
514
  lineage: z.ZodOptional<z.ZodObject<{
@@ -636,6 +646,7 @@ declare const TxReceiptSchema: z.ZodObject<{
636
646
  amountSompi: string;
637
647
  txId: string;
638
648
  feeSompi: string;
649
+ hashVersion?: string | number | undefined;
639
650
  contentHash?: string | undefined;
640
651
  lineage?: {
641
652
  artifactId: string;
@@ -692,6 +703,7 @@ declare const TxReceiptSchema: z.ZodObject<{
692
703
  amountSompi: string;
693
704
  txId: string;
694
705
  feeSompi: string;
706
+ hashVersion?: string | number | undefined;
695
707
  contentHash?: string | undefined;
696
708
  lineage?: {
697
709
  artifactId: string;
@@ -731,6 +743,7 @@ declare const TxReceiptSchema: z.ZodObject<{
731
743
  declare const SignedTxSchema: z.ZodObject<{
732
744
  hardkasVersion: z.ZodString;
733
745
  version: z.ZodLiteral<"1.0.0-alpha">;
746
+ hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
734
747
  contentHash: z.ZodOptional<z.ZodString>;
735
748
  createdAt: z.ZodString;
736
749
  lineage: z.ZodOptional<z.ZodObject<{
@@ -823,6 +836,7 @@ declare const SignedTxSchema: z.ZodObject<{
823
836
  format: string;
824
837
  payload: string;
825
838
  };
839
+ hashVersion?: string | number | undefined;
826
840
  contentHash?: string | undefined;
827
841
  lineage?: {
828
842
  artifactId: string;
@@ -858,6 +872,7 @@ declare const SignedTxSchema: z.ZodObject<{
858
872
  format: string;
859
873
  payload: string;
860
874
  };
875
+ hashVersion?: string | number | undefined;
861
876
  contentHash?: string | undefined;
862
877
  lineage?: {
863
878
  artifactId: string;
@@ -872,6 +887,7 @@ declare const SignedTxSchema: z.ZodObject<{
872
887
  declare const TxTraceSchema: z.ZodObject<{
873
888
  hardkasVersion: z.ZodString;
874
889
  version: z.ZodLiteral<"1.0.0-alpha">;
890
+ hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
875
891
  contentHash: z.ZodOptional<z.ZodString>;
876
892
  createdAt: z.ZodString;
877
893
  lineage: z.ZodOptional<z.ZodObject<{
@@ -976,6 +992,7 @@ declare const TxTraceSchema: z.ZodObject<{
976
992
  timestamp: string;
977
993
  details?: any;
978
994
  }[];
995
+ hashVersion?: string | number | undefined;
979
996
  contentHash?: string | undefined;
980
997
  lineage?: {
981
998
  artifactId: string;
@@ -1012,6 +1029,7 @@ declare const TxTraceSchema: z.ZodObject<{
1012
1029
  timestamp: string;
1013
1030
  details?: any;
1014
1031
  }[];
1032
+ hashVersion?: string | number | undefined;
1015
1033
  contentHash?: string | undefined;
1016
1034
  lineage?: {
1017
1035
  artifactId: string;
@@ -1040,6 +1058,7 @@ type Snapshot = z.infer<typeof SnapshotSchema>;
1040
1058
  type TxReceipt = z.infer<typeof TxReceiptSchema>;
1041
1059
  type SignedTx = z.infer<typeof SignedTxSchema>;
1042
1060
  type TxTrace = z.infer<typeof TxTraceSchema>;
1061
+ type DagContext$1 = z.infer<typeof DagContextSchema>;
1043
1062
 
1044
1063
  interface ArtifactValidationResult {
1045
1064
  ok: boolean;
@@ -1118,15 +1137,16 @@ declare function assertDecimalBigIntString(value: any, field: string, errors: st
1118
1137
  declare function assertHexData(value: any, field: string, errors: string[]): void;
1119
1138
  declare function assertEvmAddress(value: any, field: string, errors: string[]): void;
1120
1139
  declare function assertEvmTxHash(value: any, field: string, errors: string[]): void;
1121
- declare function createIgraPlanId(): string;
1122
- declare function createIgraSignedId(): string;
1123
- declare function createIgraDeployPlanId(): string;
1140
+ declare function createIgraPlanId(hash: string): string;
1141
+ declare function createIgraSignedId(hash: string): string;
1142
+ declare function createIgraDeployPlanId(hash: string): string;
1124
1143
 
1125
1144
  type AssumptionLevel = "dev" | "trusted" | "network-observed";
1126
1145
  interface HardkasArtifactBase {
1127
1146
  schema: HardkasArtifactSchema;
1128
1147
  hardkasVersion: string;
1129
1148
  version: string;
1149
+ hashVersion?: number | string;
1130
1150
  networkId: NetworkId;
1131
1151
  mode: ExecutionMode;
1132
1152
  createdAt: string;
@@ -1135,6 +1155,7 @@ interface BaseArtifact<T extends ArtifactType> {
1135
1155
  schema: `hardkas.${T}`;
1136
1156
  hardkasVersion: string;
1137
1157
  version: string;
1158
+ hashVersion?: number | string;
1138
1159
  networkId: NetworkId;
1139
1160
  mode: ExecutionMode;
1140
1161
  createdAt: string;
@@ -1365,18 +1386,70 @@ interface TxTraceArtifact extends BaseArtifact<"txTrace"> {
1365
1386
  dagContext?: DagContext | undefined;
1366
1387
  }
1367
1388
 
1389
+ interface DeploymentRecord extends HardkasArtifactBase {
1390
+ schema: "hardkas.deployment.v1";
1391
+ /** Human-readable label (e.g., "initial-funding", "vault-covenant-v1") */
1392
+ label: string;
1393
+ /** Network where this was deployed */
1394
+ networkId: NetworkId;
1395
+ /** Deployment status */
1396
+ status: "planned" | "sent" | "confirmed" | "failed" | "unknown";
1397
+ /** The transaction ID (if sent) */
1398
+ txId?: TxId;
1399
+ /** Reference to the plan artifact that produced this deployment */
1400
+ planArtifactId?: ArtifactId;
1401
+ /** Reference to the receipt artifact (if confirmed) */
1402
+ receiptArtifactId?: ArtifactId;
1403
+ /** Deployed addresses or outputs (for covenant/contract deployments) */
1404
+ deployedAddresses?: string[];
1405
+ /** Deployment metadata */
1406
+ deployer?: string;
1407
+ /** Content hash of the deployed payload (bytecode, script, or tx content) */
1408
+ payloadHash?: string;
1409
+ /** Timestamp of deployment */
1410
+ deployedAt: string;
1411
+ /** HardKAS version used */
1412
+ hardkasVersion: string;
1413
+ /** Canonical content hash of this record */
1414
+ contentHash?: ContentHash;
1415
+ /** Notes */
1416
+ notes?: string;
1417
+ }
1418
+ interface DeploymentIndex extends HardkasArtifactBase {
1419
+ schema: "hardkas.deploymentIndex.v1";
1420
+ networkId: NetworkId;
1421
+ deployments: DeploymentSummary[];
1422
+ lastUpdated: string;
1423
+ }
1424
+ interface DeploymentSummary {
1425
+ label: string;
1426
+ networkId: NetworkId;
1427
+ status: string;
1428
+ txId?: string;
1429
+ deployedAt: string;
1430
+ contentHash: string;
1431
+ }
1432
+
1433
+ declare const SEMANTIC_EXCLUSIONS: Set<string>;
1434
+ /**
1435
+ * Current canonicalization version.
1436
+ * v1: BigInt(123) -> "123" (Collision with String "123")
1437
+ * v2: BigInt(123) -> "n:123" (Distinguishable)
1438
+ * v3: String normalization (\r\n -> \n, NFC) for cross-platform stability.
1439
+ */
1440
+ declare const CURRENT_HASH_VERSION = 3;
1368
1441
  /**
1369
1442
  * Deterministically stringifies an object by sorting keys recursively.
1370
- * Handles BigInt by converting to string.
1371
- * Excludes 'contentHash', 'artifactId', and 'lineage' fields during serialization.
1443
+ * Handles BigInt by converting to string with type marker.
1444
+ * Excludes fields in SEMANTIC_EXCLUSIONS during serialization.
1372
1445
  * Skips keys with undefined values (matching JSON.stringify behavior).
1373
1446
  */
1374
- declare function canonicalStringify(obj: any): string;
1447
+ declare function canonicalStringify(obj: any, version?: number): string;
1375
1448
  /**
1376
1449
  * Calculates a SHA-256 hash of the canonical JSON representation.
1377
- * Always excludes the 'contentHash' field from the calculation.
1450
+ * Always excludes fields in SEMANTIC_EXCLUSIONS from the calculation.
1378
1451
  */
1379
- declare function calculateContentHash(obj: any): string;
1452
+ declare function calculateContentHash(obj: any, version?: number): string;
1380
1453
 
1381
1454
  interface Clock {
1382
1455
  now(): number;
@@ -1388,12 +1461,13 @@ interface VerificationContext {
1388
1461
  networkId?: NetworkId;
1389
1462
  parent?: unknown;
1390
1463
  }
1391
- type VerificationSeverity = "info" | "warning" | "error" | "critical";
1464
+ type VerificationSeverity = CorruptionSeverity | "info" | "critical";
1392
1465
  type VerificationIssue = {
1393
- code: string;
1466
+ code: CorruptionCode | string;
1394
1467
  severity: VerificationSeverity;
1395
1468
  message: string;
1396
1469
  path?: string | undefined;
1470
+ pathStr?: string | undefined;
1397
1471
  artifactId?: string | undefined;
1398
1472
  };
1399
1473
  type ArtifactVerificationResult = {
@@ -1420,9 +1494,9 @@ declare function verifyArtifactIntegrity(artifactOrPath: unknown): Promise<Artif
1420
1494
  declare function verifyArtifactSemantics(artifact: unknown, context?: VerificationContext): ArtifactVerificationResult;
1421
1495
  /**
1422
1496
  * Verifies an artifact's replay consistency.
1423
- * Contract/Stub for Phase 4.
1497
+ * Honest implementation: reports as unsupported or not implemented.
1424
1498
  */
1425
- declare function verifyArtifactReplay(artifact: unknown, context?: VerificationContext): Promise<ArtifactVerificationResult>;
1499
+ declare function verifyArtifactReplay(artifact: unknown, _context?: VerificationContext): Promise<ArtifactVerificationResult>;
1426
1500
  /**
1427
1501
  * @deprecated Use verifyArtifactIntegrity instead.
1428
1502
  */
@@ -1631,6 +1705,9 @@ declare function createSimulatedTxReceipt(plan: TxPlan, txId: string, extra?: {
1631
1705
  spentUtxoIds?: string[];
1632
1706
  createdUtxoIds?: string[];
1633
1707
  daaScore?: string;
1708
+ preStateHash?: string;
1709
+ postStateHash?: string;
1710
+ dagContext?: DagContext$1;
1634
1711
  }): TxReceipt;
1635
1712
  /**
1636
1713
  * Validates and extracts the raw transaction from a signed artifact.
@@ -1728,9 +1805,53 @@ interface LineageValidationResult {
1728
1805
  ok: boolean;
1729
1806
  issues: VerificationIssue[];
1730
1807
  }
1808
+ interface LineageOptions {
1809
+ strict?: boolean;
1810
+ }
1731
1811
  /**
1732
1812
  * Validates the lineage relationship between an artifact and its parent.
1733
1813
  */
1734
- declare function verifyLineage(artifact: any, parent?: any): LineageValidationResult;
1814
+ declare function verifyLineage(artifact: any, parent?: any, options?: LineageOptions): LineageValidationResult;
1815
+
1816
+ interface DiffEntry {
1817
+ path: string;
1818
+ kind: "added" | "removed" | "changed";
1819
+ left?: any;
1820
+ right?: any;
1821
+ }
1822
+ interface ArtifactDiff {
1823
+ identical: boolean;
1824
+ entries: DiffEntry[];
1825
+ }
1826
+ /**
1827
+ * Performs a semantic diff between two artifacts, ignoring volatile metadata.
1828
+ * Uses the same exclusion rules as canonical hashing.
1829
+ * Redacts secrets from the output.
1830
+ */
1831
+ declare function diffArtifacts(left: any, right: any): ArtifactDiff;
1832
+
1833
+ declare function createDeploymentRecord(opts: {
1834
+ label: string;
1835
+ networkId: NetworkId;
1836
+ status?: "planned" | "sent" | "confirmed" | "failed" | "unknown";
1837
+ txId?: TxId;
1838
+ planArtifactId?: ArtifactId;
1839
+ receiptArtifactId?: ArtifactId;
1840
+ deployedAddresses?: string[];
1841
+ deployer?: string;
1842
+ payloadHash?: string;
1843
+ notes?: string;
1844
+ }): DeploymentRecord;
1845
+ declare function updateDeploymentStatus(record: DeploymentRecord, newStatus: DeploymentRecord["status"], txId?: TxId): DeploymentRecord;
1846
+
1847
+ /**
1848
+ * Manages deployment records on the filesystem.
1849
+ * Storage: .hardkas/deployments/<networkId>/<label>.json
1850
+ */
1851
+ declare function saveDeployment(rootDir: string, record: DeploymentRecord): Promise<string>;
1852
+ declare function loadDeployment(rootDir: string, networkId: string, label: string): Promise<DeploymentRecord | null>;
1853
+ declare function listDeployments(rootDir: string, networkId?: string): Promise<DeploymentSummary[]>;
1854
+ declare function updateDeployment(rootDir: string, networkId: string, label: string, update: Partial<DeploymentRecord>): Promise<DeploymentRecord>;
1855
+ declare function deleteDeployment(rootDir: string, networkId: string, label: string): Promise<boolean>;
1735
1856
 
1736
- export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactValidationResult, type ArtifactVerificationResult, type AssumptionLevel, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageValidationResult, LocalnetUtxoSchemaV2, NetworkInvariant, ReplayInvariant, SchemaInvariant, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canonicalStringify, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, isIgraTxPlanArtifact, listIgraTxReceiptArtifacts, loadIgraTxReceiptArtifact, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
1857
+ export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactDiff, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactValidationResult, type ArtifactVerificationResult, type AssumptionLevel, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, CURRENT_HASH_VERSION, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type DeploymentIndex, type DeploymentRecord, type DeploymentSummary, type DiffEntry, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageOptions, type LineageValidationResult, LocalnetUtxoSchemaV2, NetworkInvariant, ReplayInvariant, SEMANTIC_EXCLUSIONS, SchemaInvariant, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canonicalStringify, createDeploymentRecord, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, deleteDeployment, diffArtifacts, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, isIgraTxPlanArtifact, listDeployments, listIgraTxReceiptArtifacts, loadDeployment, loadIgraTxReceiptArtifact, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, saveDeployment, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, updateDeployment, updateDeploymentStatus, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/constants.ts
2
- var HARDKAS_VERSION = "0.2.2-alpha";
2
+ var HARDKAS_VERSION = "0.3.0-alpha";
3
3
  var ARTIFACT_SCHEMAS = {
4
4
  LOCALNET_STATE: "hardkas.localnetState.v1",
5
5
  REAL_ACCOUNT_STORE: "hardkas.realAccountStore.v1",
@@ -121,39 +121,64 @@ function assertEvmTxHash(value, field, errors) {
121
121
  errors.push(`Invalid ${field}: must be a 0x-prefixed 64-character EVM transaction hash`);
122
122
  }
123
123
  }
124
- function createIgraPlanId() {
125
- return `igra-plan-${Date.now()}-${Math.floor(Math.random() * 1e3)}`;
124
+ function createIgraPlanId(hash) {
125
+ return `igra-plan-${hash.slice(0, 16)}`;
126
126
  }
127
- function createIgraSignedId() {
128
- return `igra-signed-${Date.now()}-${Math.floor(Math.random() * 1e3)}`;
127
+ function createIgraSignedId(hash) {
128
+ return `igra-signed-${hash.slice(0, 16)}`;
129
129
  }
130
- function createIgraDeployPlanId() {
131
- return `igradeploy_${Date.now()}_${Math.floor(Math.random() * 1e3)}`;
130
+ function createIgraDeployPlanId(hash) {
131
+ return `igradeploy_${hash.slice(0, 16)}`;
132
132
  }
133
133
 
134
134
  // src/canonical.ts
135
135
  import { createHash } from "crypto";
136
- function canonicalStringify(obj) {
136
+ var SEMANTIC_EXCLUSIONS = /* @__PURE__ */ new Set([
137
+ "contentHash",
138
+ "artifactId",
139
+ "planId",
140
+ "lineage",
141
+ "createdAt",
142
+ "rpcUrl",
143
+ "indexedAt",
144
+ "file_path",
145
+ "file_mtime_ms",
146
+ "hardkasVersion",
147
+ "hashVersion",
148
+ // Exclude hash version from hash
149
+ "parentArtifactId",
150
+ "signedId",
151
+ "deployedAt"
152
+ ]);
153
+ var CURRENT_HASH_VERSION = 3;
154
+ function canonicalStringify(obj, version = CURRENT_HASH_VERSION) {
137
155
  if (obj === null || typeof obj !== "object") {
138
156
  if (typeof obj === "bigint") {
139
- return obj.toString();
157
+ if (version >= 2) {
158
+ return JSON.stringify(`n:${obj.toString()}`);
159
+ }
160
+ return JSON.stringify(obj.toString());
161
+ }
162
+ if (typeof obj === "string" && version >= 3) {
163
+ const normalized = obj.normalize("NFC").replace(/\r\n/g, "\n");
164
+ return JSON.stringify(normalized);
140
165
  }
141
166
  return JSON.stringify(obj);
142
167
  }
143
168
  if (Array.isArray(obj)) {
144
- return "[" + obj.map((item) => canonicalStringify(item)).join(",") + "]";
169
+ return "[" + obj.map((item) => canonicalStringify(item, version)).join(",") + "]";
145
170
  }
146
171
  const sortedKeys = Object.keys(obj).filter(
147
- (key) => key !== "contentHash" && key !== "artifactId" && key !== "lineage" && obj[key] !== void 0
172
+ (key) => !SEMANTIC_EXCLUSIONS.has(key) && obj[key] !== void 0
148
173
  ).sort();
149
174
  const result = sortedKeys.map((key) => {
150
175
  const value = obj[key];
151
- return JSON.stringify(key) + ":" + canonicalStringify(value);
176
+ return JSON.stringify(key) + ":" + canonicalStringify(value, version);
152
177
  }).join(",");
153
178
  return "{" + result + "}";
154
179
  }
155
- function calculateContentHash(obj) {
156
- const canonical = canonicalStringify(obj);
180
+ function calculateContentHash(obj, version = CURRENT_HASH_VERSION) {
181
+ const canonical = canonicalStringify(obj, version);
157
182
  return createHash("sha256").update(canonical).digest("hex");
158
183
  }
159
184
 
@@ -172,6 +197,7 @@ var BaseArtifactSchema = z.object({
172
197
  schema: z.string(),
173
198
  hardkasVersion: z.string(),
174
199
  version: z.literal(ARTIFACT_VERSION),
200
+ hashVersion: z.union([z.number(), z.string()]).optional(),
175
201
  networkId: kaspaNetworkIdSchema,
176
202
  mode: executionModeSchema,
177
203
  contentHash: z.string().optional(),
@@ -381,14 +407,15 @@ function verifyFeeSemantics(artifact) {
381
407
  }
382
408
 
383
409
  // src/lineage.ts
384
- function verifyLineage(artifact, parent) {
410
+ function verifyLineage(artifact, parent, options = {}) {
385
411
  const issues = [];
386
412
  const addIssue = (code, message, severity = "error") => {
387
413
  issues.push({ code, severity, message });
388
414
  };
389
415
  const lineage = artifact.lineage;
390
416
  if (!lineage) {
391
- addIssue("MISSING_LINEAGE", "Artifact has no lineage metadata", "warning");
417
+ const severity = options.strict ? "error" : "warning";
418
+ addIssue("MISSING_LINEAGE", "Artifact has no lineage metadata", severity);
392
419
  return {
393
420
  ok: issues.every((i) => i.severity !== "error"),
394
421
  issues
@@ -413,26 +440,32 @@ function verifyLineage(artifact, parent) {
413
440
  if (!parentLineage) {
414
441
  addIssue("PARENT_MISSING_LINEAGE", "Parent artifact has no lineage metadata");
415
442
  } else {
443
+ if (!lineage.parentArtifactId) {
444
+ addIssue("MISSING_PARENT_ID", "Artifact is missing parentArtifactId reference, but parent was provided for verification.");
445
+ } else if (lineage.parentArtifactId !== parentLineage.artifactId) {
446
+ addIssue("PARENT_ID_MISMATCH", `Parent Artifact ID mismatch: expected ${parentLineage.artifactId}, got ${lineage.parentArtifactId}`);
447
+ }
416
448
  if (lineage.lineageId !== parentLineage.lineageId) {
417
449
  addIssue("LINEAGE_ID_MISMATCH", `Lineage ID mismatch: expected ${parentLineage.lineageId}, got ${lineage.lineageId}`);
418
450
  }
419
451
  if (lineage.rootArtifactId !== parentLineage.rootArtifactId) {
420
- addIssue("ROOT_ID_MISMATCH", `Root Artifact ID mismatch: expected ${parentLineage.rootArtifactId}, got ${lineage.rootArtifactId}`);
421
- }
422
- if (lineage.parentArtifactId && lineage.parentArtifactId !== parentLineage.artifactId) {
423
- addIssue("PARENT_ID_MISMATCH", `Parent Artifact ID mismatch: expected ${parentLineage.artifactId}, got ${lineage.parentArtifactId}`);
452
+ addIssue("ROOT_ARTIFACT_ID_MISMATCH", `Root Artifact ID mismatch: expected ${parentLineage.rootArtifactId}, got ${lineage.rootArtifactId}`);
424
453
  }
425
454
  if (lineage.sequence !== void 0 && parentLineage.sequence !== void 0) {
426
455
  if (lineage.sequence <= parentLineage.sequence) {
427
- addIssue("INVALID_SEQUENCE", `Invalid sequence: current (${lineage.sequence}) must be greater than parent (${parentLineage.sequence})`);
456
+ const severity = options.strict ? "error" : "warning";
457
+ addIssue("NON_MONOTONIC_SEQUENCE", `Non-monotonic sequence: current (${lineage.sequence}) <= parent (${parentLineage.sequence}).`, severity);
428
458
  }
429
459
  }
430
460
  }
431
461
  if (artifact.networkId !== parent.networkId) {
432
- addIssue("NETWORK_CONTAMINATION", `Network mismatch: parent is ${parent.networkId}, current is ${artifact.networkId}`);
462
+ addIssue("NETWORK_MISMATCH", `Network mismatch: parent is ${parent.networkId}, current is ${artifact.networkId}`);
433
463
  }
434
464
  if (artifact.mode !== parent.mode) {
435
- addIssue("MODE_CONTAMINATION", `Mode mismatch: parent is ${parent.mode}, current is ${artifact.mode}`);
465
+ addIssue("MODE_MISMATCH", `Mode mismatch: parent is ${parent.mode}, current is ${artifact.mode}`);
466
+ }
467
+ if (lineage.artifactId === lineage.parentArtifactId) {
468
+ addIssue("SELF_PARENT", "Artifact cannot be its own parent.");
436
469
  }
437
470
  }
438
471
  if (parent) {
@@ -469,9 +502,9 @@ async function verifyArtifactIntegrity(artifactOrPath) {
469
502
  errors: [],
470
503
  issues: []
471
504
  };
472
- const addError = (code, message, path3) => {
505
+ const addError = (code, message, path4) => {
473
506
  result.errors.push(message);
474
- result.issues.push({ code, severity: "error", message, path: path3 });
507
+ result.issues.push({ code, severity: "error", message, path: path4 });
475
508
  };
476
509
  let artifact;
477
510
  try {
@@ -490,21 +523,22 @@ async function verifyArtifactIntegrity(artifactOrPath) {
490
523
  result.version = v.version;
491
524
  result.expectedHash = v.contentHash;
492
525
  if (!v.version || !v.schema) {
493
- addError("MISSING_METADATA", "Missing version or schema (Artifact might be v1 or legacy)");
526
+ addError("ARTIFACT_SCHEMA_MISSING", "Missing version or schema (Artifact might be v1 or legacy)");
494
527
  return result;
495
528
  }
496
529
  const [currentMajor] = ARTIFACT_VERSION.split(".");
497
530
  const [artifactMajor] = v.version.split(".");
498
531
  if (currentMajor !== artifactMajor) {
499
- addError("INCOMPATIBLE_VERSION", `Incompatible version: current system is v${currentMajor}, artifact is v${artifactMajor}`);
532
+ addError("ARTIFACT_SCHEMA_INVALID", `Incompatible version: current system is v${currentMajor}, artifact is v${artifactMajor}`);
500
533
  return result;
501
534
  }
502
- const actualHash = calculateContentHash(v);
535
+ const hashVersion = v.hashVersion || 1;
536
+ const actualHash = calculateContentHash(v, hashVersion);
503
537
  result.actualHash = actualHash;
504
538
  if (!v.contentHash) {
505
- addError("MISSING_HASH", "Missing contentHash field");
539
+ addError("ARTIFACT_HASH_MISMATCH", "Missing contentHash field");
506
540
  } else if (actualHash !== v.contentHash) {
507
- addError("HASH_MISMATCH", `Hash mismatch: expected ${v.contentHash}, got ${actualHash}`);
541
+ addError("ARTIFACT_HASH_MISMATCH", `Hash mismatch: expected ${v.contentHash}, got ${actualHash}`);
508
542
  }
509
543
  let schema;
510
544
  switch (v.schema) {
@@ -529,16 +563,20 @@ async function verifyArtifactIntegrity(artifactOrPath) {
529
563
  if (!validation.success) {
530
564
  validation.error.issues.forEach((e) => {
531
565
  const pathStr = e.path.join(".");
532
- addError("SCHEMA_VALIDATION_ERROR", `${pathStr}: ${e.message}`, pathStr);
566
+ addError("ARTIFACT_SCHEMA_INVALID", `${pathStr}: ${e.message}`, pathStr);
533
567
  });
534
568
  }
535
569
  } else {
536
- addError("UNSUPPORTED_SCHEMA", `Unsupported or unknown artifact schema: ${v.schema}`);
570
+ addError("ARTIFACT_SCHEMA_INVALID", `Unsupported or unknown artifact schema: ${v.schema}`);
537
571
  }
538
572
  result.ok = result.issues.every((i) => i.severity !== "error" && i.severity !== "critical");
539
573
  return result;
540
574
  } catch (e) {
541
- addError("UNEXPECTED_ERROR", `Integrity verification error: ${e.message}`);
575
+ if (e instanceof SyntaxError) {
576
+ addError("ARTIFACT_JSON_INVALID", `Invalid JSON: ${e.message}`);
577
+ } else {
578
+ addError("ARTIFACT_ID_INVALID", `Unexpected verification error: ${e.message}`);
579
+ }
542
580
  return result;
543
581
  }
544
582
  }
@@ -584,22 +622,10 @@ function verifyArtifactSemantics(artifact, context = {}) {
584
622
  });
585
623
  }
586
624
  }
587
- if (v.schema === "hardkas.signedTx" && v.mode === "simulated") {
588
- }
589
- const lineageAudit = verifyLineage(v, context.parent);
625
+ const lineageAudit = verifyLineage(v, context.parent, { strict });
590
626
  if (!lineageAudit.ok || strict && !v.lineage) {
591
- if (!v.lineage && strict) {
592
- addIssue({
593
- code: "MISSING_LINEAGE",
594
- severity: "error",
595
- message: "Strict mode requires formal lineage metadata."
596
- });
597
- }
598
627
  lineageAudit.issues.forEach((issue) => {
599
- addIssue({
600
- ...issue,
601
- severity: strict ? "error" : "warning"
602
- });
628
+ addIssue(issue);
603
629
  });
604
630
  }
605
631
  if (strict) {
@@ -626,31 +652,17 @@ function verifyArtifactSemantics(artifact, context = {}) {
626
652
  });
627
653
  }
628
654
  }
629
- const lineage = v.lineage;
630
- if (lineage) {
631
- const { artifactId, parentArtifactId, rootArtifactId } = lineage;
632
- if (artifactId === parentArtifactId) {
633
- addIssue({
634
- code: "LINEAGE_INCONSISTENCY",
635
- severity: "error",
636
- message: "Artifact cannot be its own parent."
637
- });
638
- }
639
- if (!parentArtifactId && artifactId !== rootArtifactId) {
640
- addIssue({
641
- code: "LINEAGE_INCONSISTENCY",
642
- severity: "error",
643
- message: "Root artifactId must match artifactId when no parent exists."
644
- });
645
- }
646
- }
647
655
  return result;
648
656
  }
649
- async function verifyArtifactReplay(artifact, context = {}) {
657
+ async function verifyArtifactReplay(artifact, _context = {}) {
650
658
  return {
651
- ok: true,
652
- issues: [],
653
- errors: []
659
+ ok: false,
660
+ issues: [{
661
+ code: "REPLAY_UNSUPPORTED_CHECK",
662
+ severity: "warning",
663
+ message: "Replay verification (full consensus simulation) is currently unsupported in this build."
664
+ }],
665
+ errors: ["Replay verification (consensus) unsupported"]
654
666
  };
655
667
  }
656
668
  var verifyArtifact = verifyArtifactIntegrity;
@@ -874,16 +886,11 @@ function migrateToCanonical(v1Artifact) {
874
886
  // src/io.ts
875
887
  import fs2 from "fs/promises";
876
888
  import path from "path";
889
+ import { writeFileAtomic } from "@hardkas/core";
877
890
  var bigIntReplacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
878
891
  async function writeArtifact(filePath, artifact) {
879
- try {
880
- const dir = path.dirname(filePath);
881
- await fs2.mkdir(dir, { recursive: true });
882
- const content = typeof artifact === "string" ? artifact : JSON.stringify(artifact, bigIntReplacer, 2) + "\n";
883
- await fs2.writeFile(filePath, content, "utf-8");
884
- } catch (error) {
885
- throw new Error(`Failed to write artifact at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
886
- }
892
+ const content = typeof artifact === "string" ? artifact : JSON.stringify(artifact, bigIntReplacer, 2) + "\n";
893
+ await writeFileAtomic(filePath, content);
887
894
  }
888
895
  function getDefaultReceiptPath(txId, cwd = process.cwd()) {
889
896
  return path.join(cwd, "artifacts", "receipts", `${txId}.json`);
@@ -1045,10 +1052,10 @@ function createTxPlanArtifact(options) {
1045
1052
  schema: "hardkas.txPlan",
1046
1053
  hardkasVersion: HARDKAS_VERSION,
1047
1054
  version: ARTIFACT_VERSION,
1055
+ hashVersion: CURRENT_HASH_VERSION,
1048
1056
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1049
1057
  networkId: options.networkId,
1050
1058
  mode: options.mode,
1051
- planId: `plan-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
1052
1059
  from: {
1053
1060
  address: options.from.address,
1054
1061
  accountName: options.from.accountName,
@@ -1080,7 +1087,9 @@ function createTxPlanArtifact(options) {
1080
1087
  amountSompi: options.plan.change.amountSompi.toString()
1081
1088
  };
1082
1089
  }
1083
- artifact.contentHash = calculateContentHash(artifact);
1090
+ const hash = calculateContentHash(artifact, CURRENT_HASH_VERSION);
1091
+ artifact.planId = `plan-${hash.slice(0, 16)}`;
1092
+ artifact.contentHash = hash;
1084
1093
  return artifact;
1085
1094
  }
1086
1095
 
@@ -1090,22 +1099,24 @@ function createSimulatedSignedTxArtifact(plan, payload) {
1090
1099
  schema: "hardkas.signedTx",
1091
1100
  hardkasVersion: HARDKAS_VERSION,
1092
1101
  version: ARTIFACT_VERSION,
1102
+ hashVersion: CURRENT_HASH_VERSION,
1093
1103
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1094
1104
  status: "signed",
1095
- signedId: `signed-${Date.now()}`,
1096
1105
  sourcePlanId: plan.planId,
1097
1106
  networkId: plan.networkId,
1098
1107
  mode: plan.mode,
1099
1108
  from: { address: plan.from.address },
1100
1109
  to: { address: plan.to.address },
1101
1110
  amountSompi: plan.amountSompi,
1102
- txId: `simulated-${plan.planId}-${Date.now()}`,
1103
1111
  signedTransaction: {
1104
1112
  format: "simulated",
1105
1113
  payload
1106
1114
  }
1107
1115
  };
1108
- artifact.contentHash = calculateContentHash(artifact);
1116
+ const hash = calculateContentHash(artifact, CURRENT_HASH_VERSION);
1117
+ artifact.signedId = `signed-${hash.slice(0, 16)}`;
1118
+ artifact.txId = `simulated-${plan.planId}-${hash.slice(0, 8)}`;
1119
+ artifact.contentHash = hash;
1109
1120
  return artifact;
1110
1121
  }
1111
1122
  function createSimulatedTxReceipt(plan, txId, extra) {
@@ -1113,6 +1124,7 @@ function createSimulatedTxReceipt(plan, txId, extra) {
1113
1124
  schema: "hardkas.txReceipt",
1114
1125
  hardkasVersion: HARDKAS_VERSION,
1115
1126
  version: ARTIFACT_VERSION,
1127
+ hashVersion: CURRENT_HASH_VERSION,
1116
1128
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1117
1129
  txId,
1118
1130
  status: "accepted",
@@ -1125,9 +1137,13 @@ function createSimulatedTxReceipt(plan, txId, extra) {
1125
1137
  changeSompi: plan.change?.amountSompi,
1126
1138
  spentUtxoIds: extra?.spentUtxoIds,
1127
1139
  createdUtxoIds: extra?.createdUtxoIds,
1128
- daaScore: extra?.daaScore
1140
+ daaScore: extra?.daaScore,
1141
+ preStateHash: extra?.preStateHash,
1142
+ postStateHash: extra?.postStateHash,
1143
+ dagContext: extra?.dagContext
1129
1144
  };
1130
- artifact.contentHash = calculateContentHash(artifact);
1145
+ const hash = calculateContentHash(artifact, CURRENT_HASH_VERSION);
1146
+ artifact.contentHash = hash;
1131
1147
  return artifact;
1132
1148
  }
1133
1149
  function getBroadcastableSignedTransaction(artifact) {
@@ -1351,6 +1367,162 @@ function validateTxHash(txHash) {
1351
1367
  throw new Error(`Invalid EVM txHash: must be a 0x-prefixed 64-character hex string. Got: ${txHash}`);
1352
1368
  }
1353
1369
  }
1370
+
1371
+ // src/diff.ts
1372
+ import { maskSecrets } from "@hardkas/core";
1373
+ function diffArtifacts(left, right) {
1374
+ const entries = [];
1375
+ const leftRedacted = maskSecrets(left);
1376
+ const rightRedacted = maskSecrets(right);
1377
+ compareRecursive(leftRedacted, rightRedacted, "$", entries);
1378
+ return {
1379
+ identical: entries.length === 0,
1380
+ entries
1381
+ };
1382
+ }
1383
+ function compareRecursive(left, right, path4, entries) {
1384
+ if (isPrimitive(left) || isPrimitive(right)) {
1385
+ if (left !== right) {
1386
+ entries.push({ path: path4, kind: "changed", left, right });
1387
+ }
1388
+ return;
1389
+ }
1390
+ if (Array.isArray(left) || Array.isArray(right)) {
1391
+ if (!Array.isArray(left) || !Array.isArray(right)) {
1392
+ entries.push({ path: path4, kind: "changed", left, right });
1393
+ return;
1394
+ }
1395
+ const maxLength = Math.max(left.length, right.length);
1396
+ for (let i = 0; i < maxLength; i++) {
1397
+ if (i >= left.length) {
1398
+ entries.push({ path: `${path4}[${i}]`, kind: "added", right: right[i] });
1399
+ } else if (i >= right.length) {
1400
+ entries.push({ path: `${path4}[${i}]`, kind: "removed", left: left[i] });
1401
+ } else {
1402
+ compareRecursive(left[i], right[i], `${path4}[${i}]`, entries);
1403
+ }
1404
+ }
1405
+ return;
1406
+ }
1407
+ const leftKeys = Object.keys(left).filter((k) => !SEMANTIC_EXCLUSIONS.has(k));
1408
+ const rightKeys = Object.keys(right).filter((k) => !SEMANTIC_EXCLUSIONS.has(k));
1409
+ const allKeys = /* @__PURE__ */ new Set([...leftKeys, ...rightKeys]);
1410
+ for (const key of allKeys) {
1411
+ const nextPath = path4 === "$" ? key : `${path4}.${key}`;
1412
+ if (!leftKeys.includes(key)) {
1413
+ entries.push({ path: nextPath, kind: "added", right: right[key] });
1414
+ } else if (!rightKeys.includes(key)) {
1415
+ entries.push({ path: nextPath, kind: "removed", left: left[key] });
1416
+ } else {
1417
+ compareRecursive(left[key], right[key], nextPath, entries);
1418
+ }
1419
+ }
1420
+ }
1421
+ function isPrimitive(val) {
1422
+ if (val === null) return true;
1423
+ return typeof val !== "object" && typeof val !== "function";
1424
+ }
1425
+
1426
+ // src/deployment.ts
1427
+ function createDeploymentRecord(opts) {
1428
+ const record = {
1429
+ schema: "hardkas.deployment.v1",
1430
+ label: opts.label,
1431
+ networkId: opts.networkId,
1432
+ status: opts.status || "planned",
1433
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
1434
+ hardkasVersion: HARDKAS_VERSION,
1435
+ version: ARTIFACT_VERSION,
1436
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1437
+ mode: "real"
1438
+ };
1439
+ if (opts.txId) record.txId = opts.txId;
1440
+ if (opts.planArtifactId) record.planArtifactId = opts.planArtifactId;
1441
+ if (opts.receiptArtifactId) record.receiptArtifactId = opts.receiptArtifactId;
1442
+ if (opts.deployedAddresses) record.deployedAddresses = opts.deployedAddresses;
1443
+ if (opts.deployer) record.deployer = opts.deployer;
1444
+ if (opts.payloadHash) record.payloadHash = opts.payloadHash;
1445
+ if (opts.notes) record.notes = opts.notes;
1446
+ record.contentHash = calculateContentHash(record, CURRENT_HASH_VERSION);
1447
+ return record;
1448
+ }
1449
+ function updateDeploymentStatus(record, newStatus, txId) {
1450
+ const updated = {
1451
+ ...record,
1452
+ status: newStatus,
1453
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString()
1454
+ };
1455
+ if (txId) updated.txId = txId;
1456
+ delete updated.contentHash;
1457
+ updated.contentHash = calculateContentHash(updated, CURRENT_HASH_VERSION);
1458
+ return updated;
1459
+ }
1460
+
1461
+ // src/deployment-store.ts
1462
+ import fs4 from "fs/promises";
1463
+ import { existsSync } from "fs";
1464
+ import path3 from "path";
1465
+ import { writeFileAtomic as writeFileAtomic2 } from "@hardkas/core";
1466
+ async function saveDeployment(rootDir, record) {
1467
+ const deploymentsDir = path3.join(rootDir, ".hardkas", "deployments", record.networkId);
1468
+ const targetPath = path3.join(deploymentsDir, `${record.label}.json`);
1469
+ await writeFileAtomic2(targetPath, JSON.stringify(record, null, 2));
1470
+ return targetPath;
1471
+ }
1472
+ async function loadDeployment(rootDir, networkId, label) {
1473
+ const targetPath = path3.join(rootDir, ".hardkas", "deployments", networkId, `${label}.json`);
1474
+ if (!existsSync(targetPath)) return null;
1475
+ const content = await fs4.readFile(targetPath, "utf-8");
1476
+ return JSON.parse(content);
1477
+ }
1478
+ async function listDeployments(rootDir, networkId) {
1479
+ const baseDir = path3.join(rootDir, ".hardkas", "deployments");
1480
+ if (!existsSync(baseDir)) return [];
1481
+ const summaries = [];
1482
+ const networks = networkId ? [networkId] : await fs4.readdir(baseDir);
1483
+ for (const net of networks) {
1484
+ const netDir = path3.join(baseDir, net);
1485
+ if (!existsSync(netDir)) continue;
1486
+ const files = await fs4.readdir(netDir);
1487
+ for (const file of files) {
1488
+ if (!file.endsWith(".json")) continue;
1489
+ try {
1490
+ const content = await fs4.readFile(path3.join(netDir, file), "utf-8");
1491
+ const record = JSON.parse(content);
1492
+ const summary = {
1493
+ label: record.label,
1494
+ networkId: record.networkId,
1495
+ status: record.status,
1496
+ deployedAt: record.deployedAt,
1497
+ contentHash: record.contentHash || ""
1498
+ };
1499
+ if (record.txId) summary.txId = record.txId;
1500
+ summaries.push(summary);
1501
+ } catch (e) {
1502
+ }
1503
+ }
1504
+ }
1505
+ return summaries.sort((a, b) => new Date(b.deployedAt).getTime() - new Date(a.deployedAt).getTime());
1506
+ }
1507
+ async function updateDeployment(rootDir, networkId, label, update) {
1508
+ const existing = await loadDeployment(rootDir, networkId, label);
1509
+ if (!existing) {
1510
+ throw new Error(`Deployment '${label}' not found on network '${networkId}'.`);
1511
+ }
1512
+ const updated = {
1513
+ ...existing,
1514
+ ...update,
1515
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString()
1516
+ };
1517
+ await saveDeployment(rootDir, updated);
1518
+ return updated;
1519
+ }
1520
+ async function deleteDeployment(rootDir, networkId, label) {
1521
+ const targetPath = path3.join(rootDir, ".hardkas", "deployments", networkId, `${label}.json`);
1522
+ if (!existsSync(targetPath)) return false;
1523
+ await fs4.unlink(targetPath);
1524
+ return true;
1525
+ }
1354
1526
  export {
1355
1527
  ARTIFACT_SCHEMAS,
1356
1528
  ARTIFACT_VERSION,
@@ -1359,6 +1531,7 @@ export {
1359
1531
  BaseArtifactSchema,
1360
1532
  BasicCorrelationInvariant,
1361
1533
  BasicLineageInvariant,
1534
+ CURRENT_HASH_VERSION,
1362
1535
  DagContextSchema,
1363
1536
  HARDKAS_VERSION,
1364
1537
  HashInvariant,
@@ -1367,6 +1540,7 @@ export {
1367
1540
  LocalnetUtxoSchemaV2,
1368
1541
  NetworkInvariant,
1369
1542
  ReplayInvariant,
1543
+ SEMANTIC_EXCLUSIONS,
1370
1544
  SchemaInvariant,
1371
1545
  SignedTxSchema,
1372
1546
  SnapshotSchema,
@@ -1386,6 +1560,7 @@ export {
1386
1560
  bigIntReplacer,
1387
1561
  calculateContentHash,
1388
1562
  canonicalStringify,
1563
+ createDeploymentRecord,
1389
1564
  createIgraDeployPlanId,
1390
1565
  createIgraPlanId,
1391
1566
  createIgraSignedId,
@@ -1393,6 +1568,8 @@ export {
1393
1568
  createSimulatedTxReceipt,
1394
1569
  createTxPlanArtifact,
1395
1570
  defaultClock,
1571
+ deleteDeployment,
1572
+ diffArtifacts,
1396
1573
  explainArtifact,
1397
1574
  formatSignedTxArtifact,
1398
1575
  formatTxPlanArtifact,
@@ -1402,7 +1579,9 @@ export {
1402
1579
  getDefaultReceiptPath,
1403
1580
  getL2ReceiptPath,
1404
1581
  isIgraTxPlanArtifact,
1582
+ listDeployments,
1405
1583
  listIgraTxReceiptArtifacts,
1584
+ loadDeployment,
1406
1585
  loadIgraTxReceiptArtifact,
1407
1586
  migrateToCanonical,
1408
1587
  readArtifact,
@@ -1410,10 +1589,13 @@ export {
1410
1589
  readTxPlanArtifact,
1411
1590
  readTxReceiptArtifact,
1412
1591
  recomputeMass,
1592
+ saveDeployment,
1413
1593
  saveIgraTxReceiptArtifact,
1414
1594
  sortUtxosByOutpoint,
1415
1595
  txOutputFromArtifact,
1416
1596
  txOutputToArtifact,
1597
+ updateDeployment,
1598
+ updateDeploymentStatus,
1417
1599
  utxoFromArtifact,
1418
1600
  utxoToArtifact,
1419
1601
  validateArtifact,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/artifacts",
3
- "version": "0.2.2-alpha",
3
+ "version": "0.3.0-alpha",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Javier Rodriguez",
@@ -24,8 +24,8 @@
24
24
  "types": "./dist/index.d.ts",
25
25
  "dependencies": {
26
26
  "zod": "^3.24.1",
27
- "@hardkas/core": "0.2.2-alpha",
28
- "@hardkas/tx-builder": "0.2.2-alpha"
27
+ "@hardkas/core": "0.3.0-alpha",
28
+ "@hardkas/tx-builder": "0.3.0-alpha"
29
29
  },
30
30
  "devDependencies": {
31
31
  "tsup": "^8.3.5",