@hardkas/artifacts 0.5.5-alpha → 0.6.1-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 +392 -33
  2. package/dist/index.js +341 -80
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,5 +1,48 @@
1
+ // package.json
2
+ var package_default = {
3
+ name: "@hardkas/artifacts",
4
+ version: "0.6.1-alpha",
5
+ type: "module",
6
+ license: "MIT",
7
+ author: "Javier Rodriguez",
8
+ repository: {
9
+ type: "git",
10
+ url: "git+https://github.com/KasLabDevs/HardKas.git",
11
+ directory: "packages/artifacts"
12
+ },
13
+ homepage: "https://github.com/KasLabDevs/HardKas/tree/main/packages/artifacts#readme",
14
+ bugs: {
15
+ url: "https://github.com/KasLabDevs/HardKas/issues"
16
+ },
17
+ files: [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ exports: {
23
+ ".": "./dist/index.js"
24
+ },
25
+ types: "./dist/index.d.ts",
26
+ scripts: {
27
+ build: "tsup src/index.ts --format esm --dts --clean",
28
+ dev: "tsup src/index.ts --format esm --watch --dts",
29
+ test: "vitest run",
30
+ lint: "tsc --noEmit"
31
+ },
32
+ dependencies: {
33
+ "@hardkas/core": "workspace:*",
34
+ "@hardkas/tx-builder": "workspace:*",
35
+ zod: "^3.24.1"
36
+ },
37
+ devDependencies: {
38
+ tsup: "^8.3.5",
39
+ typescript: "^5.6.3",
40
+ vitest: "^2.1.4"
41
+ }
42
+ };
43
+
1
44
  // src/constants.ts
2
- var HARDKAS_VERSION = "0.5.5-alpha";
45
+ var HARDKAS_VERSION = package_default.version;
3
46
  var ARTIFACT_SCHEMAS = {
4
47
  LOCALNET_STATE: "hardkas.localnetState.v1",
5
48
  REAL_ACCOUNT_STORE: "hardkas.realAccountStore.v1",
@@ -133,6 +176,7 @@ function createIgraDeployPlanId(hash) {
133
176
 
134
177
  // src/canonical.ts
135
178
  import { createHash } from "crypto";
179
+ import { deterministicCompare } from "@hardkas/core";
136
180
  var SEMANTIC_EXCLUSIONS = /* @__PURE__ */ new Set([
137
181
  "contentHash",
138
182
  "artifactId",
@@ -140,6 +184,8 @@ var SEMANTIC_EXCLUSIONS = /* @__PURE__ */ new Set([
140
184
  "lineage",
141
185
  "createdAt",
142
186
  "rpcUrl",
187
+ "rpcHost",
188
+ "latencyMs",
143
189
  "indexedAt",
144
190
  "file_path",
145
191
  "file_mtime_ms",
@@ -148,7 +194,15 @@ var SEMANTIC_EXCLUSIONS = /* @__PURE__ */ new Set([
148
194
  // Exclude hash version from hash
149
195
  "parentArtifactId",
150
196
  "signedId",
151
- "deployedAt"
197
+ "deployedAt",
198
+ "tracePath",
199
+ "receiptPath",
200
+ "events",
201
+ "status",
202
+ "sourceSignedId",
203
+ "submittedAt",
204
+ "confirmedAt",
205
+ "dagContext"
152
206
  ]);
153
207
  var CURRENT_HASH_VERSION = 3;
154
208
  function canonicalStringify(obj, version = CURRENT_HASH_VERSION) {
@@ -160,7 +214,7 @@ function canonicalStringify(obj, version = CURRENT_HASH_VERSION) {
160
214
  return JSON.stringify(obj.toString());
161
215
  }
162
216
  if (typeof obj === "string" && version >= 3) {
163
- const normalized = obj.normalize("NFC").replace(/\r\n/g, "\n");
217
+ const normalized = obj.normalize("NFC").replace(/\r\n/g, "\n").replace(/\\/g, "/");
164
218
  return JSON.stringify(normalized);
165
219
  }
166
220
  return JSON.stringify(obj);
@@ -168,9 +222,22 @@ function canonicalStringify(obj, version = CURRENT_HASH_VERSION) {
168
222
  if (Array.isArray(obj)) {
169
223
  return "[" + obj.map((item) => canonicalStringify(item, version)).join(",") + "]";
170
224
  }
225
+ if (obj instanceof Map) {
226
+ throw new Error("Map is not canonicalizable. Use a plain object.");
227
+ }
228
+ if (obj instanceof Set) {
229
+ throw new Error("Set is not canonicalizable. Use an array.");
230
+ }
231
+ if (obj instanceof Date) {
232
+ throw new Error("Date must be serialized explicitly.");
233
+ }
234
+ const proto = Object.getPrototypeOf(obj);
235
+ if (proto !== Object.prototype && proto !== null) {
236
+ throw new Error("Non-plain object encountered in canonicalizer.");
237
+ }
171
238
  const sortedKeys = Object.keys(obj).filter(
172
239
  (key) => !SEMANTIC_EXCLUSIONS.has(key) && obj[key] !== void 0
173
- ).sort();
240
+ ).sort(deterministicCompare);
174
241
  const result = sortedKeys.map((key) => {
175
242
  const value = obj[key];
176
243
  return JSON.stringify(key) + ":" + canonicalStringify(value, version);
@@ -293,6 +360,7 @@ var TxReceiptSchema = BaseArtifactSchema.extend({
293
360
  tracePath: z.string().optional(),
294
361
  rpcUrl: z.string().optional(),
295
362
  sourceSignedId: z.string().optional(),
363
+ errors: z.array(z.string()).optional(),
296
364
  metadata: z.any().optional()
297
365
  });
298
366
  var SignedTxSchema = BaseArtifactSchema.extend({
@@ -325,6 +393,42 @@ var TxTraceSchema = BaseArtifactSchema.extend({
325
393
  })),
326
394
  dagContext: DagContextSchema.optional()
327
395
  });
396
+ var WorkflowSchema = BaseArtifactSchema.extend({
397
+ schema: z.literal("hardkas.workflow.v1"),
398
+ workflowId: z.string(),
399
+ status: z.enum(["pending", "running", "completed", "failed"]),
400
+ inputs: z.record(z.any()).optional(),
401
+ steps: z.array(z.object({
402
+ type: z.string(),
403
+ status: z.enum(["pending", "success", "failed", "skipped"]),
404
+ startedAt: z.string().datetime().optional(),
405
+ completedAt: z.string().datetime().optional(),
406
+ producedArtifactId: z.string().optional(),
407
+ error: z.string().optional()
408
+ })),
409
+ parentArtifacts: z.array(z.string()).optional(),
410
+ producedArtifacts: z.array(z.string()),
411
+ generationRange: z.object({
412
+ start: z.string().optional(),
413
+ end: z.string().optional()
414
+ }).optional(),
415
+ policy: z.object({
416
+ allowNetwork: z.boolean(),
417
+ allowMainnet: z.boolean(),
418
+ allowExternalWallet: z.boolean(),
419
+ requireDryRun: z.boolean()
420
+ }).optional(),
421
+ generationId: z.string().optional(),
422
+ replayResult: z.object({
423
+ verified: z.boolean(),
424
+ stateHash: z.string().optional()
425
+ }).optional(),
426
+ errorEnvelope: z.object({
427
+ code: z.string(),
428
+ message: z.string(),
429
+ redacted: z.boolean()
430
+ }).optional()
431
+ });
328
432
 
329
433
  // src/verify.ts
330
434
  import fs from "fs";
@@ -414,8 +518,11 @@ function verifyLineage(artifact, parent, options = {}) {
414
518
  };
415
519
  const lineage = artifact.lineage;
416
520
  if (!lineage) {
417
- const severity = options.strict ? "error" : "warning";
418
- addIssue("MISSING_LINEAGE", "Artifact has no lineage metadata", severity);
521
+ const isWorkflow = artifact.schema === "hardkas.workflow.v1";
522
+ const severity = options.strict && !isWorkflow ? "error" : "warning";
523
+ if (!isWorkflow || options.strict) {
524
+ addIssue("MISSING_LINEAGE", "Artifact has no lineage metadata", severity);
525
+ }
419
526
  return {
420
527
  ok: issues.every((i) => i.severity !== "error"),
421
528
  issues
@@ -488,12 +595,20 @@ function verifyLineage(artifact, parent, options = {}) {
488
595
  // src/verify.ts
489
596
  var defaultClock = {
490
597
  now: () => Date.now()
598
+ // hardkas-determinism-allow: default clock ambient source
491
599
  };
600
+ function deterministicCompare2(a, b) {
601
+ return a < b ? -1 : a > b ? 1 : 0;
602
+ }
492
603
  function sortUtxosByOutpoint(utxos) {
493
604
  return [...utxos].sort((a, b) => {
494
- const aId = a.id || (a.outpoint ? `${a.outpoint.transactionId}:${a.outpoint.index}` : "");
495
- const bId = b.id || (b.outpoint ? `${b.outpoint.transactionId}:${b.outpoint.index}` : "");
496
- return aId.localeCompare(bId);
605
+ const aRec = a;
606
+ const bRec = b;
607
+ const aOutpoint = aRec.outpoint;
608
+ const bOutpoint = bRec.outpoint;
609
+ const aId = aRec.id || (aOutpoint ? `${aOutpoint.transactionId}:${aOutpoint.index}` : "");
610
+ const bId = bRec.id || (bOutpoint ? `${bOutpoint.transactionId}:${bOutpoint.index}` : "");
611
+ return deterministicCompare2(aId, bId);
497
612
  });
498
613
  }
499
614
  async function verifyArtifactIntegrity(artifactOrPath) {
@@ -525,6 +640,10 @@ async function verifyArtifactIntegrity(artifactOrPath) {
525
640
  result.artifactType = v.schema;
526
641
  result.version = v.version;
527
642
  result.expectedHash = v.contentHash;
643
+ if (v.schema === "hardkas.replayReport.v1") {
644
+ result.ok = true;
645
+ return result;
646
+ }
528
647
  if (!v.version || !v.schema) {
529
648
  addError("ARTIFACT_SCHEMA_MISSING", "Missing version or schema (Artifact might be v1 or legacy)");
530
649
  return result;
@@ -560,6 +679,9 @@ async function verifyArtifactIntegrity(artifactOrPath) {
560
679
  case "hardkas.signedTx":
561
680
  schema = SignedTxSchema;
562
681
  break;
682
+ case "hardkas.workflow.v1":
683
+ schema = WorkflowSchema;
684
+ break;
563
685
  }
564
686
  if (schema) {
565
687
  const validation = schema.safeParse(v);
@@ -577,8 +699,10 @@ async function verifyArtifactIntegrity(artifactOrPath) {
577
699
  } catch (e) {
578
700
  if (e instanceof SyntaxError) {
579
701
  addError("ARTIFACT_JSON_INVALID", `Invalid JSON: ${e.message}`);
580
- } else {
702
+ } else if (e instanceof Error) {
581
703
  addError("ARTIFACT_ID_INVALID", `Unexpected verification error: ${e.message}`);
704
+ } else {
705
+ addError("ARTIFACT_ID_INVALID", `Unexpected verification error: ${String(e)}`);
582
706
  }
583
707
  return result;
584
708
  }
@@ -626,19 +750,19 @@ function verifyArtifactSemantics(artifact, context = {}) {
626
750
  }
627
751
  }
628
752
  const lineageAudit = verifyLineage(v, context.parent, { strict });
629
- if (!lineageAudit.ok || strict && !v.lineage) {
753
+ if (!lineageAudit.ok || strict && !v.lineage && v.schema !== "hardkas.workflow.v1") {
630
754
  lineageAudit.issues.forEach((issue) => {
631
755
  addIssue(issue);
632
756
  });
633
757
  }
634
758
  if (strict) {
635
759
  if (!v.workflowId) addIssue({ code: "MISSING_WORKFLOW_ID", severity: "error", message: "Strict mode requires workflowId" });
636
- if (!v.assumptionLevel) addIssue({ code: "MISSING_ASSUMPTION_LEVEL", severity: "error", message: "Strict mode requires assumptionLevel" });
637
- if (!v.executionMode) addIssue({ code: "MISSING_EXECUTION_MODE", severity: "error", message: "Strict mode requires executionMode" });
760
+ if (!v.assumptionLevel && v.schema !== "hardkas.workflow.v1") addIssue({ code: "MISSING_ASSUMPTION_LEVEL", severity: "error", message: "Strict mode requires assumptionLevel" });
761
+ if (!v.executionMode && !v.mode) addIssue({ code: "MISSING_EXECUTION_MODE", severity: "error", message: "Strict mode requires executionMode" });
638
762
  } else {
639
763
  if (!v.workflowId) addIssue({ code: "MISSING_WORKFLOW_ID", severity: "warning", message: "Missing workflowId" });
640
- if (!v.assumptionLevel) addIssue({ code: "MISSING_ASSUMPTION_LEVEL", severity: "warning", message: "Missing assumptionLevel" });
641
- if (!v.executionMode) addIssue({ code: "MISSING_EXECUTION_MODE", severity: "warning", message: "Missing executionMode" });
764
+ if (!v.assumptionLevel && v.schema !== "hardkas.workflow.v1") addIssue({ code: "MISSING_ASSUMPTION_LEVEL", severity: "warning", message: "Missing assumptionLevel" });
765
+ if (!v.executionMode && !v.mode) addIssue({ code: "MISSING_EXECUTION_MODE", severity: "warning", message: "Missing executionMode" });
642
766
  }
643
767
  const networkId = context.networkId || v.networkId;
644
768
  const networkIdStr = networkId;
@@ -800,7 +924,7 @@ var ReplayInvariant = class {
800
924
  };
801
925
 
802
926
  // src/invariants/watcher.ts
803
- import { createEventEnvelope } from "@hardkas/core";
927
+ import { createEventEnvelope, asWorkflowId, asCorrelationId, asNetworkId, asEventSequence } from "@hardkas/core";
804
928
  var InvariantWatcher = class {
805
929
  invariants;
806
930
  eventBus;
@@ -853,9 +977,12 @@ var InvariantWatcher = class {
853
977
  const integrityEvent = createEventEnvelope({
854
978
  kind: "integrity.violation",
855
979
  domain: "integrity",
856
- workflowId: sourceEvent.workflowId,
857
- correlationId: sourceEvent.correlationId,
858
- networkId: sourceEvent.networkId,
980
+ workflowId: asWorkflowId("system-watcher"),
981
+ correlationId: asCorrelationId(sourceEvent.correlationId),
982
+ networkId: asNetworkId(sourceEvent.networkId),
983
+ sequenceNumber: asEventSequence(0),
984
+ // Root event for watcher
985
+ sourceSubsystem: "artifact_watcher",
859
986
  payload: {
860
987
  violationCode: violation.code,
861
988
  severity: violation.severity,
@@ -869,30 +996,148 @@ var InvariantWatcher = class {
869
996
  };
870
997
 
871
998
  // src/migration.ts
872
- function migrateToCanonical(v1Artifact) {
873
- if (v1Artifact.version === ARTIFACT_VERSION) {
874
- return v1Artifact;
999
+ var migrationRegistry = [];
1000
+ function registerMigrationStep(step) {
1001
+ const existing = migrationRegistry.find(
1002
+ (s) => s.fromVersion === step.fromVersion && s.toVersion === step.toVersion
1003
+ );
1004
+ if (existing) {
1005
+ throw new Error(
1006
+ `Duplicate migration step: ${step.fromVersion} \u2192 ${step.toVersion} already registered`
1007
+ );
1008
+ }
1009
+ migrationRegistry.push(step);
1010
+ }
1011
+ function getRegisteredMigrationSteps() {
1012
+ return [...migrationRegistry];
1013
+ }
1014
+ registerMigrationStep({
1015
+ fromVersion: "0.1.0",
1016
+ toVersion: ARTIFACT_VERSION,
1017
+ description: "Legacy v1 schemas to canonical 1.0.0-alpha format",
1018
+ transform(artifact) {
1019
+ const migrated = { ...artifact };
1020
+ if (typeof migrated.schema === "string" && migrated.schema.endsWith(".v1")) {
1021
+ if (migrated.schema !== "hardkas.workflow.v1") {
1022
+ migrated.schema = migrated.schema.replace(/\.v1$/, "");
1023
+ }
1024
+ }
1025
+ migrated.version = ARTIFACT_VERSION;
1026
+ if (migrated.schema === "hardkas.txPlan" && migrated.selectedUtxos !== void 0) {
1027
+ migrated.inputs = migrated.selectedUtxos;
1028
+ delete migrated.selectedUtxos;
1029
+ }
1030
+ if (migrated.schema === "hardkas.snapshot" && Array.isArray(migrated.utxos)) {
1031
+ migrated.utxos = sortUtxosByOutpoint(migrated.utxos);
1032
+ }
1033
+ if (!migrated.hardkasVersion) {
1034
+ migrated.hardkasVersion = HARDKAS_VERSION;
1035
+ }
1036
+ if (!migrated.createdAt) {
1037
+ migrated.createdAt = (/* @__PURE__ */ new Date()).toISOString();
1038
+ }
1039
+ if (migrated.hashVersion === void 0 || migrated.hashVersion === null) {
1040
+ migrated.hashVersion = CURRENT_HASH_VERSION;
1041
+ }
1042
+ return migrated;
875
1043
  }
876
- const v2Artifact = { ...v1Artifact };
877
- if (v1Artifact.schema) {
878
- v2Artifact.schema = v1Artifact.schema.replace(".v1", "");
1044
+ });
1045
+ function detectArtifactVersion(artifact) {
1046
+ if (typeof artifact.version === "string" && artifact.version.length > 0) {
1047
+ return artifact.version;
879
1048
  }
880
- v2Artifact.version = ARTIFACT_VERSION;
881
- if (v2Artifact.schema === "hardkas.txPlan" && v1Artifact.selectedUtxos) {
882
- v2Artifact.inputs = v1Artifact.selectedUtxos;
883
- delete v2Artifact.selectedUtxos;
1049
+ if (typeof artifact.schema === "string" && artifact.schema.endsWith(".v1")) {
1050
+ return "0.1.0";
884
1051
  }
885
- if (v2Artifact.schema === "hardkas.snapshot" && v1Artifact.utxos) {
886
- v2Artifact.utxos = sortUtxosByOutpoint(v1Artifact.utxos);
1052
+ return "0.1.0";
1053
+ }
1054
+ function getMigrationPath(fromVersion, toVersion) {
1055
+ if (fromVersion === toVersion) {
1056
+ return [];
887
1057
  }
888
- if (!v2Artifact.hardkasVersion) {
889
- v2Artifact.hardkasVersion = HARDKAS_VERSION;
1058
+ const visited = /* @__PURE__ */ new Set();
1059
+ const queue = [
1060
+ { version: fromVersion, path: [] }
1061
+ ];
1062
+ visited.add(fromVersion);
1063
+ while (queue.length > 0) {
1064
+ const current = queue.shift();
1065
+ const outgoing = migrationRegistry.filter(
1066
+ (s) => s.fromVersion === current.version
1067
+ );
1068
+ for (const step of outgoing) {
1069
+ const newPath = [...current.path, step];
1070
+ if (step.toVersion === toVersion) {
1071
+ return newPath;
1072
+ }
1073
+ if (!visited.has(step.toVersion)) {
1074
+ visited.add(step.toVersion);
1075
+ queue.push({ version: step.toVersion, path: newPath });
1076
+ }
1077
+ }
890
1078
  }
891
- if (!v2Artifact.createdAt) {
892
- v2Artifact.createdAt = (/* @__PURE__ */ new Date()).toISOString();
1079
+ return [];
1080
+ }
1081
+ function canMigrate(artifact, targetVersion = ARTIFACT_VERSION) {
1082
+ const currentVersion = detectArtifactVersion(artifact);
1083
+ if (currentVersion === targetVersion) {
1084
+ return true;
893
1085
  }
894
- v2Artifact.contentHash = calculateContentHash(v2Artifact);
895
- return v2Artifact;
1086
+ const path4 = getMigrationPath(currentVersion, targetVersion);
1087
+ return path4.length > 0;
1088
+ }
1089
+ function migrateArtifactPayload(artifact, targetVersion = ARTIFACT_VERSION) {
1090
+ const currentVersion = detectArtifactVersion(artifact);
1091
+ if (currentVersion === targetVersion) {
1092
+ return {
1093
+ artifact,
1094
+ migrated: false,
1095
+ originalContentHash: artifact.contentHash,
1096
+ appliedSteps: []
1097
+ };
1098
+ }
1099
+ const path4 = getMigrationPath(currentVersion, targetVersion);
1100
+ if (path4.length === 0) {
1101
+ throw new Error(
1102
+ `No migration path from version "${currentVersion}" to "${targetVersion}". Registered steps: [${migrationRegistry.map((s) => `${s.fromVersion}\u2192${s.toVersion}`).join(", ")}]`
1103
+ );
1104
+ }
1105
+ const originalContentHash = artifact.contentHash;
1106
+ const originalLineage = artifact.lineage;
1107
+ let current = { ...artifact };
1108
+ const appliedSteps = [];
1109
+ for (const step of path4) {
1110
+ current = step.transform(current);
1111
+ appliedSteps.push({
1112
+ fromVersion: step.fromVersion,
1113
+ toVersion: step.toVersion,
1114
+ description: step.description
1115
+ });
1116
+ }
1117
+ if (originalContentHash) {
1118
+ current.originalContentHash = originalContentHash;
1119
+ }
1120
+ if (originalLineage && typeof originalLineage === "object") {
1121
+ const migratedLineage = current.lineage;
1122
+ if (migratedLineage && typeof migratedLineage === "object") {
1123
+ migratedLineage.rootArtifactId = originalLineage.rootArtifactId;
1124
+ }
1125
+ }
1126
+ current.hashVersion = CURRENT_HASH_VERSION;
1127
+ current.contentHash = calculateContentHash(current, CURRENT_HASH_VERSION);
1128
+ return {
1129
+ artifact: current,
1130
+ migrated: true,
1131
+ originalContentHash,
1132
+ appliedSteps
1133
+ };
1134
+ }
1135
+ function migrateToCanonical(v1Artifact) {
1136
+ if (v1Artifact.version === ARTIFACT_VERSION) {
1137
+ return v1Artifact;
1138
+ }
1139
+ const result = migrateArtifactPayload(v1Artifact, ARTIFACT_VERSION);
1140
+ return result.artifact;
896
1141
  }
897
1142
 
898
1143
  // src/io.ts
@@ -968,6 +1213,17 @@ function formatTxPlanArtifact(artifact) {
968
1213
  lines.push(`Outputs: ${artifact.outputs.length}`);
969
1214
  lines.push(`Fee: ${formatSompi(BigInt(artifact.estimatedFeeSompi))}`);
970
1215
  lines.push(`Mass: ${artifact.estimatedMass}`);
1216
+ lines.push("");
1217
+ lines.push("Deterministic Planning Specifications:");
1218
+ lines.push(" Coin Selection:");
1219
+ lines.push(" deterministic canonical ordering enabled");
1220
+ lines.push(" Input Ordering:");
1221
+ lines.push(" amountSompi ASC");
1222
+ lines.push(" txid ASC");
1223
+ lines.push(" index ASC");
1224
+ lines.push(" Output Ordering:");
1225
+ lines.push(" amountSompi ASC");
1226
+ lines.push(" address ASC");
971
1227
  return lines.join("\n");
972
1228
  }
973
1229
  function formatTxReceiptArtifact(artifact) {
@@ -1006,40 +1262,30 @@ function formatSignedTxArtifact(artifact) {
1006
1262
 
1007
1263
  // src/conversions.ts
1008
1264
  function utxoToArtifact(utxo) {
1009
- const artifact = {
1265
+ return {
1010
1266
  outpoint: {
1011
1267
  transactionId: utxo.outpoint.transactionId,
1012
1268
  index: utxo.outpoint.index
1013
1269
  },
1014
1270
  address: utxo.address,
1015
1271
  amountSompi: utxo.amountSompi.toString(),
1016
- scriptPublicKey: utxo.scriptPublicKey
1272
+ scriptPublicKey: utxo.scriptPublicKey,
1273
+ ...utxo.blockDaaScore !== void 0 ? { blockDaaScore: utxo.blockDaaScore.toString() } : {},
1274
+ ...utxo.isCoinbase !== void 0 ? { isCoinbase: utxo.isCoinbase } : {}
1017
1275
  };
1018
- if (utxo.blockDaaScore !== void 0) {
1019
- artifact.blockDaaScore = utxo.blockDaaScore.toString();
1020
- }
1021
- if (utxo.isCoinbase !== void 0) {
1022
- artifact.isCoinbase = utxo.isCoinbase;
1023
- }
1024
- return artifact;
1025
1276
  }
1026
1277
  function utxoFromArtifact(artifact) {
1027
- const utxo = {
1278
+ return {
1028
1279
  outpoint: {
1029
1280
  transactionId: artifact.outpoint.transactionId,
1030
1281
  index: artifact.outpoint.index
1031
1282
  },
1032
1283
  address: artifact.address,
1033
1284
  amountSompi: safeParseBigInt(artifact.amountSompi, "UtxoArtifact.amountSompi"),
1034
- scriptPublicKey: artifact.scriptPublicKey
1285
+ scriptPublicKey: artifact.scriptPublicKey,
1286
+ ...artifact.blockDaaScore !== void 0 ? { blockDaaScore: safeParseBigInt(artifact.blockDaaScore, "UtxoArtifact.blockDaaScore") } : {},
1287
+ ...artifact.isCoinbase !== void 0 ? { isCoinbase: artifact.isCoinbase } : {}
1035
1288
  };
1036
- if (artifact.blockDaaScore !== void 0) {
1037
- utxo.blockDaaScore = safeParseBigInt(artifact.blockDaaScore, "UtxoArtifact.blockDaaScore");
1038
- }
1039
- if (artifact.isCoinbase !== void 0) {
1040
- utxo.isCoinbase = artifact.isCoinbase;
1041
- }
1042
- return utxo;
1043
1289
  }
1044
1290
  function txOutputToArtifact(output) {
1045
1291
  return {
@@ -1068,7 +1314,7 @@ function createTxPlanArtifact(options) {
1068
1314
  hardkasVersion: HARDKAS_VERSION,
1069
1315
  version: ARTIFACT_VERSION,
1070
1316
  hashVersion: CURRENT_HASH_VERSION,
1071
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1317
+ createdAt: new Date(options.ctx.clock.now()).toISOString(),
1072
1318
  networkId: options.networkId,
1073
1319
  mode: options.mode,
1074
1320
  from: {
@@ -1109,13 +1355,13 @@ function createTxPlanArtifact(options) {
1109
1355
  }
1110
1356
 
1111
1357
  // src/signed-tx.ts
1112
- function createSimulatedSignedTxArtifact(plan, payload) {
1358
+ function createSimulatedSignedTxArtifact(plan, payload, ctx) {
1113
1359
  const artifact = {
1114
1360
  schema: "hardkas.signedTx",
1115
1361
  hardkasVersion: HARDKAS_VERSION,
1116
1362
  version: ARTIFACT_VERSION,
1117
1363
  hashVersion: CURRENT_HASH_VERSION,
1118
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1364
+ createdAt: new Date(ctx.clock.now()).toISOString(),
1119
1365
  status: "signed",
1120
1366
  sourcePlanId: plan.planId,
1121
1367
  networkId: plan.networkId,
@@ -1134,13 +1380,13 @@ function createSimulatedSignedTxArtifact(plan, payload) {
1134
1380
  artifact.contentHash = hash;
1135
1381
  return artifact;
1136
1382
  }
1137
- function createSimulatedTxReceipt(plan, txId, extra) {
1383
+ function createSimulatedTxReceipt(plan, txId, ctx, extra) {
1138
1384
  const artifact = {
1139
1385
  schema: "hardkas.txReceipt",
1140
1386
  hardkasVersion: HARDKAS_VERSION,
1141
1387
  version: ARTIFACT_VERSION,
1142
1388
  hashVersion: CURRENT_HASH_VERSION,
1143
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1389
+ createdAt: new Date(ctx.clock.now()).toISOString(),
1144
1390
  txId,
1145
1391
  status: "accepted",
1146
1392
  mode: "simulated",
@@ -1203,7 +1449,8 @@ function validateSignedTxArtifact(value) {
1203
1449
  if (!v.signedTransaction) {
1204
1450
  errors.push("Missing signedTransaction object");
1205
1451
  } else {
1206
- if (!["kaspa-sdk", "hex", "simulated", "unknown"].includes(v.signedTransaction.format)) {
1452
+ const st = v.signedTransaction;
1453
+ if (!["kaspa-sdk", "hex", "simulated", "unknown"].includes(st.format)) {
1207
1454
  errors.push("Invalid signedTransaction.format");
1208
1455
  }
1209
1456
  }
@@ -1265,7 +1512,8 @@ function assertDecimalBigIntString2(value, field, errors) {
1265
1512
  }
1266
1513
 
1267
1514
  // src/explain.ts
1268
- async function explainArtifact(artifact) {
1515
+ async function explainArtifact(artifactUnknown) {
1516
+ const artifact = artifactUnknown;
1269
1517
  const schema = artifact.schema || "unknown";
1270
1518
  const type = schema.split(".")[1] || "unknown";
1271
1519
  const integrity = await verifyArtifactIntegrity(artifact);
@@ -1336,6 +1584,7 @@ async function explainArtifact(artifact) {
1336
1584
  // src/igra-io.ts
1337
1585
  import fs3 from "fs/promises";
1338
1586
  import path2 from "path";
1587
+ import { deterministicCompare as deterministicCompare3 } from "@hardkas/core";
1339
1588
  function getDefaultL2ReceiptsDir(cwd = process.cwd()) {
1340
1589
  return path2.join(cwd, ".hardkas", "l2-receipts");
1341
1590
  }
@@ -1371,7 +1620,7 @@ async function listIgraTxReceiptArtifacts(options) {
1371
1620
  } catch (e) {
1372
1621
  }
1373
1622
  }
1374
- return receipts.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
1623
+ return receipts.sort((a, b) => deterministicCompare3(b.createdAt, a.createdAt));
1375
1624
  } catch (e) {
1376
1625
  if (e.code === "ENOENT") return [];
1377
1626
  throw e;
@@ -1440,7 +1689,7 @@ function isPrimitive(val) {
1440
1689
 
1441
1690
  // src/deployment.ts
1442
1691
  function createDeploymentRecord(opts) {
1443
- const record = {
1692
+ const recordDraft = {
1444
1693
  schema: "hardkas.deployment.v1",
1445
1694
  label: opts.label,
1446
1695
  networkId: opts.networkId,
@@ -1449,28 +1698,33 @@ function createDeploymentRecord(opts) {
1449
1698
  hardkasVersion: HARDKAS_VERSION,
1450
1699
  version: ARTIFACT_VERSION,
1451
1700
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1452
- mode: "real"
1701
+ mode: "real",
1702
+ ...opts.txId ? { txId: opts.txId } : {},
1703
+ ...opts.planArtifactId ? { planArtifactId: opts.planArtifactId } : {},
1704
+ ...opts.receiptArtifactId ? { receiptArtifactId: opts.receiptArtifactId } : {},
1705
+ ...opts.deployedAddresses ? { deployedAddresses: opts.deployedAddresses } : {},
1706
+ ...opts.deployer ? { deployer: opts.deployer } : {},
1707
+ ...opts.payloadHash ? { payloadHash: opts.payloadHash } : {},
1708
+ ...opts.notes ? { notes: opts.notes } : {}
1709
+ };
1710
+ const contentHash = calculateContentHash(recordDraft, CURRENT_HASH_VERSION);
1711
+ return {
1712
+ ...recordDraft,
1713
+ contentHash
1453
1714
  };
1454
- if (opts.txId) record.txId = opts.txId;
1455
- if (opts.planArtifactId) record.planArtifactId = opts.planArtifactId;
1456
- if (opts.receiptArtifactId) record.receiptArtifactId = opts.receiptArtifactId;
1457
- if (opts.deployedAddresses) record.deployedAddresses = opts.deployedAddresses;
1458
- if (opts.deployer) record.deployer = opts.deployer;
1459
- if (opts.payloadHash) record.payloadHash = opts.payloadHash;
1460
- if (opts.notes) record.notes = opts.notes;
1461
- record.contentHash = calculateContentHash(record, CURRENT_HASH_VERSION);
1462
- return record;
1463
1715
  }
1464
1716
  function updateDeploymentStatus(record, newStatus, txId) {
1465
- const updated = {
1717
+ const updatedDraft = {
1466
1718
  ...record,
1467
1719
  status: newStatus,
1468
- deployedAt: (/* @__PURE__ */ new Date()).toISOString()
1720
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
1721
+ ...txId ? { txId } : {}
1722
+ };
1723
+ const contentHash = calculateContentHash(updatedDraft, CURRENT_HASH_VERSION);
1724
+ return {
1725
+ ...updatedDraft,
1726
+ contentHash
1469
1727
  };
1470
- if (txId) updated.txId = txId;
1471
- delete updated.contentHash;
1472
- updated.contentHash = calculateContentHash(updated, CURRENT_HASH_VERSION);
1473
- return updated;
1474
1728
  }
1475
1729
 
1476
1730
  // src/deployment-store.ts
@@ -1562,6 +1816,7 @@ export {
1562
1816
  TxPlanSchema,
1563
1817
  TxReceiptSchema,
1564
1818
  TxTraceSchema,
1819
+ WorkflowSchema,
1565
1820
  assertDecimalBigIntString,
1566
1821
  assertEvmAddress,
1567
1822
  assertEvmTxHash,
@@ -1574,6 +1829,7 @@ export {
1574
1829
  assertValidTxReceiptArtifact,
1575
1830
  bigIntReplacer,
1576
1831
  calculateContentHash,
1832
+ canMigrate,
1577
1833
  canonicalStringify,
1578
1834
  createDeploymentRecord,
1579
1835
  createIgraDeployPlanId,
@@ -1584,6 +1840,7 @@ export {
1584
1840
  createTxPlanArtifact,
1585
1841
  defaultClock,
1586
1842
  deleteDeployment,
1843
+ detectArtifactVersion,
1587
1844
  diffArtifacts,
1588
1845
  explainArtifact,
1589
1846
  formatSignedTxArtifact,
@@ -1593,17 +1850,21 @@ export {
1593
1850
  getDefaultL2ReceiptsDir,
1594
1851
  getDefaultReceiptPath,
1595
1852
  getL2ReceiptPath,
1853
+ getMigrationPath,
1854
+ getRegisteredMigrationSteps,
1596
1855
  isIgraTxPlanArtifact,
1597
1856
  listDeployments,
1598
1857
  listIgraTxReceiptArtifacts,
1599
1858
  loadDeployment,
1600
1859
  loadIgraTxReceiptArtifact,
1860
+ migrateArtifactPayload,
1601
1861
  migrateToCanonical,
1602
1862
  readArtifact,
1603
1863
  readSignedTxArtifact,
1604
1864
  readTxPlanArtifact,
1605
1865
  readTxReceiptArtifact,
1606
1866
  recomputeMass,
1867
+ registerMigrationStep,
1607
1868
  saveDeployment,
1608
1869
  saveIgraTxReceiptArtifact,
1609
1870
  sortUtxosByOutpoint,