@hardkas/sdk 0.7.7-alpha → 0.7.9-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 +58 -3
- package/dist/index.js +202 -35
- package/package.json +15 -14
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as _hardkas_config from '@hardkas/config';
|
|
|
2
2
|
import { LoadedHardkasConfig } from '@hardkas/config';
|
|
3
3
|
export { defineHardkasConfig } from '@hardkas/config';
|
|
4
4
|
import { KaspaRpcClient } from '@hardkas/kaspa-rpc';
|
|
5
|
-
import { NetworkId } from '@hardkas/core';
|
|
5
|
+
import { EventEnvelope, NetworkId } from '@hardkas/core';
|
|
6
6
|
export { ArtifactId, HardkasError, KaspaAddress, LineageId, NetworkId, SOMPI_PER_KAS, TxId, formatSompi, parseKasToSompi } from '@hardkas/core';
|
|
7
7
|
import { TxPlanArtifact, SignedTxArtifact, TxReceiptArtifact, HardkasArtifactBase, WorkflowArtifact } from '@hardkas/artifacts';
|
|
8
8
|
export { ARTIFACT_SCHEMAS, HARDKAS_VERSION, SignedTxArtifact, TxPlanArtifact, TxReceiptArtifact, TxTraceArtifact, createTxPlanArtifact, writeArtifact } from '@hardkas/artifacts';
|
|
@@ -131,6 +131,21 @@ declare class HardkasQuery {
|
|
|
131
131
|
* Internal lazy-loaded query engine.
|
|
132
132
|
*/
|
|
133
133
|
private getEngine;
|
|
134
|
+
/**
|
|
135
|
+
* Synchronizes the query store with the filesystem artifacts.
|
|
136
|
+
*/
|
|
137
|
+
sync(options?: {
|
|
138
|
+
force?: boolean;
|
|
139
|
+
}): Promise<any>;
|
|
140
|
+
/**
|
|
141
|
+
* Fetches events from the query store.
|
|
142
|
+
*/
|
|
143
|
+
events(filter?: {
|
|
144
|
+
domain?: string;
|
|
145
|
+
kind?: string;
|
|
146
|
+
correlationId?: string;
|
|
147
|
+
artifactId?: string;
|
|
148
|
+
}): Promise<readonly EventEnvelope[]>;
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
/**
|
|
@@ -173,7 +188,28 @@ declare class HardkasReplay {
|
|
|
173
188
|
* Verifies the deterministic artifact lineage of a transaction replay
|
|
174
189
|
* against the mathematically reconstructed localnet state.
|
|
175
190
|
*/
|
|
176
|
-
verify(
|
|
191
|
+
verify(targetOrOptions?: string | {
|
|
192
|
+
schema?: string;
|
|
193
|
+
artifactId?: string;
|
|
194
|
+
} | ReplayVerifyOptions, options?: ReplayVerifyOptions): Promise<ReplayVerifyResult>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* HardKAS Lineage Module
|
|
199
|
+
* @alpha
|
|
200
|
+
*/
|
|
201
|
+
declare class HardkasLineage {
|
|
202
|
+
private sdk;
|
|
203
|
+
constructor(sdk: Hardkas);
|
|
204
|
+
/**
|
|
205
|
+
* Traces the lineage of an artifact, identifying ancestors and descendants.
|
|
206
|
+
*/
|
|
207
|
+
trace(target: string | {
|
|
208
|
+
artifactId?: string;
|
|
209
|
+
contentHash?: string;
|
|
210
|
+
}, options?: {
|
|
211
|
+
direction?: "ancestors" | "descendants";
|
|
212
|
+
}): Promise<any>;
|
|
177
213
|
}
|
|
178
214
|
|
|
179
215
|
/**
|
|
@@ -251,6 +287,15 @@ declare class HardkasArtifactsManager {
|
|
|
251
287
|
* Lists all artifacts in the workspace.
|
|
252
288
|
*/
|
|
253
289
|
list(): Promise<any[]>;
|
|
290
|
+
/**
|
|
291
|
+
* Cryptographically verifies the determinism and integrity of an artifact.
|
|
292
|
+
* Throws an error with details if corruption or mismatch is found.
|
|
293
|
+
*/
|
|
294
|
+
verify(target: string | {
|
|
295
|
+
schema?: string;
|
|
296
|
+
artifactId?: string;
|
|
297
|
+
contentHash?: string;
|
|
298
|
+
}): Promise<any>;
|
|
254
299
|
}
|
|
255
300
|
|
|
256
301
|
interface WorkflowRunOptions {
|
|
@@ -290,6 +335,15 @@ interface HardkasOptions {
|
|
|
290
335
|
cwd?: string;
|
|
291
336
|
configPath?: string;
|
|
292
337
|
mode?: "developer" | "agent";
|
|
338
|
+
network?: string;
|
|
339
|
+
autoBootstrap?: boolean;
|
|
340
|
+
logger?: {
|
|
341
|
+
info: (msg: string) => void;
|
|
342
|
+
warn: (msg: string) => void;
|
|
343
|
+
error: (msg: string) => void;
|
|
344
|
+
debug: (msg: string) => void;
|
|
345
|
+
[key: string]: any;
|
|
346
|
+
};
|
|
293
347
|
policy?: {
|
|
294
348
|
allowNetwork?: boolean;
|
|
295
349
|
allowMainnet?: boolean;
|
|
@@ -313,6 +367,7 @@ declare class Hardkas {
|
|
|
313
367
|
readonly query: HardkasQuery;
|
|
314
368
|
readonly localnet: HardkasLocalnet;
|
|
315
369
|
readonly replay: HardkasReplay;
|
|
370
|
+
readonly lineage: HardkasLineage;
|
|
316
371
|
readonly workflow: HardkasWorkflow;
|
|
317
372
|
readonly mode: "developer" | "agent";
|
|
318
373
|
readonly policy: Required<NonNullable<HardkasOptions["policy"]>>;
|
|
@@ -340,4 +395,4 @@ declare class Hardkas {
|
|
|
340
395
|
enforcePolicy(action: "network" | "mainnet" | "external-wallet" | "mutation", context?: string): void;
|
|
341
396
|
}
|
|
342
397
|
|
|
343
|
-
export { Hardkas, HardkasAccounts, HardkasArtifactsManager, HardkasL2, HardkasLocalnet, type HardkasOptions, HardkasQuery, HardkasReplay, HardkasTx, HardkasWorkspace, type TaskArgs, type TaskContext, defineTask };
|
|
398
|
+
export { Hardkas, HardkasAccounts, HardkasArtifactsManager, HardkasL2, HardkasLineage, HardkasLocalnet, type HardkasOptions, HardkasQuery, HardkasReplay, HardkasTx, HardkasWorkspace, type TaskArgs, type TaskContext, defineTask };
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
loadHardkasConfig as loadConfig
|
|
8
8
|
} from "@hardkas/config";
|
|
9
9
|
import { JsonWrpcKaspaClient } from "@hardkas/kaspa-rpc";
|
|
10
|
-
import { HardkasError as
|
|
10
|
+
import { HardkasError as HardkasError3 } from "@hardkas/core";
|
|
11
11
|
|
|
12
12
|
// src/accounts.ts
|
|
13
13
|
import { resolveHardkasAccount } from "@hardkas/accounts";
|
|
@@ -56,8 +56,23 @@ var HardkasAccounts = class {
|
|
|
56
56
|
* Funds an account from another account (defaults to 'default' account).
|
|
57
57
|
*/
|
|
58
58
|
async fund(accountNameOrAddress, options) {
|
|
59
|
-
|
|
59
|
+
let from = options?.from;
|
|
60
60
|
const amount = options?.amount || "1000000000";
|
|
61
|
+
if (!from) {
|
|
62
|
+
const accounts = await this.list();
|
|
63
|
+
if (accounts.includes("faucet")) {
|
|
64
|
+
from = "faucet";
|
|
65
|
+
} else if (accounts.includes("simulated_faucet")) {
|
|
66
|
+
from = "simulated_faucet";
|
|
67
|
+
} else if (this.sdk.network === "simulated" && accounts.includes("alice")) {
|
|
68
|
+
from = "alice";
|
|
69
|
+
} else {
|
|
70
|
+
throw new Error("No funding account available.\nFor simulated mode, run Hardkas.create({ network: 'simulated', autoBootstrap: true })\nor call accounts.fund(target, { from: 'alice' }).");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (from === accountNameOrAddress) {
|
|
74
|
+
throw new Error(`Cannot fund account '${accountNameOrAddress}' from itself.`);
|
|
75
|
+
}
|
|
61
76
|
const plan = await this.sdk.tx.plan({
|
|
62
77
|
from,
|
|
63
78
|
to: accountNameOrAddress,
|
|
@@ -73,7 +88,7 @@ var HardkasAccounts = class {
|
|
|
73
88
|
};
|
|
74
89
|
|
|
75
90
|
// src/tx.ts
|
|
76
|
-
import { systemRuntimeContext } from "@hardkas/core";
|
|
91
|
+
import { systemRuntimeContext, deterministicCompare } from "@hardkas/core";
|
|
77
92
|
import {
|
|
78
93
|
buildPaymentPlan,
|
|
79
94
|
verifySignedTxSemantics
|
|
@@ -112,7 +127,8 @@ var HardkasTx = class {
|
|
|
112
127
|
throw new Error("Kaspa value-transfer outputs require amount > 0.\nFor metadata/notary/DID marker transactions use --amount 1.\nFuture: hardkas tx anchor.");
|
|
113
128
|
}
|
|
114
129
|
let builderUtxos = [];
|
|
115
|
-
|
|
130
|
+
const activeNetwork = this.sdk.config.config.defaultNetwork || "simnet";
|
|
131
|
+
if (activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated") {
|
|
116
132
|
const { loadOrCreateLocalnetState, getSpendableUtxos } = await import("@hardkas/localnet");
|
|
117
133
|
const localState = await loadOrCreateLocalnetState({
|
|
118
134
|
cwd: this.sdk.workspace.root
|
|
@@ -152,9 +168,10 @@ var HardkasTx = class {
|
|
|
152
168
|
],
|
|
153
169
|
feeRateSompiPerMass: options.feeRate ?? 1n
|
|
154
170
|
});
|
|
171
|
+
const isSimulated = activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated";
|
|
155
172
|
return createTxPlanArtifact({
|
|
156
|
-
networkId:
|
|
157
|
-
mode: "simulated",
|
|
173
|
+
networkId: activeNetwork,
|
|
174
|
+
mode: isSimulated ? "simulated" : "real",
|
|
158
175
|
from: {
|
|
159
176
|
input: fromAccount.name || fromAccount.address,
|
|
160
177
|
address: fromAccount.address,
|
|
@@ -228,7 +245,7 @@ var HardkasTx = class {
|
|
|
228
245
|
signature: `simulated-signature-of-${signerAddress}`
|
|
229
246
|
};
|
|
230
247
|
const newSignatures = [...sigs, signatureEntry].sort(
|
|
231
|
-
(a, b) => a.signer
|
|
248
|
+
(a, b) => deterministicCompare(a.signer, b.signer)
|
|
232
249
|
);
|
|
233
250
|
const newMeta = [
|
|
234
251
|
...partialTx.signatureMetadata || [],
|
|
@@ -299,7 +316,7 @@ var HardkasTx = class {
|
|
|
299
316
|
signature: `simulated-signature-of-${signerAddress}`
|
|
300
317
|
};
|
|
301
318
|
const signatures = [signatureEntry].sort(
|
|
302
|
-
(a, b) => a.signer
|
|
319
|
+
(a, b) => deterministicCompare(a.signer, b.signer)
|
|
303
320
|
);
|
|
304
321
|
const signatureMetadata = [
|
|
305
322
|
{
|
|
@@ -428,14 +445,16 @@ var HardkasTx = class {
|
|
|
428
445
|
{ cwd: this.sdk.workspace.root }
|
|
429
446
|
);
|
|
430
447
|
const tracePath = receiptPath.replace(".json", ".trace.json");
|
|
448
|
+
const activeNetwork = this.sdk.config.config.defaultNetwork || "simnet";
|
|
449
|
+
const isSimulated = activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated";
|
|
431
450
|
const receiptBase = {
|
|
432
451
|
schema: ARTIFACT_SCHEMAS.TX_RECEIPT,
|
|
433
452
|
schemaVersion: "hardkas.receipt.v1",
|
|
434
453
|
hardkasVersion: HARDKAS_VERSION,
|
|
435
454
|
version: ARTIFACT_VERSION,
|
|
436
455
|
hashVersion: CURRENT_HASH_VERSION,
|
|
437
|
-
networkId:
|
|
438
|
-
mode: "simulated",
|
|
456
|
+
networkId: activeNetwork,
|
|
457
|
+
mode: isSimulated ? "simulated" : "real",
|
|
439
458
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
440
459
|
status: "confirmed",
|
|
441
460
|
txId: simResult.receipt.txId,
|
|
@@ -470,8 +489,8 @@ var HardkasTx = class {
|
|
|
470
489
|
hashVersion: CURRENT_HASH_VERSION,
|
|
471
490
|
createdAt: receipt.createdAt,
|
|
472
491
|
txId: receipt.txId,
|
|
473
|
-
mode: "simulated",
|
|
474
|
-
networkId:
|
|
492
|
+
mode: isSimulated ? "simulated" : "real",
|
|
493
|
+
networkId: activeNetwork,
|
|
475
494
|
steps: traceSteps
|
|
476
495
|
};
|
|
477
496
|
traceBase.contentHash = calculateContentHash(traceBase, CURRENT_HASH_VERSION);
|
|
@@ -604,11 +623,62 @@ var HardkasQuery = class {
|
|
|
604
623
|
async getEngine() {
|
|
605
624
|
if (this._engine) return this._engine;
|
|
606
625
|
const { QueryEngine } = await import("@hardkas/query");
|
|
607
|
-
this._engine =
|
|
608
|
-
artifactDir: this.sdk.
|
|
626
|
+
this._engine = await QueryEngine.create({
|
|
627
|
+
artifactDir: this.sdk.workspace.root,
|
|
628
|
+
autoSync: false
|
|
629
|
+
// We don't auto-sync on every getter
|
|
609
630
|
});
|
|
610
631
|
return this._engine;
|
|
611
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* Synchronizes the query store with the filesystem artifacts.
|
|
635
|
+
*/
|
|
636
|
+
async sync(options) {
|
|
637
|
+
const { HardkasStore, HardkasIndexer } = await import("@hardkas/query-store");
|
|
638
|
+
const { withLock } = await import("@hardkas/core");
|
|
639
|
+
const path4 = await import("path");
|
|
640
|
+
const dbPath = path4.join(this.sdk.workspace.root, ".hardkas", "store.db");
|
|
641
|
+
const store = new HardkasStore({ dbPath });
|
|
642
|
+
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();
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
);
|
|
660
|
+
return stats;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Fetches events from the query store.
|
|
664
|
+
*/
|
|
665
|
+
async events(filter) {
|
|
666
|
+
const engine = await this.getEngine();
|
|
667
|
+
const { createQueryRequest } = await import("@hardkas/query");
|
|
668
|
+
const filters = [];
|
|
669
|
+
if (filter) {
|
|
670
|
+
for (const [k, v] of Object.entries(filter)) {
|
|
671
|
+
if (v) filters.push({ field: k, op: "eq", value: v });
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
const request = createQueryRequest({
|
|
675
|
+
domain: "events",
|
|
676
|
+
op: "list",
|
|
677
|
+
filters
|
|
678
|
+
});
|
|
679
|
+
const result = await engine.execute(request);
|
|
680
|
+
return result.items;
|
|
681
|
+
}
|
|
612
682
|
};
|
|
613
683
|
|
|
614
684
|
// src/localnet.ts
|
|
@@ -652,6 +722,7 @@ import {
|
|
|
652
722
|
verifyArtifactIntegrity,
|
|
653
723
|
writeArtifact as writeArtifact2
|
|
654
724
|
} from "@hardkas/artifacts";
|
|
725
|
+
import { deterministicCompare as deterministicCompare2 } from "@hardkas/core";
|
|
655
726
|
function resolveReplayTargets(cwd, options) {
|
|
656
727
|
if (options.path) {
|
|
657
728
|
const fullPath = path.resolve(cwd, options.path);
|
|
@@ -728,7 +799,7 @@ function resolveFromDirectory(dir, source) {
|
|
|
728
799
|
Hint: Run a transaction first: hardkas tx send --from alice --to bob --amount 10 --network simulated --yes`
|
|
729
800
|
);
|
|
730
801
|
}
|
|
731
|
-
plans.sort((a, b) => b.createdAt
|
|
802
|
+
plans.sort((a, b) => deterministicCompare2(b.createdAt, a.createdAt));
|
|
732
803
|
for (const plan of plans) {
|
|
733
804
|
const matchingReceipt = receipts.find(
|
|
734
805
|
(r) => (
|
|
@@ -779,16 +850,24 @@ var HardkasReplay = class {
|
|
|
779
850
|
* Verifies the deterministic artifact lineage of a transaction replay
|
|
780
851
|
* against the mathematically reconstructed localnet state.
|
|
781
852
|
*/
|
|
782
|
-
async verify(options) {
|
|
783
|
-
|
|
853
|
+
async verify(targetOrOptions, options) {
|
|
854
|
+
let opts = options || {};
|
|
855
|
+
if (typeof targetOrOptions === "string") {
|
|
856
|
+
opts.path = targetOrOptions;
|
|
857
|
+
} else if (targetOrOptions && "artifactId" in targetOrOptions) {
|
|
858
|
+
opts.path = targetOrOptions.artifactId;
|
|
859
|
+
} else if (targetOrOptions) {
|
|
860
|
+
opts = { ...opts, ...targetOrOptions };
|
|
861
|
+
}
|
|
862
|
+
const targets = resolveReplayTargets(this.sdk.config.cwd, opts);
|
|
784
863
|
let { planPath, receiptPath, artifactDir } = targets;
|
|
785
864
|
if (!fs.existsSync(path.join(this.sdk.config.cwd, "hardkas.config.ts"))) {
|
|
786
865
|
throw new Error(`Workspace not found at ${this.sdk.config.cwd}`);
|
|
787
866
|
}
|
|
788
867
|
const canonicalDirs = [
|
|
789
|
-
path.join(
|
|
790
|
-
path.join(
|
|
791
|
-
path.join(
|
|
868
|
+
path.join(this.sdk.workspace.hardkasDir, "receipts"),
|
|
869
|
+
path.join(this.sdk.workspace.hardkasDir, "traces"),
|
|
870
|
+
path.join(this.sdk.workspace.hardkasDir, "deployments")
|
|
792
871
|
];
|
|
793
872
|
const files = [];
|
|
794
873
|
for (const dir of canonicalDirs) {
|
|
@@ -851,9 +930,9 @@ var HardkasReplay = class {
|
|
|
851
930
|
let receipt;
|
|
852
931
|
let verifyErrorMsg;
|
|
853
932
|
let report = null;
|
|
854
|
-
if (
|
|
933
|
+
if (opts.workflowId) {
|
|
855
934
|
try {
|
|
856
|
-
const wfArtifactPath = fs.readdirSync(this.sdk.workspace.artifactsDir).find((f) => f.includes(
|
|
935
|
+
const wfArtifactPath = fs.readdirSync(this.sdk.workspace.artifactsDir).find((f) => f.includes(opts.workflowId) && f.endsWith(".json"));
|
|
857
936
|
if (!wfArtifactPath) throw new Error("Workflow artifact not found");
|
|
858
937
|
const wfArtifactStr = fs.readFileSync(
|
|
859
938
|
path.join(this.sdk.workspace.artifactsDir, wfArtifactPath),
|
|
@@ -861,7 +940,7 @@ var HardkasReplay = class {
|
|
|
861
940
|
);
|
|
862
941
|
const wfArtifact = JSON.parse(wfArtifactStr);
|
|
863
942
|
if (wfArtifact.schema !== "hardkas.workflow.v1") {
|
|
864
|
-
throw new Error(`Artifact ${
|
|
943
|
+
throw new Error(`Artifact ${opts.workflowId} is not a workflow artifact`);
|
|
865
944
|
}
|
|
866
945
|
const childArtifacts = wfArtifact.producedArtifacts || [];
|
|
867
946
|
for (const childId of childArtifacts) {
|
|
@@ -940,6 +1019,33 @@ var HardkasReplay = class {
|
|
|
940
1019
|
}
|
|
941
1020
|
};
|
|
942
1021
|
|
|
1022
|
+
// src/lineage.ts
|
|
1023
|
+
var HardkasLineage = class {
|
|
1024
|
+
constructor(sdk) {
|
|
1025
|
+
this.sdk = sdk;
|
|
1026
|
+
}
|
|
1027
|
+
sdk;
|
|
1028
|
+
/**
|
|
1029
|
+
* Traces the lineage of an artifact, identifying ancestors and descendants.
|
|
1030
|
+
*/
|
|
1031
|
+
async trace(target, options) {
|
|
1032
|
+
const anchor = typeof target === "string" ? target : target.artifactId || target.contentHash || "";
|
|
1033
|
+
if (!anchor) throw new Error("No anchor target provided for lineage trace.");
|
|
1034
|
+
const { createQueryRequest, QueryEngine } = await import("@hardkas/query");
|
|
1035
|
+
const engine = await QueryEngine.create({
|
|
1036
|
+
artifactDir: this.sdk.workspace.root,
|
|
1037
|
+
autoSync: false
|
|
1038
|
+
});
|
|
1039
|
+
const request = createQueryRequest({
|
|
1040
|
+
domain: "lineage",
|
|
1041
|
+
op: "chain",
|
|
1042
|
+
params: { anchor, direction: options?.direction || "ancestors" }
|
|
1043
|
+
});
|
|
1044
|
+
const result = await engine.execute(request);
|
|
1045
|
+
return result.items[0];
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
|
|
943
1049
|
// src/workspace.ts
|
|
944
1050
|
import path2 from "path";
|
|
945
1051
|
import fs2 from "fs";
|
|
@@ -955,7 +1061,7 @@ var HardkasWorkspace = class {
|
|
|
955
1061
|
return path2.join(this.hardkasDir, "artifacts");
|
|
956
1062
|
}
|
|
957
1063
|
get localnetStatePath() {
|
|
958
|
-
return path2.join(this.hardkasDir, "localnet
|
|
1064
|
+
return path2.join(this.hardkasDir, "localnet.json");
|
|
959
1065
|
}
|
|
960
1066
|
get keystoreDir() {
|
|
961
1067
|
return path2.join(this.hardkasDir, "keystore");
|
|
@@ -985,6 +1091,7 @@ var HardkasWorkspace = class {
|
|
|
985
1091
|
// src/artifacts-manager.ts
|
|
986
1092
|
import path3 from "path";
|
|
987
1093
|
import fs3 from "fs";
|
|
1094
|
+
import { HardkasError } from "@hardkas/core";
|
|
988
1095
|
var HardkasArtifactsManager = class {
|
|
989
1096
|
constructor(workspace) {
|
|
990
1097
|
this.workspace = workspace;
|
|
@@ -1059,6 +1166,15 @@ var HardkasArtifactsManager = class {
|
|
|
1059
1166
|
}
|
|
1060
1167
|
const { readArtifact } = await import("@hardkas/artifacts");
|
|
1061
1168
|
let filePath = id;
|
|
1169
|
+
let resolvedPath = path3.resolve(this.workspace.root, filePath);
|
|
1170
|
+
if (fs3.existsSync(resolvedPath)) {
|
|
1171
|
+
resolvedPath = fs3.realpathSync(resolvedPath);
|
|
1172
|
+
}
|
|
1173
|
+
const rootRel = path3.relative(this.workspace.root, resolvedPath);
|
|
1174
|
+
const artifactsRel = path3.relative(this.workspace.artifactsDir, resolvedPath);
|
|
1175
|
+
if ((rootRel.startsWith("..") || path3.isAbsolute(rootRel)) && (artifactsRel.startsWith("..") || path3.isAbsolute(artifactsRel))) {
|
|
1176
|
+
throw new HardkasError("PATH_TRAVERSAL", "Artifact path escapes workspace boundary");
|
|
1177
|
+
}
|
|
1062
1178
|
if (!fs3.existsSync(filePath)) {
|
|
1063
1179
|
filePath = path3.join(this.workspace.artifactsDir, `${id}.json`);
|
|
1064
1180
|
if (!fs3.existsSync(filePath)) {
|
|
@@ -1104,11 +1220,26 @@ var HardkasArtifactsManager = class {
|
|
|
1104
1220
|
}
|
|
1105
1221
|
return artifacts;
|
|
1106
1222
|
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Cryptographically verifies the determinism and integrity of an artifact.
|
|
1225
|
+
* Throws an error with details if corruption or mismatch is found.
|
|
1226
|
+
*/
|
|
1227
|
+
async verify(target) {
|
|
1228
|
+
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);
|
|
1231
|
+
const { verifyArtifactIntegrity: verifyArtifactIntegrity2 } = await import("@hardkas/artifacts");
|
|
1232
|
+
const result = await verifyArtifactIntegrity2(artifact);
|
|
1233
|
+
if (!result.ok) {
|
|
1234
|
+
throw new Error(`Artifact ${id} corrupted or invalid: ` + JSON.stringify(result.issues, null, 2));
|
|
1235
|
+
}
|
|
1236
|
+
return result;
|
|
1237
|
+
}
|
|
1107
1238
|
};
|
|
1108
1239
|
|
|
1109
1240
|
// src/workflow.ts
|
|
1110
1241
|
import { HARDKAS_VERSION as HARDKAS_VERSION2 } from "@hardkas/artifacts";
|
|
1111
|
-
import { HardkasError, deterministicCompare } from "@hardkas/core";
|
|
1242
|
+
import { HardkasError as HardkasError2, deterministicCompare as deterministicCompare3 } from "@hardkas/core";
|
|
1112
1243
|
var HardkasWorkflow = class {
|
|
1113
1244
|
constructor(sdk) {
|
|
1114
1245
|
this.sdk = sdk;
|
|
@@ -1155,12 +1286,12 @@ var HardkasWorkflow = class {
|
|
|
1155
1286
|
try {
|
|
1156
1287
|
if (step.type === "simulate-failure") {
|
|
1157
1288
|
if (this.sdk.mode === "agent") {
|
|
1158
|
-
throw new
|
|
1289
|
+
throw new HardkasError2(
|
|
1159
1290
|
"POLICY_DENIED",
|
|
1160
1291
|
"simulate-failure is strictly prohibited in agent mode"
|
|
1161
1292
|
);
|
|
1162
1293
|
}
|
|
1163
|
-
throw new
|
|
1294
|
+
throw new HardkasError2("MOCKED_FAIL", "Simulated failure for contract tests");
|
|
1164
1295
|
}
|
|
1165
1296
|
let producedArtifactId = void 0;
|
|
1166
1297
|
let result = void 0;
|
|
@@ -1321,9 +1452,9 @@ var HardkasWorkflow = class {
|
|
|
1321
1452
|
artifactId: workflowId,
|
|
1322
1453
|
status,
|
|
1323
1454
|
steps: artifactSteps,
|
|
1324
|
-
parentArtifacts: parentArtifacts.sort(
|
|
1455
|
+
parentArtifacts: parentArtifacts.sort(deterministicCompare3),
|
|
1325
1456
|
producedArtifacts: Array.from(new Set(producedArtifacts)).sort(
|
|
1326
|
-
|
|
1457
|
+
deterministicCompare3
|
|
1327
1458
|
),
|
|
1328
1459
|
generationRange: {
|
|
1329
1460
|
start: generationStart,
|
|
@@ -1393,7 +1524,7 @@ import {
|
|
|
1393
1524
|
} from "@hardkas/artifacts";
|
|
1394
1525
|
import {
|
|
1395
1526
|
SOMPI_PER_KAS,
|
|
1396
|
-
HardkasError as
|
|
1527
|
+
HardkasError as HardkasError4,
|
|
1397
1528
|
parseKasToSompi as parseKasToSompi2,
|
|
1398
1529
|
formatSompi as formatSompi2
|
|
1399
1530
|
} from "@hardkas/core";
|
|
@@ -1418,6 +1549,7 @@ var Hardkas = class _Hardkas {
|
|
|
1418
1549
|
this.query = new HardkasQuery(this);
|
|
1419
1550
|
this.localnet = new HardkasLocalnet(this);
|
|
1420
1551
|
this.replay = new HardkasReplay(this);
|
|
1552
|
+
this.lineage = new HardkasLineage(this);
|
|
1421
1553
|
this.workflow = new HardkasWorkflow(this);
|
|
1422
1554
|
}
|
|
1423
1555
|
config;
|
|
@@ -1429,6 +1561,7 @@ var Hardkas = class _Hardkas {
|
|
|
1429
1561
|
query;
|
|
1430
1562
|
localnet;
|
|
1431
1563
|
replay;
|
|
1564
|
+
lineage;
|
|
1432
1565
|
workflow;
|
|
1433
1566
|
mode;
|
|
1434
1567
|
policy;
|
|
@@ -1447,6 +1580,39 @@ var Hardkas = class _Hardkas {
|
|
|
1447
1580
|
static async open(dirOrOptions = ".") {
|
|
1448
1581
|
const options = typeof dirOrOptions === "string" ? { cwd: dirOrOptions } : dirOrOptions;
|
|
1449
1582
|
const loaded = await loadConfig(options);
|
|
1583
|
+
const activeNetwork = options.network || loaded.config.defaultNetwork || "simnet";
|
|
1584
|
+
const isSimulated = activeNetwork === "simulated" || loaded.config.networks?.[activeNetwork]?.kind === "simulated";
|
|
1585
|
+
const autoBootstrap = options.autoBootstrap ?? (isSimulated ? true : false);
|
|
1586
|
+
const fs4 = await import("fs");
|
|
1587
|
+
const path4 = await import("path");
|
|
1588
|
+
const cwd = options.cwd || process.cwd();
|
|
1589
|
+
const hardkasDir = path4.join(cwd, ".hardkas");
|
|
1590
|
+
if (autoBootstrap) {
|
|
1591
|
+
if (!isSimulated) {
|
|
1592
|
+
if (options.logger) {
|
|
1593
|
+
options.logger.warn("[HardKAS] autoBootstrap ignored for non-simulated network");
|
|
1594
|
+
}
|
|
1595
|
+
} else {
|
|
1596
|
+
if (!fs4.existsSync(hardkasDir)) {
|
|
1597
|
+
if (options.logger) {
|
|
1598
|
+
options.logger.info("[HardKAS] Auto-bootstrapping simulated workspace");
|
|
1599
|
+
}
|
|
1600
|
+
fs4.mkdirSync(hardkasDir, { recursive: true });
|
|
1601
|
+
}
|
|
1602
|
+
try {
|
|
1603
|
+
const { loadOrCreateLocalnetState } = await import("@hardkas/localnet");
|
|
1604
|
+
await loadOrCreateLocalnetState({ cwd });
|
|
1605
|
+
} catch {
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
} else {
|
|
1609
|
+
if (!fs4.existsSync(hardkasDir)) {
|
|
1610
|
+
throw new HardkasError3("NOT_INITIALIZED", "Workspace not initialized. Run npx hardkas init . or pass autoBootstrap: true.");
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
if (options.network) {
|
|
1614
|
+
loaded.config.defaultNetwork = options.network;
|
|
1615
|
+
}
|
|
1450
1616
|
return new _Hardkas(loaded, options);
|
|
1451
1617
|
}
|
|
1452
1618
|
/**
|
|
@@ -1477,19 +1643,19 @@ var Hardkas = class _Hardkas {
|
|
|
1477
1643
|
switch (action) {
|
|
1478
1644
|
case "network":
|
|
1479
1645
|
if (!this.policy.allowNetwork)
|
|
1480
|
-
throw new
|
|
1646
|
+
throw new HardkasError3("POLICY_VIOLATION", msg("allowNetwork"));
|
|
1481
1647
|
break;
|
|
1482
1648
|
case "mainnet":
|
|
1483
1649
|
if (!this.policy.allowMainnet)
|
|
1484
|
-
throw new
|
|
1650
|
+
throw new HardkasError3("POLICY_VIOLATION", msg("allowMainnet"));
|
|
1485
1651
|
break;
|
|
1486
1652
|
case "external-wallet":
|
|
1487
1653
|
if (!this.policy.allowExternalWallet)
|
|
1488
|
-
throw new
|
|
1654
|
+
throw new HardkasError3("POLICY_VIOLATION", msg("allowExternalWallet"));
|
|
1489
1655
|
break;
|
|
1490
1656
|
case "mutation":
|
|
1491
1657
|
if (this.policy.requireDryRun)
|
|
1492
|
-
throw new
|
|
1658
|
+
throw new HardkasError3("POLICY_VIOLATION", msg("requireDryRun"));
|
|
1493
1659
|
break;
|
|
1494
1660
|
}
|
|
1495
1661
|
}
|
|
@@ -1500,8 +1666,9 @@ export {
|
|
|
1500
1666
|
Hardkas,
|
|
1501
1667
|
HardkasAccounts,
|
|
1502
1668
|
HardkasArtifactsManager,
|
|
1503
|
-
|
|
1669
|
+
HardkasError4 as HardkasError,
|
|
1504
1670
|
HardkasL2,
|
|
1671
|
+
HardkasLineage,
|
|
1505
1672
|
HardkasLocalnet,
|
|
1506
1673
|
HardkasQuery,
|
|
1507
1674
|
HardkasReplay,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardkas/sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9-alpha",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -23,23 +23,24 @@
|
|
|
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/wallet-adapter": "0.7.
|
|
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"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"tsup": "^8.3.5",
|
|
41
|
+
"@types/node": "^20.12.7",
|
|
40
42
|
"typescript": "^5.7.2",
|
|
41
|
-
"vitest": "^2.1.8"
|
|
42
|
-
"@hardkas/query-store": "0.7.7-alpha"
|
|
43
|
+
"vitest": "^2.1.8"
|
|
43
44
|
},
|
|
44
45
|
"license": "MIT",
|
|
45
46
|
"author": "Javier Rodriguez",
|