@hardkas/sdk 0.7.4-alpha → 0.7.6-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.
package/dist/index.d.ts CHANGED
@@ -207,6 +207,7 @@ interface WriteArtifactResult {
207
207
  */
208
208
  declare class HardkasArtifactsManager {
209
209
  private workspace;
210
+ private cache;
210
211
  constructor(workspace: HardkasWorkspace);
211
212
  /**
212
213
  * Writes a valid artifact to disk (canonical or custom path).
package/dist/index.js CHANGED
@@ -351,7 +351,8 @@ var HardkasTx = class {
351
351
  const {
352
352
  loadOrCreateLocalnetState,
353
353
  saveLocalnetState,
354
- applySimulatedPayment,
354
+ getDefaultLocalnetStatePath,
355
+ applySimulatedPlan,
355
356
  saveSimulatedReceipt,
356
357
  saveSimulatedTrace
357
358
  } = await import("@hardkas/localnet");
@@ -361,24 +362,29 @@ var HardkasTx = class {
361
362
  const events = [
362
363
  { type: "phase.started", phase: "send", timestamp: startTime }
363
364
  ];
364
- const simResult = applySimulatedPayment(
365
+ const planArtifact = await this.sdk.artifacts.read(signedArtifact.sourcePlanId);
366
+ const simResult = applySimulatedPlan(
365
367
  state,
366
- {
367
- from: signedArtifact.from.input || signedArtifact.from.address,
368
- to: signedArtifact.to.input || signedArtifact.to.address,
369
- amountSompi: BigInt(signedArtifact.amountSompi)
370
- },
371
- systemRuntimeContext
368
+ planArtifact,
369
+ systemRuntimeContext,
370
+ { txId: signedArtifact.txId || `simulated-${signedArtifact.sourcePlanId}-tx` }
372
371
  );
372
+ if (!simResult.ok) {
373
+ throw new Error(`Strict validation failed: ${simResult.errors?.join(", ")}`);
374
+ }
373
375
  coreEvents.normalizeAndEmit({
374
376
  kind: "workflow.submitted",
375
377
  txId: simResult.receipt.txId,
376
378
  endpoint: "simulated://local"
377
379
  });
378
380
  events.push({ type: "phase.completed", phase: "send", timestamp: Date.now() });
379
- await saveLocalnetState(simResult.state);
381
+ await saveLocalnetState(
382
+ simResult.state,
383
+ getDefaultLocalnetStatePath(this.sdk.workspace.root)
384
+ );
380
385
  const receiptPath = await saveSimulatedReceipt(
381
- simResult.receipt
386
+ simResult.receipt,
387
+ { cwd: this.sdk.workspace.root }
382
388
  );
383
389
  const tracePath = receiptPath.replace(".json", ".trace.json");
384
390
  const receiptBase = {
@@ -428,11 +434,14 @@ var HardkasTx = class {
428
434
  steps: traceSteps
429
435
  };
430
436
  traceBase.contentHash = calculateContentHash(traceBase, CURRENT_HASH_VERSION);
431
- await saveSimulatedTrace({
432
- ...traceBase,
433
- events,
434
- receiptPath
435
- });
437
+ await saveSimulatedTrace(
438
+ {
439
+ ...traceBase,
440
+ events,
441
+ receiptPath
442
+ },
443
+ { cwd: this.sdk.workspace.root }
444
+ );
436
445
  coreEvents.normalizeAndEmit({
437
446
  kind: "artifact.created",
438
447
  schema: receipt.schema,
@@ -585,6 +594,124 @@ import {
585
594
  verifyArtifactIntegrity,
586
595
  writeArtifact as writeArtifact2
587
596
  } from "@hardkas/artifacts";
597
+ function resolveReplayTargets(cwd, options) {
598
+ if (options.path) {
599
+ const fullPath = path.resolve(cwd, options.path);
600
+ if (!fs.existsSync(fullPath)) {
601
+ throw new Error(`Path not found: ${options.path}`);
602
+ }
603
+ if (fs.statSync(fullPath).isFile()) {
604
+ const dir = path.dirname(fullPath);
605
+ let planId = "";
606
+ try {
607
+ const data = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
608
+ planId = data.planId || "";
609
+ } catch {
610
+ }
611
+ let receiptPath = "";
612
+ if (planId) {
613
+ receiptPath = findReceiptByPlanId(dir, planId);
614
+ }
615
+ return {
616
+ planPath: fullPath,
617
+ receiptPath,
618
+ artifactDir: dir,
619
+ source: "explicit-file"
620
+ };
621
+ }
622
+ return resolveFromDirectory(fullPath, "explicit-dir");
623
+ }
624
+ if (options.workflowId) {
625
+ return {
626
+ planPath: path.join(cwd, "tx-plan.json"),
627
+ receiptPath: path.join(cwd, "tx-receipt.json"),
628
+ artifactDir: cwd,
629
+ source: "workflow-id"
630
+ };
631
+ }
632
+ const artifactsDir = path.join(cwd, ".hardkas", "artifacts");
633
+ if (!fs.existsSync(artifactsDir) || !fs.statSync(artifactsDir).isDirectory()) {
634
+ throw new Error(
635
+ `No .hardkas/artifacts/ directory found.
636
+ Hint: Run 'hardkas init' first, then execute a transaction.`
637
+ );
638
+ }
639
+ return resolveFromDirectory(artifactsDir, "artifact-scan");
640
+ }
641
+ function resolveFromDirectory(dir, source) {
642
+ const allFiles = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
643
+ const plans = [];
644
+ const receipts = [];
645
+ for (const f of allFiles) {
646
+ try {
647
+ const raw = fs.readFileSync(path.join(dir, f), "utf-8");
648
+ const data = JSON.parse(raw);
649
+ if (!data || !data.schema) continue;
650
+ if (data.schema === "hardkas.txPlan") {
651
+ plans.push({
652
+ file: f,
653
+ planId: data.planId || "",
654
+ createdAt: data.createdAt || ""
655
+ });
656
+ } else if (data.schema === "hardkas.txReceipt") {
657
+ receipts.push({
658
+ file: f,
659
+ sourcePlanId: data.sourcePlanId || data.lineage?.parentArtifactId || data.lineage?.rootArtifactId || "",
660
+ txId: data.txId || "",
661
+ createdAt: data.createdAt || ""
662
+ });
663
+ }
664
+ } catch {
665
+ }
666
+ }
667
+ if (plans.length === 0) {
668
+ throw new Error(
669
+ `No plan artifacts found in ${dir}.
670
+ Hint: Run a transaction first: hardkas tx send --from alice --to bob --amount 10 --network simulated --yes`
671
+ );
672
+ }
673
+ plans.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
674
+ for (const plan of plans) {
675
+ const matchingReceipt = receipts.find(
676
+ (r) => (
677
+ // Direct sourcePlanId match
678
+ r.sourcePlanId && r.sourcePlanId === plan.planId || // txId derived from planId (e.g., "simulated-plan-xxx-tx" contains "plan-xxx")
679
+ r.txId && plan.planId && r.txId.includes(plan.planId)
680
+ )
681
+ );
682
+ if (matchingReceipt) {
683
+ return {
684
+ planPath: path.join(dir, plan.file),
685
+ receiptPath: path.join(dir, matchingReceipt.file),
686
+ artifactDir: dir,
687
+ source
688
+ };
689
+ }
690
+ }
691
+ const bestPlan = plans[0];
692
+ return {
693
+ planPath: path.join(dir, bestPlan.file),
694
+ receiptPath: "",
695
+ // Will trigger actionable error downstream
696
+ artifactDir: dir,
697
+ source
698
+ };
699
+ }
700
+ function findReceiptByPlanId(dir, planId) {
701
+ if (!fs.existsSync(dir)) return "";
702
+ const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
703
+ for (const f of files) {
704
+ try {
705
+ const raw = fs.readFileSync(path.join(dir, f), "utf-8");
706
+ const data = JSON.parse(raw);
707
+ if (data && data.schema === "hardkas.txReceipt" && (data.sourcePlanId && data.sourcePlanId === planId || data.lineage?.parentArtifactId && data.lineage.parentArtifactId === planId || data.lineage?.rootArtifactId && data.lineage.rootArtifactId === planId || data.txId && data.txId.includes(planId))) {
708
+ return path.join(dir, f);
709
+ }
710
+ } catch {
711
+ }
712
+ }
713
+ return "";
714
+ }
588
715
  var HardkasReplay = class {
589
716
  constructor(sdk) {
590
717
  this.sdk = sdk;
@@ -595,36 +722,8 @@ var HardkasReplay = class {
595
722
  * against the mathematically reconstructed localnet state.
596
723
  */
597
724
  async verify(options) {
598
- let artifactDir = this.sdk.config.cwd;
599
- let planPath = path.join(artifactDir, "tx-plan.json");
600
- let receiptPath = path.join(artifactDir, "tx-receipt.json");
601
- if (options.path) {
602
- const fullPath = path.resolve(this.sdk.config.cwd, options.path);
603
- if (fs.existsSync(fullPath)) {
604
- if (fs.statSync(fullPath).isFile()) {
605
- planPath = fullPath;
606
- artifactDir = path.dirname(fullPath);
607
- receiptPath = fullPath.replace("tx-plan", "tx-receipt");
608
- try {
609
- let content = fs.readFileSync(fullPath, "utf-8");
610
- if (content.charCodeAt(0) === 65279) {
611
- content = content.slice(1);
612
- }
613
- const json = JSON.parse(content);
614
- if (json && json.schema === "hardkas.workflow.v1" && json.workflowId) {
615
- options.workflowId = json.workflowId;
616
- }
617
- } catch (e) {
618
- }
619
- } else {
620
- artifactDir = fullPath;
621
- planPath = path.join(artifactDir, "tx-plan.json");
622
- receiptPath = path.join(artifactDir, "tx-receipt.json");
623
- }
624
- } else {
625
- throw new Error(`Path not found: ${options.path}`);
626
- }
627
- }
725
+ const targets = resolveReplayTargets(this.sdk.config.cwd, options);
726
+ let { planPath, receiptPath, artifactDir } = targets;
628
727
  if (!fs.existsSync(path.join(this.sdk.config.cwd, "hardkas.config.ts"))) {
629
728
  throw new Error(`Workspace not found at ${this.sdk.config.cwd}`);
630
729
  }
@@ -734,12 +833,15 @@ var HardkasReplay = class {
734
833
  lineageOk = false;
735
834
  determinismOk = false;
736
835
  }
737
- } else if (options.path) {
836
+ } else if (targets.source !== "none") {
738
837
  try {
739
838
  if (!fs.existsSync(planPath))
740
839
  throw new Error(`Transaction plan artifact is missing at: ${planPath}`);
741
- if (!fs.existsSync(receiptPath))
742
- throw new Error(`Transaction receipt artifact is missing at: ${receiptPath}`);
840
+ if (!receiptPath || !fs.existsSync(receiptPath))
841
+ throw new Error(
842
+ `No matching receipt artifact found for plan at: ${planPath}
843
+ Hint: Run 'hardkas tx send --from alice --to bob --amount 10 --network simulated --yes' to create a complete plan\u2192sign\u2192send chain.`
844
+ );
743
845
  plan = await readTxPlanArtifact(planPath);
744
846
  receipt = await readTxReceiptArtifact2(receiptPath);
745
847
  } catch (err) {
@@ -830,12 +932,17 @@ var HardkasArtifactsManager = class {
830
932
  this.workspace = workspace;
831
933
  }
832
934
  workspace;
935
+ cache = /* @__PURE__ */ new Map();
833
936
  /**
834
937
  * Writes a valid artifact to disk (canonical or custom path).
835
938
  */
836
939
  async write(artifact, options = {}) {
837
940
  const record = artifact;
838
941
  const hash = record.contentHash || "unknown";
942
+ if (record.planId) this.cache.set(record.planId, artifact);
943
+ if (record.signedId) this.cache.set(record.signedId, artifact);
944
+ if (record.txId) this.cache.set(record.txId, artifact);
945
+ this.cache.set(hash, artifact);
839
946
  if (options.dryRun) {
840
947
  return {
841
948
  dryRun: true,
@@ -889,6 +996,9 @@ var HardkasArtifactsManager = class {
889
996
  * Reads an artifact by path or ID/hash from the workspace.
890
997
  */
891
998
  async read(id) {
999
+ if (this.cache.has(id)) {
1000
+ return this.cache.get(id);
1001
+ }
892
1002
  const { readArtifact } = await import("@hardkas/artifacts");
893
1003
  let filePath = id;
894
1004
  if (!fs3.existsSync(filePath)) {
@@ -983,9 +1093,7 @@ var HardkasWorkflow = class {
983
1093
  );
984
1094
  }
985
1095
  const plan = await this.sdk.tx.plan({ ...opts, workflowId });
986
- if (!options.dryRun) {
987
- await this.sdk.artifacts.write(plan);
988
- }
1096
+ await this.sdk.artifacts.write(plan, { dryRun: options.dryRun ?? false });
989
1097
  const planRecord = plan;
990
1098
  const id = planRecord.contentHash || planRecord.artifactId || plan.planId;
991
1099
  if (id) producedArtifacts.push(id);
@@ -994,9 +1102,9 @@ var HardkasWorkflow = class {
994
1102
  },
995
1103
  sign: async (plan, account) => {
996
1104
  const signed = await this.sdk.tx.sign(plan, account);
997
- if (!options.dryRun) {
998
- await this.sdk.artifacts.write(signed);
999
- }
1105
+ await this.sdk.artifacts.write(signed, {
1106
+ dryRun: options.dryRun ?? false
1107
+ });
1000
1108
  const signedRecord = signed;
1001
1109
  const id = signedRecord.contentHash || signedRecord.artifactId || signed.signedId;
1002
1110
  if (id) producedArtifacts.push(id);
@@ -1009,7 +1117,9 @@ var HardkasWorkflow = class {
1009
1117
  "Workflow script requested real broadcast"
1010
1118
  );
1011
1119
  const res = this.sdk.network === "simulated" ? await this.sdk.tx.simulate(signed) : await this.sdk.tx.send(signed);
1012
- if (!options.dryRun) await this.sdk.artifacts.write(res.receipt);
1120
+ await this.sdk.artifacts.write(res.receipt, {
1121
+ dryRun: options.dryRun ?? false
1122
+ });
1013
1123
  const receiptRecord = res.receipt;
1014
1124
  const id = receiptRecord.contentHash || receiptRecord.artifactId || receiptRecord.txId;
1015
1125
  if (id) producedArtifacts.push(id);
@@ -1017,7 +1127,9 @@ var HardkasWorkflow = class {
1017
1127
  },
1018
1128
  simulate: async (signed) => {
1019
1129
  const res = await this.sdk.tx.simulate(signed);
1020
- if (!options.dryRun) await this.sdk.artifacts.write(res.receipt);
1130
+ await this.sdk.artifacts.write(res.receipt, {
1131
+ dryRun: options.dryRun ?? false
1132
+ });
1021
1133
  const receiptRecord = res.receipt;
1022
1134
  const id = receiptRecord.contentHash || receiptRecord.artifactId || receiptRecord.txId;
1023
1135
  if (id) producedArtifacts.push(id);
@@ -1045,9 +1157,7 @@ var HardkasWorkflow = class {
1045
1157
  amount: step.args?.amount || step.amount,
1046
1158
  workflowId
1047
1159
  });
1048
- if (!options.dryRun) {
1049
- await this.sdk.artifacts.write(lastPlan);
1050
- }
1160
+ await this.sdk.artifacts.write(lastPlan, { dryRun: options.dryRun ?? false });
1051
1161
  const planRecord = lastPlan;
1052
1162
  producedArtifactId = planRecord.contentHash || planRecord.artifactId || lastPlan.planId;
1053
1163
  if (producedArtifactId) producedArtifacts.push(producedArtifactId);
@@ -1062,22 +1172,20 @@ var HardkasWorkflow = class {
1062
1172
  );
1063
1173
  }
1064
1174
  lastSigned = await this.sdk.tx.sign(lastPlan);
1065
- if (!options.dryRun) {
1066
- await this.sdk.artifacts.write(lastSigned);
1067
- }
1175
+ await this.sdk.artifacts.write(lastSigned, { dryRun: options.dryRun ?? false });
1068
1176
  const signedRecord = lastSigned;
1069
1177
  const signedId = signedRecord.contentHash || signedRecord.artifactId || lastSigned.signedId;
1070
1178
  if (signedId) producedArtifacts.push(signedId);
1071
1179
  if (step.type === "tx.simulate") {
1072
1180
  const { receipt } = await this.sdk.tx.simulate(lastSigned);
1073
- if (!options.dryRun) await this.sdk.artifacts.write(receipt);
1181
+ await this.sdk.artifacts.write(receipt, { dryRun: options.dryRun ?? false });
1074
1182
  const receiptRecord = receipt;
1075
1183
  producedArtifactId = receiptRecord.contentHash || receiptRecord.artifactId || receiptRecord.txId;
1076
1184
  if (producedArtifactId) producedArtifacts.push(producedArtifactId);
1077
1185
  result = receipt;
1078
1186
  } else {
1079
1187
  const { receipt } = this.sdk.network === "simulated" ? await this.sdk.tx.simulate(lastSigned) : await this.sdk.tx.send(lastSigned);
1080
- if (!options.dryRun) await this.sdk.artifacts.write(receipt);
1188
+ await this.sdk.artifacts.write(receipt, { dryRun: options.dryRun ?? false });
1081
1189
  const receiptRecord = receipt;
1082
1190
  producedArtifactId = receiptRecord.contentHash || receiptRecord.artifactId || receiptRecord.txId;
1083
1191
  if (producedArtifactId) producedArtifacts.push(producedArtifactId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/sdk",
3
- "version": "0.7.4-alpha",
3
+ "version": "0.7.6-alpha",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -23,23 +23,23 @@
23
23
  }
24
24
  },
25
25
  "dependencies": {
26
- "@hardkas/accounts": "0.7.4-alpha",
27
- "@hardkas/config": "0.7.4-alpha",
28
- "@hardkas/core": "0.7.4-alpha",
29
- "@hardkas/artifacts": "0.7.4-alpha",
30
- "@hardkas/kaspa-rpc": "0.7.4-alpha",
31
- "@hardkas/l2": "0.7.4-alpha",
32
- "@hardkas/simulator": "0.7.4-alpha",
33
- "@hardkas/localnet": "0.7.4-alpha",
34
- "@hardkas/tx-builder": "0.7.4-alpha",
35
- "@hardkas/query": "0.7.4-alpha",
36
- "@hardkas/wallet-adapter": "0.7.4-alpha"
26
+ "@hardkas/config": "0.7.6-alpha",
27
+ "@hardkas/artifacts": "0.7.6-alpha",
28
+ "@hardkas/accounts": "0.7.6-alpha",
29
+ "@hardkas/core": "0.7.6-alpha",
30
+ "@hardkas/l2": "0.7.6-alpha",
31
+ "@hardkas/simulator": "0.7.6-alpha",
32
+ "@hardkas/localnet": "0.7.6-alpha",
33
+ "@hardkas/query": "0.7.6-alpha",
34
+ "@hardkas/tx-builder": "0.7.6-alpha",
35
+ "@hardkas/wallet-adapter": "0.7.6-alpha",
36
+ "@hardkas/kaspa-rpc": "0.7.6-alpha"
37
37
  },
38
38
  "devDependencies": {
39
39
  "tsup": "^8.3.5",
40
40
  "typescript": "^5.7.2",
41
41
  "vitest": "^2.1.8",
42
- "@hardkas/query-store": "0.7.4-alpha"
42
+ "@hardkas/query-store": "0.7.6-alpha"
43
43
  },
44
44
  "license": "MIT",
45
45
  "author": "Javier Rodriguez",