@hardkas/sdk 0.7.5-alpha → 0.7.7-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 +34 -0
  2. package/dist/index.js +233 -43
  3. package/package.json +13 -13
package/dist/index.d.ts CHANGED
@@ -30,6 +30,24 @@ declare class HardkasAccounts {
30
30
  sompi: bigint;
31
31
  formatted: string;
32
32
  }>;
33
+ /**
34
+ * Alias for getBalance.
35
+ */
36
+ balance(accountNameOrAddress: string): Promise<{
37
+ sompi: bigint;
38
+ formatted: string;
39
+ }>;
40
+ /**
41
+ * Lists all configured account names.
42
+ */
43
+ list(): Promise<string[]>;
44
+ /**
45
+ * Funds an account from another account (defaults to 'default' account).
46
+ */
47
+ fund(accountNameOrAddress: string, options?: {
48
+ from?: string;
49
+ amount?: string | bigint;
50
+ }): Promise<any>;
33
51
  }
34
52
 
35
53
  /**
@@ -73,6 +91,14 @@ declare class HardkasTx {
73
91
  receipt: TxReceiptArtifact;
74
92
  receiptPath: string;
75
93
  }>;
94
+ /**
95
+ * Explicitly appends a signature to a partially signed transaction.
96
+ */
97
+ appendSignature(plan: SignedTxArtifact, account?: HardkasAccount | string): Promise<SignedTxArtifact>;
98
+ /**
99
+ * Fetches the current status of a transaction by ID.
100
+ */
101
+ status(txId: string): Promise<any>;
76
102
  }
77
103
 
78
104
  /**
@@ -217,6 +243,14 @@ declare class HardkasArtifactsManager {
217
243
  * Reads an artifact by path or ID/hash from the workspace.
218
244
  */
219
245
  read(id: string): Promise<any>;
246
+ /**
247
+ * Alias for read().
248
+ */
249
+ get(id: string): Promise<any>;
250
+ /**
251
+ * Lists all artifacts in the workspace.
252
+ */
253
+ list(): Promise<any[]>;
220
254
  }
221
255
 
222
256
  interface WorkflowRunOptions {
package/dist/index.js CHANGED
@@ -40,6 +40,36 @@ var HardkasAccounts = class {
40
40
  formatted: formatSompi(sompi)
41
41
  };
42
42
  }
43
+ /**
44
+ * Alias for getBalance.
45
+ */
46
+ async balance(accountNameOrAddress) {
47
+ return this.getBalance(accountNameOrAddress);
48
+ }
49
+ /**
50
+ * Lists all configured account names.
51
+ */
52
+ async list() {
53
+ return Object.keys(this.sdk.config.config.accounts || {});
54
+ }
55
+ /**
56
+ * Funds an account from another account (defaults to 'default' account).
57
+ */
58
+ async fund(accountNameOrAddress, options) {
59
+ const from = options?.from || "default";
60
+ const amount = options?.amount || "1000000000";
61
+ const plan = await this.sdk.tx.plan({
62
+ from,
63
+ to: accountNameOrAddress,
64
+ amount
65
+ });
66
+ const signed = await this.sdk.tx.sign(plan, from);
67
+ if (this.sdk.network === "simulated") {
68
+ return this.sdk.tx.simulate(signed);
69
+ } else {
70
+ return this.sdk.tx.send(signed);
71
+ }
72
+ }
43
73
  };
44
74
 
45
75
  // src/tx.ts
@@ -78,6 +108,9 @@ var HardkasTx = class {
78
108
  if (!toAccount.address)
79
109
  throw new Error(`To account ${toAccount.name} has no address.`);
80
110
  const amountSompi = typeof options.amount === "string" ? parseKasToSompi(options.amount) : typeof options.amount === "number" ? BigInt(options.amount) : options.amount;
111
+ if (amountSompi === 0n) {
112
+ throw new Error("Kaspa value-transfer outputs require amount > 0.\nFor metadata/notary/DID marker transactions use --amount 1.\nFuture: hardkas tx anchor.");
113
+ }
81
114
  let builderUtxos = [];
82
115
  if (this.sdk.network === "simulated") {
83
116
  const { loadOrCreateLocalnetState, getSpendableUtxos } = await import("@hardkas/localnet");
@@ -160,6 +193,9 @@ var HardkasTx = class {
160
193
  "Cannot append signature to an already completed signed transaction."
161
194
  );
162
195
  }
196
+ if (options?.append === void 0 && plan.status === "partially_signed") {
197
+ options = { ...options, append: true };
198
+ }
163
199
  if (!options?.append) {
164
200
  throw new Error(
165
201
  "Input file is a partially signed transaction. Use the --append flag to add your signature."
@@ -247,7 +283,12 @@ var HardkasTx = class {
247
283
  if (!signerAddress) {
248
284
  throw new Error(`Signer account '${resolvedAccount.name}' has no address.`);
249
285
  }
250
- const requiredSigners = options?.requiredSigners || [signerAddress];
286
+ const requiredSignersList = options?.requiredSigners || [signerAddress];
287
+ const requiredSigners = [];
288
+ for (const r of requiredSignersList) {
289
+ const acc = await this.sdk.accounts.resolve(r);
290
+ requiredSigners.push(acc.address || r);
291
+ }
251
292
  if (!requiredSigners.includes(signerAddress)) {
252
293
  throw new Error(
253
294
  `Signer '${signerAddress}' is not an authorized signer for this transaction.`
@@ -378,7 +419,10 @@ var HardkasTx = class {
378
419
  endpoint: "simulated://local"
379
420
  });
380
421
  events.push({ type: "phase.completed", phase: "send", timestamp: Date.now() });
381
- await saveLocalnetState(simResult.state, getDefaultLocalnetStatePath(this.sdk.workspace.root));
422
+ await saveLocalnetState(
423
+ simResult.state,
424
+ getDefaultLocalnetStatePath(this.sdk.workspace.root)
425
+ );
382
426
  const receiptPath = await saveSimulatedReceipt(
383
427
  simResult.receipt,
384
428
  { cwd: this.sdk.workspace.root }
@@ -431,11 +475,14 @@ var HardkasTx = class {
431
475
  steps: traceSteps
432
476
  };
433
477
  traceBase.contentHash = calculateContentHash(traceBase, CURRENT_HASH_VERSION);
434
- await saveSimulatedTrace({
435
- ...traceBase,
436
- events,
437
- receiptPath
438
- }, { cwd: this.sdk.workspace.root });
478
+ await saveSimulatedTrace(
479
+ {
480
+ ...traceBase,
481
+ events,
482
+ receiptPath
483
+ },
484
+ { cwd: this.sdk.workspace.root }
485
+ );
439
486
  coreEvents.normalizeAndEmit({
440
487
  kind: "artifact.created",
441
488
  schema: receipt.schema,
@@ -508,6 +555,23 @@ var HardkasTx = class {
508
555
  receiptPath
509
556
  };
510
557
  }
558
+ /**
559
+ * Explicitly appends a signature to a partially signed transaction.
560
+ */
561
+ async appendSignature(plan, account) {
562
+ return this.sign(plan, account, { append: true });
563
+ }
564
+ /**
565
+ * Fetches the current status of a transaction by ID.
566
+ */
567
+ async status(txId) {
568
+ const isLocal = txId.startsWith("simulated-");
569
+ if (isLocal) {
570
+ return { status: "simulated_confirmed" };
571
+ }
572
+ const result = await this.sdk.rpc.getTransaction(txId);
573
+ return result;
574
+ }
511
575
  };
512
576
 
513
577
  // src/l2.ts
@@ -588,6 +652,124 @@ import {
588
652
  verifyArtifactIntegrity,
589
653
  writeArtifact as writeArtifact2
590
654
  } from "@hardkas/artifacts";
655
+ function resolveReplayTargets(cwd, options) {
656
+ if (options.path) {
657
+ const fullPath = path.resolve(cwd, options.path);
658
+ if (!fs.existsSync(fullPath)) {
659
+ throw new Error(`Path not found: ${options.path}`);
660
+ }
661
+ if (fs.statSync(fullPath).isFile()) {
662
+ const dir = path.dirname(fullPath);
663
+ let planId = "";
664
+ try {
665
+ const data = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
666
+ planId = data.planId || "";
667
+ } catch {
668
+ }
669
+ let receiptPath = "";
670
+ if (planId) {
671
+ receiptPath = findReceiptByPlanId(dir, planId);
672
+ }
673
+ return {
674
+ planPath: fullPath,
675
+ receiptPath,
676
+ artifactDir: dir,
677
+ source: "explicit-file"
678
+ };
679
+ }
680
+ return resolveFromDirectory(fullPath, "explicit-dir");
681
+ }
682
+ if (options.workflowId) {
683
+ return {
684
+ planPath: path.join(cwd, "tx-plan.json"),
685
+ receiptPath: path.join(cwd, "tx-receipt.json"),
686
+ artifactDir: cwd,
687
+ source: "workflow-id"
688
+ };
689
+ }
690
+ const artifactsDir = path.join(cwd, ".hardkas", "artifacts");
691
+ if (!fs.existsSync(artifactsDir) || !fs.statSync(artifactsDir).isDirectory()) {
692
+ throw new Error(
693
+ `No .hardkas/artifacts/ directory found.
694
+ Hint: Run 'hardkas init' first, then execute a transaction.`
695
+ );
696
+ }
697
+ return resolveFromDirectory(artifactsDir, "artifact-scan");
698
+ }
699
+ function resolveFromDirectory(dir, source) {
700
+ const allFiles = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
701
+ const plans = [];
702
+ const receipts = [];
703
+ for (const f of allFiles) {
704
+ try {
705
+ const raw = fs.readFileSync(path.join(dir, f), "utf-8");
706
+ const data = JSON.parse(raw);
707
+ if (!data || !data.schema) continue;
708
+ if (data.schema === "hardkas.txPlan") {
709
+ plans.push({
710
+ file: f,
711
+ planId: data.planId || "",
712
+ createdAt: data.createdAt || ""
713
+ });
714
+ } else if (data.schema === "hardkas.txReceipt") {
715
+ receipts.push({
716
+ file: f,
717
+ sourcePlanId: data.sourcePlanId || data.lineage?.parentArtifactId || data.lineage?.rootArtifactId || "",
718
+ txId: data.txId || "",
719
+ createdAt: data.createdAt || ""
720
+ });
721
+ }
722
+ } catch {
723
+ }
724
+ }
725
+ if (plans.length === 0) {
726
+ throw new Error(
727
+ `No plan artifacts found in ${dir}.
728
+ Hint: Run a transaction first: hardkas tx send --from alice --to bob --amount 10 --network simulated --yes`
729
+ );
730
+ }
731
+ plans.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
732
+ for (const plan of plans) {
733
+ const matchingReceipt = receipts.find(
734
+ (r) => (
735
+ // Direct sourcePlanId match
736
+ r.sourcePlanId && r.sourcePlanId === plan.planId || // txId derived from planId (e.g., "simulated-plan-xxx-tx" contains "plan-xxx")
737
+ r.txId && plan.planId && r.txId.includes(plan.planId)
738
+ )
739
+ );
740
+ if (matchingReceipt) {
741
+ return {
742
+ planPath: path.join(dir, plan.file),
743
+ receiptPath: path.join(dir, matchingReceipt.file),
744
+ artifactDir: dir,
745
+ source
746
+ };
747
+ }
748
+ }
749
+ const bestPlan = plans[0];
750
+ return {
751
+ planPath: path.join(dir, bestPlan.file),
752
+ receiptPath: "",
753
+ // Will trigger actionable error downstream
754
+ artifactDir: dir,
755
+ source
756
+ };
757
+ }
758
+ function findReceiptByPlanId(dir, planId) {
759
+ if (!fs.existsSync(dir)) return "";
760
+ const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
761
+ for (const f of files) {
762
+ try {
763
+ const raw = fs.readFileSync(path.join(dir, f), "utf-8");
764
+ const data = JSON.parse(raw);
765
+ 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))) {
766
+ return path.join(dir, f);
767
+ }
768
+ } catch {
769
+ }
770
+ }
771
+ return "";
772
+ }
591
773
  var HardkasReplay = class {
592
774
  constructor(sdk) {
593
775
  this.sdk = sdk;
@@ -598,36 +780,8 @@ var HardkasReplay = class {
598
780
  * against the mathematically reconstructed localnet state.
599
781
  */
600
782
  async verify(options) {
601
- let artifactDir = this.sdk.config.cwd;
602
- let planPath = path.join(artifactDir, "tx-plan.json");
603
- let receiptPath = path.join(artifactDir, "tx-receipt.json");
604
- if (options.path) {
605
- const fullPath = path.resolve(this.sdk.config.cwd, options.path);
606
- if (fs.existsSync(fullPath)) {
607
- if (fs.statSync(fullPath).isFile()) {
608
- planPath = fullPath;
609
- artifactDir = path.dirname(fullPath);
610
- receiptPath = fullPath.replace("tx-plan", "tx-receipt");
611
- try {
612
- let content = fs.readFileSync(fullPath, "utf-8");
613
- if (content.charCodeAt(0) === 65279) {
614
- content = content.slice(1);
615
- }
616
- const json = JSON.parse(content);
617
- if (json && json.schema === "hardkas.workflow.v1" && json.workflowId) {
618
- options.workflowId = json.workflowId;
619
- }
620
- } catch (e) {
621
- }
622
- } else {
623
- artifactDir = fullPath;
624
- planPath = path.join(artifactDir, "tx-plan.json");
625
- receiptPath = path.join(artifactDir, "tx-receipt.json");
626
- }
627
- } else {
628
- throw new Error(`Path not found: ${options.path}`);
629
- }
630
- }
783
+ const targets = resolveReplayTargets(this.sdk.config.cwd, options);
784
+ let { planPath, receiptPath, artifactDir } = targets;
631
785
  if (!fs.existsSync(path.join(this.sdk.config.cwd, "hardkas.config.ts"))) {
632
786
  throw new Error(`Workspace not found at ${this.sdk.config.cwd}`);
633
787
  }
@@ -737,12 +891,15 @@ var HardkasReplay = class {
737
891
  lineageOk = false;
738
892
  determinismOk = false;
739
893
  }
740
- } else if (options.path) {
894
+ } else if (targets.source !== "none") {
741
895
  try {
742
896
  if (!fs.existsSync(planPath))
743
897
  throw new Error(`Transaction plan artifact is missing at: ${planPath}`);
744
- if (!fs.existsSync(receiptPath))
745
- throw new Error(`Transaction receipt artifact is missing at: ${receiptPath}`);
898
+ if (!receiptPath || !fs.existsSync(receiptPath))
899
+ throw new Error(
900
+ `No matching receipt artifact found for plan at: ${planPath}
901
+ Hint: Run 'hardkas tx send --from alice --to bob --amount 10 --network simulated --yes' to create a complete plan\u2192sign\u2192send chain.`
902
+ );
746
903
  plan = await readTxPlanArtifact(planPath);
747
904
  receipt = await readTxReceiptArtifact2(receiptPath);
748
905
  } catch (err) {
@@ -920,6 +1077,33 @@ var HardkasArtifactsManager = class {
920
1077
  }
921
1078
  return readArtifact(filePath);
922
1079
  }
1080
+ /**
1081
+ * Alias for read().
1082
+ */
1083
+ async get(id) {
1084
+ return this.read(id);
1085
+ }
1086
+ /**
1087
+ * Lists all artifacts in the workspace.
1088
+ */
1089
+ async list() {
1090
+ if (!fs3.existsSync(this.workspace.artifactsDir)) {
1091
+ return [];
1092
+ }
1093
+ const { readArtifact } = await import("@hardkas/artifacts");
1094
+ const files = fs3.readdirSync(this.workspace.artifactsDir);
1095
+ const artifacts = [];
1096
+ for (const file of files) {
1097
+ if (file.endsWith(".json")) {
1098
+ try {
1099
+ const artifact = await readArtifact(path3.join(this.workspace.artifactsDir, file));
1100
+ artifacts.push(artifact);
1101
+ } catch (e) {
1102
+ }
1103
+ }
1104
+ }
1105
+ return artifacts;
1106
+ }
923
1107
  };
924
1108
 
925
1109
  // src/workflow.ts
@@ -1003,7 +1187,9 @@ var HardkasWorkflow = class {
1003
1187
  },
1004
1188
  sign: async (plan, account) => {
1005
1189
  const signed = await this.sdk.tx.sign(plan, account);
1006
- await this.sdk.artifacts.write(signed, { dryRun: options.dryRun ?? false });
1190
+ await this.sdk.artifacts.write(signed, {
1191
+ dryRun: options.dryRun ?? false
1192
+ });
1007
1193
  const signedRecord = signed;
1008
1194
  const id = signedRecord.contentHash || signedRecord.artifactId || signed.signedId;
1009
1195
  if (id) producedArtifacts.push(id);
@@ -1016,7 +1202,9 @@ var HardkasWorkflow = class {
1016
1202
  "Workflow script requested real broadcast"
1017
1203
  );
1018
1204
  const res = this.sdk.network === "simulated" ? await this.sdk.tx.simulate(signed) : await this.sdk.tx.send(signed);
1019
- await this.sdk.artifacts.write(res.receipt, { dryRun: options.dryRun ?? false });
1205
+ await this.sdk.artifacts.write(res.receipt, {
1206
+ dryRun: options.dryRun ?? false
1207
+ });
1020
1208
  const receiptRecord = res.receipt;
1021
1209
  const id = receiptRecord.contentHash || receiptRecord.artifactId || receiptRecord.txId;
1022
1210
  if (id) producedArtifacts.push(id);
@@ -1024,7 +1212,9 @@ var HardkasWorkflow = class {
1024
1212
  },
1025
1213
  simulate: async (signed) => {
1026
1214
  const res = await this.sdk.tx.simulate(signed);
1027
- await this.sdk.artifacts.write(res.receipt, { dryRun: options.dryRun ?? false });
1215
+ await this.sdk.artifacts.write(res.receipt, {
1216
+ dryRun: options.dryRun ?? false
1217
+ });
1028
1218
  const receiptRecord = res.receipt;
1029
1219
  const id = receiptRecord.contentHash || receiptRecord.artifactId || receiptRecord.txId;
1030
1220
  if (id) producedArtifacts.push(id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/sdk",
3
- "version": "0.7.5-alpha",
3
+ "version": "0.7.7-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.5-alpha",
27
- "@hardkas/artifacts": "0.7.5-alpha",
28
- "@hardkas/l2": "0.7.5-alpha",
29
- "@hardkas/core": "0.7.5-alpha",
30
- "@hardkas/config": "0.7.5-alpha",
31
- "@hardkas/query": "0.7.5-alpha",
32
- "@hardkas/kaspa-rpc": "0.7.5-alpha",
33
- "@hardkas/simulator": "0.7.5-alpha",
34
- "@hardkas/tx-builder": "0.7.5-alpha",
35
- "@hardkas/localnet": "0.7.5-alpha",
36
- "@hardkas/wallet-adapter": "0.7.5-alpha"
26
+ "@hardkas/artifacts": "0.7.7-alpha",
27
+ "@hardkas/accounts": "0.7.7-alpha",
28
+ "@hardkas/core": "0.7.7-alpha",
29
+ "@hardkas/kaspa-rpc": "0.7.7-alpha",
30
+ "@hardkas/localnet": "0.7.7-alpha",
31
+ "@hardkas/query": "0.7.7-alpha",
32
+ "@hardkas/config": "0.7.7-alpha",
33
+ "@hardkas/simulator": "0.7.7-alpha",
34
+ "@hardkas/tx-builder": "0.7.7-alpha",
35
+ "@hardkas/l2": "0.7.7-alpha",
36
+ "@hardkas/wallet-adapter": "0.7.7-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.5-alpha"
42
+ "@hardkas/query-store": "0.7.7-alpha"
43
43
  },
44
44
  "license": "MIT",
45
45
  "author": "Javier Rodriguez",