@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 +1 -0
- package/dist/index.js +172 -64
- package/package.json +13 -13
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -351,7 +351,8 @@ var HardkasTx = class {
|
|
|
351
351
|
const {
|
|
352
352
|
loadOrCreateLocalnetState,
|
|
353
353
|
saveLocalnetState,
|
|
354
|
-
|
|
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
|
|
365
|
+
const planArtifact = await this.sdk.artifacts.read(signedArtifact.sourcePlanId);
|
|
366
|
+
const simResult = applySimulatedPlan(
|
|
365
367
|
state,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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(
|
|
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
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
-
|
|
599
|
-
let planPath
|
|
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 (
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
998
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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/
|
|
27
|
-
"@hardkas/
|
|
28
|
-
"@hardkas/
|
|
29
|
-
"@hardkas/
|
|
30
|
-
"@hardkas/
|
|
31
|
-
"@hardkas/
|
|
32
|
-
"@hardkas/
|
|
33
|
-
"@hardkas/
|
|
34
|
-
"@hardkas/tx-builder": "0.7.
|
|
35
|
-
"@hardkas/
|
|
36
|
-
"@hardkas/
|
|
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.
|
|
42
|
+
"@hardkas/query-store": "0.7.6-alpha"
|
|
43
43
|
},
|
|
44
44
|
"license": "MIT",
|
|
45
45
|
"author": "Javier Rodriguez",
|