@hardkas/sdk 0.7.9-alpha → 0.7.10-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
@@ -79,10 +79,12 @@ declare class HardkasTx {
79
79
  * Simulates a transaction on the local state without broadcasting to a real Kaspa node.
80
80
  * Modifies the local deterministic state and outputs receipt/trace artifacts.
81
81
  */
82
- simulate(signedArtifact: SignedTxArtifact): Promise<{
82
+ simulate(target: string | Partial<TxPlanArtifact> | SignedTxArtifact, options?: {
83
+ persist?: boolean;
84
+ }): Promise<{
83
85
  receipt: TxReceiptArtifact;
84
- receiptPath: string;
85
- tracePath: string;
86
+ receiptPath?: string;
87
+ tracePath?: string;
86
88
  }>;
87
89
  /**
88
90
  * Sends a signed transaction to the real RPC network.
@@ -295,6 +297,8 @@ declare class HardkasArtifactsManager {
295
297
  schema?: string;
296
298
  artifactId?: string;
297
299
  contentHash?: string;
300
+ }, options?: {
301
+ throwOnInvalid?: boolean;
298
302
  }): Promise<any>;
299
303
  }
300
304
 
package/dist/index.js CHANGED
@@ -405,7 +405,8 @@ var HardkasTx = class {
405
405
  * Simulates a transaction on the local state without broadcasting to a real Kaspa node.
406
406
  * Modifies the local deterministic state and outputs receipt/trace artifacts.
407
407
  */
408
- async simulate(signedArtifact) {
408
+ async simulate(target, options = {}) {
409
+ const persist = options.persist ?? true;
409
410
  const {
410
411
  loadOrCreateLocalnetState,
411
412
  saveLocalnetState,
@@ -420,12 +421,41 @@ var HardkasTx = class {
420
421
  const events = [
421
422
  { type: "phase.started", phase: "send", timestamp: startTime }
422
423
  ];
423
- const planArtifact = await this.sdk.artifacts.read(signedArtifact.sourcePlanId);
424
+ let planArtifact;
425
+ let signedId = "unknown";
426
+ let sourcePlanId = "unknown";
427
+ let txId = `simulated-tx-${Date.now()}`;
428
+ let targetObj = target;
429
+ if (typeof target === "string") {
430
+ try {
431
+ targetObj = await this.sdk.artifacts.read(target);
432
+ } catch (e) {
433
+ throw new Error(`Artifact '${target}' not found. If you already have an in-memory artifact, pass the object directly to tx.simulate(artifact).`);
434
+ }
435
+ }
436
+ if (targetObj.schema === ARTIFACT_SCHEMAS.SIGNED_TX) {
437
+ signedId = targetObj.signedId || targetObj.id || "unknown";
438
+ sourcePlanId = targetObj.sourcePlanId || "unknown";
439
+ txId = targetObj.txId || `simulated-${sourcePlanId}-tx`;
440
+ try {
441
+ planArtifact = await this.sdk.artifacts.read(sourcePlanId);
442
+ } catch (e) {
443
+ throw new Error(`Cannot simulate signed artifact: source plan '${sourcePlanId}' not found in workspace.`);
444
+ }
445
+ } else {
446
+ planArtifact = targetObj;
447
+ sourcePlanId = planArtifact.planId || planArtifact.id || "unknown";
448
+ txId = `simulated-${sourcePlanId}-tx`;
449
+ if (persist && !planArtifact.planId) {
450
+ const savedPlanResult = await this.sdk.artifacts.write(planArtifact);
451
+ sourcePlanId = planArtifact.planId || "unknown";
452
+ }
453
+ }
424
454
  const simResult = applySimulatedPlan(
425
455
  state,
426
456
  planArtifact,
427
457
  systemRuntimeContext,
428
- { txId: signedArtifact.txId || `simulated-${signedArtifact.sourcePlanId}-tx` }
458
+ { txId }
429
459
  );
430
460
  if (!simResult.ok) {
431
461
  throw new Error(`Strict validation failed: ${simResult.errors?.join(", ")}`);
@@ -436,15 +466,18 @@ var HardkasTx = class {
436
466
  endpoint: "simulated://local"
437
467
  });
438
468
  events.push({ type: "phase.completed", phase: "send", timestamp: Date.now() });
439
- await saveLocalnetState(
440
- simResult.state,
441
- getDefaultLocalnetStatePath(this.sdk.workspace.root)
442
- );
443
- const receiptPath = await saveSimulatedReceipt(
444
- simResult.receipt,
445
- { cwd: this.sdk.workspace.root }
446
- );
447
- const tracePath = receiptPath.replace(".json", ".trace.json");
469
+ let receiptPath;
470
+ if (persist) {
471
+ await saveLocalnetState(
472
+ simResult.state,
473
+ getDefaultLocalnetStatePath(this.sdk.workspace.root)
474
+ );
475
+ receiptPath = await saveSimulatedReceipt(
476
+ simResult.receipt,
477
+ { cwd: this.sdk.workspace.root }
478
+ );
479
+ }
480
+ const tracePath = receiptPath ? receiptPath.replace(".json", ".trace.json") : void 0;
448
481
  const activeNetwork = this.sdk.config.config.defaultNetwork || "simnet";
449
482
  const isSimulated = activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated";
450
483
  const receiptBase = {
@@ -458,10 +491,10 @@ var HardkasTx = class {
458
491
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
459
492
  status: "confirmed",
460
493
  txId: simResult.receipt.txId,
461
- sourceSignedId: signedArtifact.signedId,
462
- from: { address: signedArtifact.from.address },
463
- to: { address: signedArtifact.to.address },
464
- amountSompi: signedArtifact.amountSompi,
494
+ sourceSignedId: signedId,
495
+ from: { address: planArtifact.from?.address || "unknown" },
496
+ to: { address: planArtifact.to?.address || "unknown" },
497
+ amountSompi: planArtifact.amountSompi || "0",
465
498
  feeSompi: simResult.receipt.feeSompi?.toString() || "0",
466
499
  changeSompi: simResult.receipt.changeSompi?.toString() || "0",
467
500
  spentUtxoIds: simResult.receipt.spentUtxoIds,
@@ -494,22 +527,26 @@ var HardkasTx = class {
494
527
  steps: traceSteps
495
528
  };
496
529
  traceBase.contentHash = calculateContentHash(traceBase, CURRENT_HASH_VERSION);
497
- await saveSimulatedTrace(
498
- {
499
- ...traceBase,
500
- events,
501
- receiptPath
502
- },
503
- { cwd: this.sdk.workspace.root }
504
- );
505
- coreEvents.normalizeAndEmit({
506
- kind: "artifact.created",
507
- schema: receipt.schema,
508
- artifactId: receipt.txId,
509
- network: receipt.networkId,
510
- mode: receipt.mode,
511
- path: receiptPath
512
- });
530
+ if (persist) {
531
+ await saveSimulatedTrace(
532
+ {
533
+ ...traceBase,
534
+ events,
535
+ receiptPath
536
+ },
537
+ { cwd: this.sdk.workspace.root }
538
+ );
539
+ }
540
+ if (persist) {
541
+ coreEvents.normalizeAndEmit({
542
+ kind: "artifact.created",
543
+ schema: receipt.schema,
544
+ artifactId: receipt.txId,
545
+ network: receipt.networkId,
546
+ mode: receipt.mode,
547
+ path: receiptPath
548
+ });
549
+ }
513
550
  coreEvents.normalizeAndEmit({
514
551
  kind: "tx.confirmed",
515
552
  txId: receipt.txId,
@@ -518,11 +555,10 @@ var HardkasTx = class {
518
555
  amountSompi: receipt.amountSompi,
519
556
  feeSompi: receipt.feeSompi
520
557
  });
521
- return {
522
- receipt,
523
- receiptPath,
524
- tracePath
525
- };
558
+ const result = { receipt };
559
+ if (receiptPath) result.receiptPath = receiptPath;
560
+ if (tracePath) result.tracePath = tracePath;
561
+ return result;
526
562
  }
527
563
  /**
528
564
  * Sends a signed transaction to the real RPC network.
@@ -634,29 +670,48 @@ var HardkasQuery = class {
634
670
  * Synchronizes the query store with the filesystem artifacts.
635
671
  */
636
672
  async sync(options) {
637
- const { HardkasStore, HardkasIndexer } = await import("@hardkas/query-store");
638
- const { withLock } = await import("@hardkas/core");
673
+ const fs4 = await import("fs");
639
674
  const path4 = await import("path");
640
- const dbPath = path4.join(this.sdk.workspace.root, ".hardkas", "store.db");
675
+ const hardkasDir = path4.join(this.sdk.workspace.root, ".hardkas");
676
+ if (!fs4.existsSync(hardkasDir)) {
677
+ throw new Error("Workspace not initialized. Run hardkas init or Hardkas.create({ autoBootstrap:true }).");
678
+ }
679
+ let HardkasStore, HardkasIndexer;
680
+ try {
681
+ const qs = await import("@hardkas/query-store");
682
+ HardkasStore = qs.HardkasStore;
683
+ HardkasIndexer = qs.HardkasIndexer;
684
+ } catch (e) {
685
+ throw new Error("Query store backend unavailable. Install @hardkas/query-store or run query.store.rebuild.");
686
+ }
687
+ const { withLock } = await import("@hardkas/core");
688
+ const dbPath = path4.join(hardkasDir, "store.db");
641
689
  const store = new HardkasStore({ dbPath });
642
690
  let stats;
643
- await withLock(
644
- {
645
- rootDir: this.sdk.workspace.root,
646
- name: "query-store",
647
- command: "query-sync",
648
- wait: true
649
- },
650
- async () => {
651
- store.connect({ autoMigrate: true });
652
- const indexer = new HardkasIndexer(store.getDatabase());
653
- if (options?.force) {
654
- stats = await indexer.rebuild();
655
- } else {
656
- stats = await indexer.sync();
691
+ try {
692
+ await withLock(
693
+ {
694
+ rootDir: this.sdk.workspace.root,
695
+ name: "query-store",
696
+ command: "query-sync",
697
+ wait: true
698
+ },
699
+ async () => {
700
+ store.connect({ autoMigrate: true });
701
+ const indexer = new HardkasIndexer(store.getDatabase());
702
+ if (options?.force) {
703
+ stats = await indexer.rebuild();
704
+ } else {
705
+ stats = await indexer.sync();
706
+ }
657
707
  }
708
+ );
709
+ } catch (e) {
710
+ if (e.message?.includes("SQLITE") || e.message?.includes("Cannot read properties")) {
711
+ throw new Error("Query store database is not configured correctly or corrupted. Try running query.sync({ force: true }).");
658
712
  }
659
- );
713
+ throw e;
714
+ }
660
715
  return stats;
661
716
  }
662
717
  /**
@@ -1224,14 +1279,36 @@ var HardkasArtifactsManager = class {
1224
1279
  * Cryptographically verifies the determinism and integrity of an artifact.
1225
1280
  * Throws an error with details if corruption or mismatch is found.
1226
1281
  */
1227
- async verify(target) {
1282
+ async verify(target, options = {}) {
1283
+ const throwOnInvalid = options.throwOnInvalid ?? true;
1228
1284
  const id = typeof target === "string" ? target : target.artifactId || target.contentHash || "";
1229
- if (!id) throw new Error("No artifact target provided for verification.");
1230
- const artifact = await this.read(id);
1285
+ if (!id) {
1286
+ if (throwOnInvalid) throw new Error("No artifact target provided for verification.");
1287
+ return { valid: false, reason: "unknown", message: "No artifact target provided for verification." };
1288
+ }
1289
+ let artifact;
1290
+ try {
1291
+ artifact = await this.read(id);
1292
+ } catch (e) {
1293
+ if (throwOnInvalid) throw e;
1294
+ return { valid: false, reason: "missing_artifact", message: e.message, artifactId: id };
1295
+ }
1231
1296
  const { verifyArtifactIntegrity: verifyArtifactIntegrity2 } = await import("@hardkas/artifacts");
1232
1297
  const result = await verifyArtifactIntegrity2(artifact);
1233
1298
  if (!result.ok) {
1234
- throw new Error(`Artifact ${id} corrupted or invalid: ` + JSON.stringify(result.issues, null, 2));
1299
+ if (throwOnInvalid) {
1300
+ throw new Error(`Artifact ${id} corrupted or invalid: ` + JSON.stringify(result.issues, null, 2));
1301
+ }
1302
+ return {
1303
+ valid: false,
1304
+ reason: result.issues[0]?.code === "HASH_MISMATCH" ? "hash_mismatch" : result.issues[0]?.code === "MISSING_SIGNATURE" ? "missing_signature" : "schema_invalid",
1305
+ message: result.issues.map((i) => i.message).join(", "),
1306
+ artifactId: id,
1307
+ details: result.issues
1308
+ };
1309
+ }
1310
+ if (!throwOnInvalid) {
1311
+ return { valid: true, artifactId: id, details: result };
1235
1312
  }
1236
1313
  return result;
1237
1314
  }
@@ -1613,7 +1690,12 @@ var Hardkas = class _Hardkas {
1613
1690
  if (options.network) {
1614
1691
  loaded.config.defaultNetwork = options.network;
1615
1692
  }
1616
- return new _Hardkas(loaded, options);
1693
+ let provider;
1694
+ if (isSimulated) {
1695
+ const { LocalnetSimulatedProvider } = await import("@hardkas/localnet");
1696
+ provider = new LocalnetSimulatedProvider(cwd);
1697
+ }
1698
+ return new _Hardkas(loaded, options, provider);
1617
1699
  }
1618
1700
  /**
1619
1701
  * Alias for open(). Used in most examples.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/sdk",
3
- "version": "0.7.9-alpha",
3
+ "version": "0.7.10-alpha",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -23,18 +23,18 @@
23
23
  }
24
24
  },
25
25
  "dependencies": {
26
- "@hardkas/config": "0.7.9-alpha",
27
- "@hardkas/artifacts": "0.7.9-alpha",
28
- "@hardkas/accounts": "0.7.9-alpha",
29
- "@hardkas/core": "0.7.9-alpha",
30
- "@hardkas/kaspa-rpc": "0.7.9-alpha",
31
- "@hardkas/l2": "0.7.9-alpha",
32
- "@hardkas/query": "0.7.9-alpha",
33
- "@hardkas/localnet": "0.7.9-alpha",
34
- "@hardkas/tx-builder": "0.7.9-alpha",
35
- "@hardkas/simulator": "0.7.9-alpha",
36
- "@hardkas/wallet-adapter": "0.7.9-alpha",
37
- "@hardkas/query-store": "0.7.9-alpha"
26
+ "@hardkas/config": "0.7.10-alpha",
27
+ "@hardkas/accounts": "0.7.10-alpha",
28
+ "@hardkas/artifacts": "0.7.10-alpha",
29
+ "@hardkas/l2": "0.7.10-alpha",
30
+ "@hardkas/simulator": "0.7.10-alpha",
31
+ "@hardkas/core": "0.7.10-alpha",
32
+ "@hardkas/localnet": "0.7.10-alpha",
33
+ "@hardkas/kaspa-rpc": "0.7.10-alpha",
34
+ "@hardkas/query": "0.7.10-alpha",
35
+ "@hardkas/tx-builder": "0.7.10-alpha",
36
+ "@hardkas/query-store": "0.7.10-alpha",
37
+ "@hardkas/wallet-adapter": "0.7.10-alpha"
38
38
  },
39
39
  "devDependencies": {
40
40
  "tsup": "^8.3.5",