@hardkas/artifacts 0.8.3-alpha → 0.8.4-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
@@ -843,6 +843,7 @@ declare const TxPlanSchema: z.ZodObject<{
843
843
  rpcUrl: z.ZodOptional<z.ZodString>;
844
844
  networkProfileRef: z.ZodOptional<z.ZodString>;
845
845
  policyRef: z.ZodOptional<z.ZodString>;
846
+ policyRefs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
846
847
  assumptionRef: z.ZodOptional<z.ZodString>;
847
848
  }, "strip", z.ZodTypeAny, {
848
849
  version: "1.0.0-alpha";
@@ -905,6 +906,7 @@ declare const TxPlanSchema: z.ZodObject<{
905
906
  rpcUrl?: string | undefined;
906
907
  networkProfileRef?: string | undefined;
907
908
  policyRef?: string | undefined;
909
+ policyRefs?: string[] | undefined;
908
910
  assumptionRef?: string | undefined;
909
911
  }, {
910
912
  version: "1.0.0-alpha";
@@ -967,6 +969,7 @@ declare const TxPlanSchema: z.ZodObject<{
967
969
  rpcUrl?: string | undefined;
968
970
  networkProfileRef?: string | undefined;
969
971
  policyRef?: string | undefined;
972
+ policyRefs?: string[] | undefined;
970
973
  assumptionRef?: string | undefined;
971
974
  }>;
972
975
  declare const DagContextSchema: z.ZodObject<{
@@ -2670,6 +2673,7 @@ interface TxPlanArtifact extends BaseArtifact<"txPlan"> {
2670
2673
  } | undefined;
2671
2674
  networkProfileRef?: string | undefined;
2672
2675
  policyRef?: string | undefined;
2676
+ policyRefs?: string[] | undefined;
2673
2677
  assumptionRef?: string | undefined;
2674
2678
  }
2675
2679
  interface SignedTxArtifact extends BaseArtifact<"signedTx"> {
@@ -2894,6 +2898,9 @@ interface VerificationContext {
2894
2898
  strict?: boolean;
2895
2899
  networkId?: NetworkId;
2896
2900
  parent?: unknown;
2901
+ artifactsDir?: string;
2902
+ enforceMetadata?: boolean;
2903
+ resolveArtifact?: (id: string) => any;
2897
2904
  }
2898
2905
  type VerificationSeverity = CorruptionSeverity | "info" | "critical";
2899
2906
  type VerificationIssue = {
@@ -2918,7 +2925,12 @@ type ArtifactVerificationResult = {
2918
2925
  */
2919
2926
  declare function sortUtxosByOutpoint<T>(utxos: T[]): T[];
2920
2927
  /**
2921
- * Verifies an artifact's integrity.
2928
+ * Verifies an artifact's integrity synchronously.
2929
+ * Can take a raw object or a file path.
2930
+ */
2931
+ declare function verifyArtifactIntegritySync(artifactOrPath: unknown): ArtifactVerificationResult;
2932
+ /**
2933
+ * Verifies an artifact's integrity asynchronously.
2922
2934
  * Can take a raw object or a file path.
2923
2935
  */
2924
2936
  declare function verifyArtifactIntegrity(artifactOrPath: unknown): Promise<ArtifactVerificationResult>;
@@ -3413,4 +3425,4 @@ declare function listDeployments(rootDir: string, networkId?: string): Promise<D
3413
3425
  declare function updateDeployment(rootDir: string, networkId: string, label: string, update: Partial<DeploymentRecord>): Promise<DeploymentRecord>;
3414
3426
  declare function deleteDeployment(rootDir: string, networkId: string, label: string): Promise<boolean>;
3415
3427
 
3416
- export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactDiff, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactPayload, type ArtifactValidationResult, type ArtifactVerificationResult, type Assumption, type AssumptionArtifact, type AssumptionLevel, AssumptionSchema, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, CURRENT_HASH_VERSION, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type DeploymentIndex, type DeploymentRecord, type DeploymentSummary, type DiffEntry, type DraftArtifact, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageOptions, type LineageValidationResult, LocalnetUtxoSchemaV2, type MigrationReceipt, type MigrationReceiptArtifact, MigrationReceiptSchema, MigrationRequiredError, type MigrationResult, type MigrationStep, NetworkInvariant, type NetworkProfile, type NetworkProfileArtifact, NetworkProfileSchema, type Policy, type PolicyArtifact, PolicySchema, ReplayInvariant, type RuntimeSession, RuntimeSessionSchema, SEMANTIC_EXCLUSIONS, STRICT_PATH_KEYS, SchemaInvariant, type ScriptCapability, ScriptCapabilitySchema, ScriptMetadataSchema, SignatureEntrySchema, SignatureMetadataEntrySchema, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, type Workflow, type WorkflowArtifact, WorkflowSchema, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canMigrate, canonicalStringify, createDeploymentRecord, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, deleteDeployment, detectArtifactVersion, diffArtifacts, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, generateMigrationReceipt, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, getMigrationPath, getRegisteredMigrationSteps, isIgraTxPlanArtifact, listDeployments, listIgraTxReceiptArtifacts, loadDeployment, loadIgraTxReceiptArtifact, migrateArtifactPayload, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, registerMigrationStep, saveDeployment, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, updateDeployment, updateDeploymentStatus, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
3428
+ export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactDiff, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactPayload, type ArtifactValidationResult, type ArtifactVerificationResult, type Assumption, type AssumptionArtifact, type AssumptionLevel, AssumptionSchema, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, CURRENT_HASH_VERSION, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type DeploymentIndex, type DeploymentRecord, type DeploymentSummary, type DiffEntry, type DraftArtifact, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageOptions, type LineageValidationResult, LocalnetUtxoSchemaV2, type MigrationReceipt, type MigrationReceiptArtifact, MigrationReceiptSchema, MigrationRequiredError, type MigrationResult, type MigrationStep, NetworkInvariant, type NetworkProfile, type NetworkProfileArtifact, NetworkProfileSchema, type Policy, type PolicyArtifact, PolicySchema, ReplayInvariant, type RuntimeSession, RuntimeSessionSchema, SEMANTIC_EXCLUSIONS, STRICT_PATH_KEYS, SchemaInvariant, type ScriptCapability, ScriptCapabilitySchema, ScriptMetadataSchema, SignatureEntrySchema, SignatureMetadataEntrySchema, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, type Workflow, type WorkflowArtifact, WorkflowSchema, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canMigrate, canonicalStringify, createDeploymentRecord, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, deleteDeployment, detectArtifactVersion, diffArtifacts, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, generateMigrationReceipt, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, getMigrationPath, getRegisteredMigrationSteps, isIgraTxPlanArtifact, listDeployments, listIgraTxReceiptArtifacts, loadDeployment, loadIgraTxReceiptArtifact, migrateArtifactPayload, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, registerMigrationStep, saveDeployment, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, updateDeployment, updateDeploymentStatus, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactIntegritySync, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@hardkas/artifacts",
4
- version: "0.8.3-alpha",
4
+ version: "0.8.4-alpha",
5
5
  type: "module",
6
6
  license: "MIT",
7
7
  author: "Javier Rodriguez",
@@ -416,6 +416,7 @@ var TxPlanSchema = BaseArtifactSchema.extend({
416
416
  rpcUrl: z.string().optional(),
417
417
  networkProfileRef: z.string().optional(),
418
418
  policyRef: z.string().optional(),
419
+ policyRefs: z.array(z.string()).optional(),
419
420
  assumptionRef: z.string().optional()
420
421
  });
421
422
  var DagContextSchema = z.object({
@@ -581,6 +582,7 @@ var RuntimeSessionSchema = BaseArtifactSchema.extend({
581
582
 
582
583
  // src/verify.ts
583
584
  import fs from "fs";
585
+ import path from "path";
584
586
 
585
587
  // src/feeVerify.ts
586
588
  import {
@@ -815,15 +817,15 @@ function sortUtxosByOutpoint(utxos) {
815
817
  return deterministicCompare2(aId, bId);
816
818
  });
817
819
  }
818
- async function verifyArtifactIntegrity(artifactOrPath) {
820
+ function verifyArtifactIntegritySync(artifactOrPath) {
819
821
  const result = {
820
822
  ok: false,
821
823
  errors: [],
822
824
  issues: []
823
825
  };
824
- const addError = (code, message, path4) => {
826
+ const addError = (code, message, path5) => {
825
827
  result.errors.push(message);
826
- result.issues.push({ code, severity: "error", message, path: path4 });
828
+ result.issues.push({ code, severity: "error", message, path: path5 });
827
829
  };
828
830
  let artifact;
829
831
  try {
@@ -937,6 +939,37 @@ async function verifyArtifactIntegrity(artifactOrPath) {
937
939
  return result;
938
940
  }
939
941
  }
942
+ async function verifyArtifactIntegrity(artifactOrPath) {
943
+ return verifyArtifactIntegritySync(artifactOrPath);
944
+ }
945
+ function findFileByHash(hash, dirs) {
946
+ const shortHash = hash.startsWith("plan-") || hash.startsWith("signed-") ? hash : hash.slice(0, 16);
947
+ for (const dir of dirs) {
948
+ if (!fs.existsSync(dir)) continue;
949
+ try {
950
+ const files = fs.readdirSync(dir);
951
+ if (files.includes(`${hash}.json`)) {
952
+ return path.join(dir, `${hash}.json`);
953
+ }
954
+ for (const file of files) {
955
+ if (!file.endsWith(".json")) continue;
956
+ if (file.includes(hash) || file.includes(shortHash) || file.includes(hash.slice(0, 8))) {
957
+ const filePath = path.join(dir, file);
958
+ try {
959
+ const content = fs.readFileSync(filePath, "utf-8");
960
+ const obj = JSON.parse(content);
961
+ if (obj.contentHash === hash || obj.artifactId === hash || obj.planId === hash || obj.signedId === hash || obj.txId === hash) {
962
+ return filePath;
963
+ }
964
+ } catch {
965
+ }
966
+ }
967
+ }
968
+ } catch {
969
+ }
970
+ }
971
+ return null;
972
+ }
940
973
  function verifyArtifactSemantics(artifact, context = {}) {
941
974
  const result = {
942
975
  ok: true,
@@ -962,6 +995,225 @@ function verifyArtifactSemantics(artifact, context = {}) {
962
995
  });
963
996
  }
964
997
  const v = artifact;
998
+ let parentObj = null;
999
+ if (strict) {
1000
+ const searchDirs = [];
1001
+ if (context.artifactsDir) {
1002
+ searchDirs.push(context.artifactsDir);
1003
+ }
1004
+ searchDirs.push(path.join(process.cwd(), ".hardkas", "artifacts"));
1005
+ searchDirs.push(path.join(process.cwd(), "artifacts"));
1006
+ const policyRefs = [];
1007
+ if (Array.isArray(v.policyRefs)) {
1008
+ policyRefs.push(...v.policyRefs);
1009
+ } else if (typeof v.policyRef === "string") {
1010
+ policyRefs.push(v.policyRef);
1011
+ }
1012
+ for (const ref of policyRefs) {
1013
+ let refObj = context.resolveArtifact ? context.resolveArtifact(ref) : null;
1014
+ if (!refObj) {
1015
+ const refFile = findFileByHash(ref, searchDirs);
1016
+ if (refFile) {
1017
+ try {
1018
+ const content = fs.readFileSync(refFile, "utf-8");
1019
+ refObj = JSON.parse(content);
1020
+ } catch (e) {
1021
+ addIssue({
1022
+ code: "REFERENCE_CORRUPT",
1023
+ severity: "error",
1024
+ message: `Failed to read policy ${ref}: ${e.message}`
1025
+ });
1026
+ }
1027
+ }
1028
+ }
1029
+ if (!refObj) {
1030
+ addIssue({
1031
+ code: "REFERENCE_MISSING",
1032
+ severity: "error",
1033
+ message: `Referenced policy artifact ${ref} not found in workspace`
1034
+ });
1035
+ } else {
1036
+ try {
1037
+ const integrity = verifyArtifactIntegritySync(refObj);
1038
+ if (!integrity.ok) {
1039
+ addIssue({
1040
+ code: "REFERENCE_HASH_MISMATCH",
1041
+ severity: "error",
1042
+ message: `Referenced policy ${ref} integrity check failed: ${integrity.errors.join(", ")}`
1043
+ });
1044
+ } else if (refObj.contentHash !== ref && refObj.artifactId !== ref) {
1045
+ addIssue({
1046
+ code: "REFERENCE_HASH_MISMATCH",
1047
+ severity: "error",
1048
+ message: `Policy reference mismatch: expected ${ref}, got ${refObj.contentHash}`
1049
+ });
1050
+ } else {
1051
+ if (refObj.schema === "hardkas.policy.v1") {
1052
+ if (refObj.decision === "DENY") {
1053
+ addIssue({
1054
+ code: "POLICY_VIOLATION",
1055
+ severity: "error",
1056
+ message: `Policy evaluation rejected: decision is DENY`
1057
+ });
1058
+ } else if (refObj.decision !== "ALLOW") {
1059
+ addIssue({
1060
+ code: "POLICY_VIOLATION",
1061
+ severity: "error",
1062
+ message: `Policy evaluation rejected: decision is invalid (${refObj.decision})`
1063
+ });
1064
+ }
1065
+ const failedRules = refObj.rules?.filter((r) => r.result === "FAIL") || [];
1066
+ if (failedRules.length > 0) {
1067
+ addIssue({
1068
+ code: "POLICY_VIOLATION",
1069
+ severity: "error",
1070
+ message: `Policy rules failed: ${failedRules.map((r) => r.id).join(", ")}`
1071
+ });
1072
+ }
1073
+ }
1074
+ }
1075
+ } catch (e) {
1076
+ addIssue({
1077
+ code: "REFERENCE_CORRUPT",
1078
+ severity: "error",
1079
+ message: `Failed to read/verify policy ${ref}: ${e.message}`
1080
+ });
1081
+ }
1082
+ }
1083
+ }
1084
+ if (typeof v.networkProfileRef === "string") {
1085
+ const ref = v.networkProfileRef;
1086
+ let refObj = context.resolveArtifact ? context.resolveArtifact(ref) : null;
1087
+ if (!refObj) {
1088
+ const refFile = findFileByHash(ref, searchDirs);
1089
+ if (refFile) {
1090
+ try {
1091
+ refObj = JSON.parse(fs.readFileSync(refFile, "utf-8"));
1092
+ } catch {
1093
+ }
1094
+ }
1095
+ }
1096
+ if (!refObj) {
1097
+ addIssue({
1098
+ code: "REFERENCE_MISSING",
1099
+ severity: "error",
1100
+ message: `Referenced network profile ${ref} not found in workspace`
1101
+ });
1102
+ } else {
1103
+ try {
1104
+ const integrity = verifyArtifactIntegritySync(refObj);
1105
+ if (!integrity.ok) {
1106
+ addIssue({
1107
+ code: "REFERENCE_HASH_MISMATCH",
1108
+ severity: "error",
1109
+ message: `Referenced profile ${ref} integrity check failed`
1110
+ });
1111
+ } else if (refObj.contentHash !== ref && refObj.artifactId !== ref) {
1112
+ addIssue({
1113
+ code: "REFERENCE_HASH_MISMATCH",
1114
+ severity: "error",
1115
+ message: `Profile reference mismatch: expected ${ref}, got ${refObj.contentHash}`
1116
+ });
1117
+ }
1118
+ } catch (e) {
1119
+ addIssue({
1120
+ code: "REFERENCE_CORRUPT",
1121
+ severity: "error",
1122
+ message: `Failed to verify profile ${ref}`
1123
+ });
1124
+ }
1125
+ }
1126
+ }
1127
+ if (typeof v.assumptionRef === "string") {
1128
+ const ref = v.assumptionRef;
1129
+ let refObj = context.resolveArtifact ? context.resolveArtifact(ref) : null;
1130
+ if (!refObj) {
1131
+ const refFile = findFileByHash(ref, searchDirs);
1132
+ if (refFile) {
1133
+ try {
1134
+ refObj = JSON.parse(fs.readFileSync(refFile, "utf-8"));
1135
+ } catch {
1136
+ }
1137
+ }
1138
+ }
1139
+ if (!refObj) {
1140
+ addIssue({
1141
+ code: "REFERENCE_MISSING",
1142
+ severity: "error",
1143
+ message: `Referenced assumption ${ref} not found in workspace`
1144
+ });
1145
+ } else {
1146
+ try {
1147
+ const integrity = verifyArtifactIntegritySync(refObj);
1148
+ if (!integrity.ok) {
1149
+ addIssue({
1150
+ code: "REFERENCE_HASH_MISMATCH",
1151
+ severity: "error",
1152
+ message: `Referenced assumption ${ref} integrity check failed`
1153
+ });
1154
+ } else if (refObj.contentHash !== ref && refObj.artifactId !== ref) {
1155
+ addIssue({
1156
+ code: "REFERENCE_HASH_MISMATCH",
1157
+ severity: "error",
1158
+ message: `Assumption reference mismatch: expected ${ref}, got ${refObj.contentHash}`
1159
+ });
1160
+ }
1161
+ } catch (e) {
1162
+ addIssue({
1163
+ code: "REFERENCE_CORRUPT",
1164
+ severity: "error",
1165
+ message: `Failed to verify assumption ${ref}`
1166
+ });
1167
+ }
1168
+ }
1169
+ }
1170
+ let parentId;
1171
+ const lineage = v.lineage;
1172
+ if (lineage?.parentArtifactId && lineage?.parentArtifactId !== lineage?.artifactId) {
1173
+ parentId = lineage?.parentArtifactId;
1174
+ } else if (v.schema === "hardkas.signedTx") {
1175
+ parentId = v.sourcePlanId;
1176
+ } else if (v.schema === "hardkas.txReceipt") {
1177
+ parentId = v.sourceSignedId || lineage?.parentArtifactId;
1178
+ }
1179
+ if (parentId) {
1180
+ parentObj = context.resolveArtifact ? context.resolveArtifact(parentId) : null;
1181
+ if (!parentObj) {
1182
+ const parentFile = findFileByHash(parentId, searchDirs);
1183
+ if (parentFile) {
1184
+ try {
1185
+ parentObj = JSON.parse(fs.readFileSync(parentFile, "utf-8"));
1186
+ } catch (e) {
1187
+ addIssue({
1188
+ code: "PARENT_CORRUPT",
1189
+ severity: "error",
1190
+ message: `Failed to read parent ${parentId}: ${e.message}`
1191
+ });
1192
+ }
1193
+ }
1194
+ }
1195
+ if (!parentObj) {
1196
+ addIssue({
1197
+ code: "PARENT_MISSING",
1198
+ severity: "warning",
1199
+ message: `Parent artifact ${parentId} not found in workspace`
1200
+ });
1201
+ } else {
1202
+ try {
1203
+ const parentSem = verifyArtifactSemantics(parentObj, { ...context, strict: true });
1204
+ if (!parentSem.ok) {
1205
+ parentSem.issues.forEach((issue) => addIssue(issue));
1206
+ }
1207
+ } catch (e) {
1208
+ addIssue({
1209
+ code: "PARENT_CORRUPT",
1210
+ severity: "error",
1211
+ message: `Failed to verify parent ${parentId}: ${e.message}`
1212
+ });
1213
+ }
1214
+ }
1215
+ }
1216
+ }
965
1217
  if (v.createdAt && typeof v.createdAt === "string") {
966
1218
  const created = new Date(v.createdAt).getTime();
967
1219
  const now = clock.now();
@@ -980,31 +1232,47 @@ function verifyArtifactSemantics(artifact, context = {}) {
980
1232
  });
981
1233
  }
982
1234
  }
983
- const lineageAudit = verifyLineage(v, context.parent, { strict });
1235
+ const lineageAudit = verifyLineage(v, parentObj || context.parent, { strict });
984
1236
  if (!lineageAudit.ok || strict && !v.lineage && v.schema !== "hardkas.workflow.v1") {
985
1237
  lineageAudit.issues.forEach((issue) => {
986
1238
  addIssue(issue);
987
1239
  });
988
1240
  }
989
1241
  if (strict) {
990
- if (!v.workflowId)
991
- addIssue({
992
- code: "MISSING_WORKFLOW_ID",
993
- severity: "error",
994
- message: "Strict mode requires workflowId"
995
- });
996
- if (!v.assumptionLevel && v.schema !== "hardkas.workflow.v1")
997
- addIssue({
998
- code: "MISSING_ASSUMPTION_LEVEL",
999
- severity: "error",
1000
- message: "Strict mode requires assumptionLevel"
1001
- });
1002
- if (!v.executionMode && !v.mode)
1003
- addIssue({
1004
- code: "MISSING_EXECUTION_MODE",
1005
- severity: "error",
1006
- message: "Strict mode requires executionMode"
1007
- });
1242
+ const enforceMetadata = context.enforceMetadata ?? true;
1243
+ if (enforceMetadata) {
1244
+ if (!v.workflowId)
1245
+ addIssue({
1246
+ code: "MISSING_WORKFLOW_ID",
1247
+ severity: "error",
1248
+ message: "Strict mode requires workflowId"
1249
+ });
1250
+ if (!v.assumptionLevel && v.schema !== "hardkas.workflow.v1")
1251
+ addIssue({
1252
+ code: "MISSING_ASSUMPTION_LEVEL",
1253
+ severity: "error",
1254
+ message: "Strict mode requires assumptionLevel"
1255
+ });
1256
+ if (!v.executionMode && !v.mode)
1257
+ addIssue({
1258
+ code: "MISSING_EXECUTION_MODE",
1259
+ severity: "error",
1260
+ message: "Strict mode requires executionMode"
1261
+ });
1262
+ } else {
1263
+ if (!v.workflowId)
1264
+ addIssue({
1265
+ code: "MISSING_WORKFLOW_ID",
1266
+ severity: "warning",
1267
+ message: "Missing workflowId"
1268
+ });
1269
+ if (!v.assumptionLevel && v.schema !== "hardkas.workflow.v1")
1270
+ addIssue({
1271
+ code: "MISSING_ASSUMPTION_LEVEL",
1272
+ severity: "warning",
1273
+ message: "Missing assumptionLevel"
1274
+ });
1275
+ }
1008
1276
  } else {
1009
1277
  if (!v.workflowId)
1010
1278
  addIssue({
@@ -1375,8 +1643,8 @@ function canMigrate(artifact, targetVersion = ARTIFACT_VERSION) {
1375
1643
  if (currentVersion === targetVersion) {
1376
1644
  return true;
1377
1645
  }
1378
- const path4 = getMigrationPath(currentVersion, targetVersion);
1379
- return path4.length > 0;
1646
+ const path5 = getMigrationPath(currentVersion, targetVersion);
1647
+ return path5.length > 0;
1380
1648
  }
1381
1649
  function migrateArtifactPayload(artifact, targetVersion = ARTIFACT_VERSION, options) {
1382
1650
  const currentVersion = detectArtifactVersion(artifact);
@@ -1391,8 +1659,8 @@ function migrateArtifactPayload(artifact, targetVersion = ARTIFACT_VERSION, opti
1391
1659
  if (options?.strictPolicy) {
1392
1660
  throw new MigrationRequiredError(currentVersion, targetVersion);
1393
1661
  }
1394
- const path4 = getMigrationPath(currentVersion, targetVersion);
1395
- if (path4.length === 0) {
1662
+ const path5 = getMigrationPath(currentVersion, targetVersion);
1663
+ if (path5.length === 0) {
1396
1664
  throw new Error(
1397
1665
  `No migration path from version "${currentVersion}" to "${targetVersion}". Registered steps: [${migrationRegistry.map((s) => `${s.fromVersion}\u2192${s.toVersion}`).join(", ")}]`
1398
1666
  );
@@ -1401,7 +1669,7 @@ function migrateArtifactPayload(artifact, targetVersion = ARTIFACT_VERSION, opti
1401
1669
  const originalLineage = artifact.lineage;
1402
1670
  let current = { ...artifact };
1403
1671
  const appliedSteps = [];
1404
- for (const step of path4) {
1672
+ for (const step of path5) {
1405
1673
  current = step.transform(current);
1406
1674
  appliedSteps.push({
1407
1675
  fromVersion: step.fromVersion,
@@ -1478,7 +1746,7 @@ function generateMigrationReceipt(oldArtifact, newArtifact, migrationId) {
1478
1746
 
1479
1747
  // src/io.ts
1480
1748
  import fs2 from "fs/promises";
1481
- import path from "path";
1749
+ import path2 from "path";
1482
1750
  import { writeFileAtomic } from "@hardkas/core";
1483
1751
  var bigIntReplacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
1484
1752
  async function writeArtifact(filePath, artifact) {
@@ -1489,10 +1757,10 @@ async function writeArtifact(filePath, artifact) {
1489
1757
  const artifactObj = typeof artifact === "string" ? JSON.parse(artifact) : artifact;
1490
1758
  const id = artifactObj.planId || artifactObj.signedId || artifactObj.txId || Date.now().toString(36);
1491
1759
  const prefix = artifactObj.schema ? artifactObj.schema.split(".")[1] || "artifact" : "artifact";
1492
- targetPath = path.join(filePath, `${prefix}-${id}.json`);
1760
+ targetPath = path2.join(filePath, `${prefix}-${id}.json`);
1493
1761
  console.log(
1494
1762
  `
1495
- Note: Provided path is a directory. Auto-generating artifact filename: ${path.basename(targetPath)}`
1763
+ Note: Provided path is a directory. Auto-generating artifact filename: ${path2.basename(targetPath)}`
1496
1764
  );
1497
1765
  }
1498
1766
  } catch (e) {
@@ -1500,14 +1768,14 @@ Note: Provided path is a directory. Auto-generating artifact filename: ${path.ba
1500
1768
  const artifactObj = typeof artifact === "string" ? JSON.parse(artifact) : artifact;
1501
1769
  const id = artifactObj.planId || artifactObj.signedId || artifactObj.txId || Date.now().toString(36);
1502
1770
  const prefix = artifactObj.schema ? artifactObj.schema.split(".")[1] || "artifact" : "artifact";
1503
- targetPath = path.join(filePath, `${prefix}-${id}.json`);
1771
+ targetPath = path2.join(filePath, `${prefix}-${id}.json`);
1504
1772
  }
1505
1773
  }
1506
1774
  const content = typeof artifact === "string" ? artifact : JSON.stringify(artifact, bigIntReplacer, 2) + "\n";
1507
1775
  await writeFileAtomic(targetPath, content);
1508
1776
  }
1509
1777
  function getDefaultReceiptPath(txId, cwd = process.cwd()) {
1510
- return path.join(cwd, "artifacts", "receipts", `${txId}.json`);
1778
+ return path2.join(cwd, "artifacts", "receipts", `${txId}.json`);
1511
1779
  }
1512
1780
  async function readArtifact(filePath) {
1513
1781
  try {
@@ -2040,15 +2308,15 @@ async function explainArtifact(artifactUnknown) {
2040
2308
 
2041
2309
  // src/igra-io.ts
2042
2310
  import fs3 from "fs/promises";
2043
- import path2 from "path";
2311
+ import path3 from "path";
2044
2312
  import { deterministicCompare as deterministicCompare3 } from "@hardkas/core";
2045
2313
  function getDefaultL2ReceiptsDir(cwd = process.cwd()) {
2046
- return path2.join(cwd, ".hardkas", "l2-receipts");
2314
+ return path3.join(cwd, ".hardkas", "l2-receipts");
2047
2315
  }
2048
2316
  function getL2ReceiptPath(txHash, options) {
2049
2317
  validateTxHash(txHash);
2050
2318
  const dir = getDefaultL2ReceiptsDir(options?.cwd);
2051
- return path2.join(dir, `${txHash}.igra.receipt.json`);
2319
+ return path3.join(dir, `${txHash}.igra.receipt.json`);
2052
2320
  }
2053
2321
  async function saveIgraTxReceiptArtifact(receipt, options) {
2054
2322
  assertValidIgraTxReceiptArtifact(receipt);
@@ -2070,7 +2338,7 @@ async function listIgraTxReceiptArtifacts(options) {
2070
2338
  const receipts = [];
2071
2339
  for (const file of receiptFiles) {
2072
2340
  try {
2073
- const data = await readArtifact(path2.join(dir, file));
2341
+ const data = await readArtifact(path3.join(dir, file));
2074
2342
  if (data && typeof data === "object" && data.schema === "hardkas.igraTxReceipt.v1") {
2075
2343
  receipts.push(data);
2076
2344
  }
@@ -2103,26 +2371,26 @@ function diffArtifacts(left, right) {
2103
2371
  entries
2104
2372
  };
2105
2373
  }
2106
- function compareRecursive(left, right, path4, entries) {
2374
+ function compareRecursive(left, right, path5, entries) {
2107
2375
  if (isPrimitive(left) || isPrimitive(right)) {
2108
2376
  if (left !== right) {
2109
- entries.push({ path: path4, kind: "changed", left, right });
2377
+ entries.push({ path: path5, kind: "changed", left, right });
2110
2378
  }
2111
2379
  return;
2112
2380
  }
2113
2381
  if (Array.isArray(left) || Array.isArray(right)) {
2114
2382
  if (!Array.isArray(left) || !Array.isArray(right)) {
2115
- entries.push({ path: path4, kind: "changed", left, right });
2383
+ entries.push({ path: path5, kind: "changed", left, right });
2116
2384
  return;
2117
2385
  }
2118
2386
  const maxLength = Math.max(left.length, right.length);
2119
2387
  for (let i = 0; i < maxLength; i++) {
2120
2388
  if (i >= left.length) {
2121
- entries.push({ path: `${path4}[${i}]`, kind: "added", right: right[i] });
2389
+ entries.push({ path: `${path5}[${i}]`, kind: "added", right: right[i] });
2122
2390
  } else if (i >= right.length) {
2123
- entries.push({ path: `${path4}[${i}]`, kind: "removed", left: left[i] });
2391
+ entries.push({ path: `${path5}[${i}]`, kind: "removed", left: left[i] });
2124
2392
  } else {
2125
- compareRecursive(left[i], right[i], `${path4}[${i}]`, entries);
2393
+ compareRecursive(left[i], right[i], `${path5}[${i}]`, entries);
2126
2394
  }
2127
2395
  }
2128
2396
  return;
@@ -2131,7 +2399,7 @@ function compareRecursive(left, right, path4, entries) {
2131
2399
  const rightKeys = Object.keys(right).filter((k) => !SEMANTIC_EXCLUSIONS.has(k));
2132
2400
  const allKeys = /* @__PURE__ */ new Set([...leftKeys, ...rightKeys]);
2133
2401
  for (const key of allKeys) {
2134
- const nextPath = path4 === "$" ? key : `${path4}.${key}`;
2402
+ const nextPath = path5 === "$" ? key : `${path5}.${key}`;
2135
2403
  if (!leftKeys.includes(key)) {
2136
2404
  entries.push({ path: nextPath, kind: "added", right: right[key] });
2137
2405
  } else if (!rightKeys.includes(key)) {
@@ -2195,16 +2463,16 @@ function updateDeploymentStatus(record, newStatus, txId) {
2195
2463
  // src/deployment-store.ts
2196
2464
  import fs4 from "fs/promises";
2197
2465
  import { existsSync } from "fs";
2198
- import path3 from "path";
2466
+ import path4 from "path";
2199
2467
  import { writeFileAtomic as writeFileAtomic2 } from "@hardkas/core";
2200
2468
  async function saveDeployment(rootDir, record) {
2201
- const deploymentsDir = path3.join(rootDir, ".hardkas", "deployments", record.networkId);
2202
- const targetPath = path3.join(deploymentsDir, `${record.label}.json`);
2469
+ const deploymentsDir = path4.join(rootDir, ".hardkas", "deployments", record.networkId);
2470
+ const targetPath = path4.join(deploymentsDir, `${record.label}.json`);
2203
2471
  await writeFileAtomic2(targetPath, JSON.stringify(record, null, 2));
2204
2472
  return targetPath;
2205
2473
  }
2206
2474
  async function loadDeployment(rootDir, networkId, label) {
2207
- const targetPath = path3.join(
2475
+ const targetPath = path4.join(
2208
2476
  rootDir,
2209
2477
  ".hardkas",
2210
2478
  "deployments",
@@ -2216,18 +2484,18 @@ async function loadDeployment(rootDir, networkId, label) {
2216
2484
  return JSON.parse(content);
2217
2485
  }
2218
2486
  async function listDeployments(rootDir, networkId) {
2219
- const baseDir = path3.join(rootDir, ".hardkas", "deployments");
2487
+ const baseDir = path4.join(rootDir, ".hardkas", "deployments");
2220
2488
  if (!existsSync(baseDir)) return [];
2221
2489
  const summaries = [];
2222
2490
  const networks = networkId ? [networkId] : await fs4.readdir(baseDir);
2223
2491
  for (const net of networks) {
2224
- const netDir = path3.join(baseDir, net);
2492
+ const netDir = path4.join(baseDir, net);
2225
2493
  if (!existsSync(netDir)) continue;
2226
2494
  const files = await fs4.readdir(netDir);
2227
2495
  for (const file of files) {
2228
2496
  if (!file.endsWith(".json")) continue;
2229
2497
  try {
2230
- const content = await fs4.readFile(path3.join(netDir, file), "utf-8");
2498
+ const content = await fs4.readFile(path4.join(netDir, file), "utf-8");
2231
2499
  const record = JSON.parse(content);
2232
2500
  const summary = {
2233
2501
  label: record.label,
@@ -2260,7 +2528,7 @@ async function updateDeployment(rootDir, networkId, label, update) {
2260
2528
  return updated;
2261
2529
  }
2262
2530
  async function deleteDeployment(rootDir, networkId, label) {
2263
- const targetPath = path3.join(
2531
+ const targetPath = path4.join(
2264
2532
  rootDir,
2265
2533
  ".hardkas",
2266
2534
  "deployments",
@@ -2375,6 +2643,7 @@ export {
2375
2643
  verifyArtifact,
2376
2644
  verifyArtifactFile,
2377
2645
  verifyArtifactIntegrity,
2646
+ verifyArtifactIntegritySync,
2378
2647
  verifyArtifactReplay,
2379
2648
  verifyArtifactSemantics,
2380
2649
  verifyFeeSemantics,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/artifacts",
3
- "version": "0.8.3-alpha",
3
+ "version": "0.8.4-alpha",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Javier Rodriguez",
@@ -24,8 +24,8 @@
24
24
  "types": "./dist/index.d.ts",
25
25
  "dependencies": {
26
26
  "zod": "^3.24.1",
27
- "@hardkas/core": "0.8.3-alpha",
28
- "@hardkas/tx-builder": "0.8.3-alpha"
27
+ "@hardkas/core": "0.8.4-alpha",
28
+ "@hardkas/tx-builder": "0.8.4-alpha"
29
29
  },
30
30
  "devDependencies": {
31
31
  "tsup": "^8.3.5",