@caatinga/core 3.2.0 → 3.3.0

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.js CHANGED
@@ -8,6 +8,8 @@ var CaatingaErrorCode = {
8
8
  STELLAR_CLI_NOT_FOUND: "CAATINGA_STELLAR_CLI_NOT_FOUND",
9
9
  STELLAR_CLI_VERSION_PARSE_FAILED: "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
10
10
  UNSUPPORTED_CLI_VERSION: "CAATINGA_UNSUPPORTED_CLI_VERSION",
11
+ STELLAR_SDK_VERSION_PARSE_FAILED: "CAATINGA_STELLAR_SDK_VERSION_PARSE_FAILED",
12
+ UNSUPPORTED_SDK_VERSION: "CAATINGA_UNSUPPORTED_SDK_VERSION",
11
13
  RUST_NOT_FOUND: "CAATINGA_RUST_NOT_FOUND",
12
14
  RUST_TARGET_NOT_FOUND: "CAATINGA_RUST_TARGET_NOT_FOUND",
13
15
  DEPLOY_FAILED: "CAATINGA_DEPLOY_FAILED",
@@ -50,6 +52,8 @@ var CaatingaErrorCode = {
50
52
  ZK_VERIFICATION_FAILED: "CAATINGA_ZK_VERIFICATION_FAILED",
51
53
  ZK_DEV_CEREMONY_BLOCKED: "CAATINGA_ZK_DEV_CEREMONY_BLOCKED",
52
54
  DOCTOR_PARTIAL_DEPLOY: "CAATINGA_DOCTOR_PARTIAL_DEPLOY",
55
+ ROLLBACK_TARGET_NOT_FOUND: "CAATINGA_ROLLBACK_TARGET_NOT_FOUND",
56
+ ESTIMATE_FAILED: "CAATINGA_ESTIMATE_FAILED",
53
57
  MULTI_AUTH_REQUIRED: "CAATINGA_MULTI_AUTH_REQUIRED"
54
58
  };
55
59
 
@@ -236,6 +240,14 @@ async function loadConfig(options = {}) {
236
240
 
237
241
  // src/artifacts/artifact.schema.ts
238
242
  import { z as z3 } from "zod";
243
+ var ArtifactSupersedeReasonSchema = z3.enum(["upgrade", "rollback", "force-redeploy"]);
244
+ var ContractArtifactHistoryEntrySchema = z3.object({
245
+ contractId: z3.string().min(1),
246
+ wasmHash: z3.string().min(1),
247
+ deployedAt: z3.string().datetime(),
248
+ supersededAt: z3.string().datetime(),
249
+ reason: ArtifactSupersedeReasonSchema.optional()
250
+ });
239
251
  var ContractArtifactSchema = z3.object({
240
252
  contractId: z3.string().min(1),
241
253
  wasmHash: z3.string().min(1),
@@ -243,17 +255,28 @@ var ContractArtifactSchema = z3.object({
243
255
  sourcePath: z3.string().min(1),
244
256
  wasmPath: z3.string().min(1),
245
257
  dependencies: z3.array(z3.string().min(1)).default([]),
246
- resolvedDeployArgs: z3.record(z3.string().min(1), z3.union([z3.string(), z3.number(), z3.boolean()])).default({})
258
+ resolvedDeployArgs: z3.record(z3.string().min(1), z3.union([z3.string(), z3.number(), z3.boolean()])).default({}),
259
+ history: z3.array(ContractArtifactHistoryEntrySchema).optional()
247
260
  });
248
261
  var NetworkArtifactsSchema = z3.object({
249
262
  contracts: z3.record(z3.string().min(1), ContractArtifactSchema).default({}),
250
263
  dependencyGraph: z3.record(z3.string().min(1), z3.array(z3.string().min(1))).default({})
251
264
  });
252
- var CaatingaArtifactsSchema = z3.object({
265
+ var CaatingaArtifactsBaseSchema = z3.object({
253
266
  project: z3.string().min(1),
254
- version: z3.literal(1),
255
267
  networks: z3.record(z3.string().min(1), NetworkArtifactsSchema).default({})
256
268
  });
269
+ var CaatingaArtifactsV1Schema = CaatingaArtifactsBaseSchema.extend({
270
+ version: z3.literal(1)
271
+ });
272
+ var CaatingaArtifactsV2Schema = CaatingaArtifactsBaseSchema.extend({
273
+ version: z3.literal(2)
274
+ });
275
+ var CaatingaArtifactsSchema = z3.union([
276
+ CaatingaArtifactsV1Schema,
277
+ CaatingaArtifactsV2Schema
278
+ ]);
279
+ var CURRENT_ARTIFACTS_SCHEMA_VERSION = 2;
257
280
 
258
281
  // src/artifacts/read-artifacts.ts
259
282
  import { readFile } from "fs/promises";
@@ -305,29 +328,139 @@ function createInitialArtifacts(project, options = {}) {
305
328
  );
306
329
  return {
307
330
  project,
308
- version: 1,
331
+ version: 2,
309
332
  networks
310
333
  };
311
334
  }
312
335
 
313
336
  // src/artifacts/update-artifact.ts
314
- function updateArtifact(artifacts, networkName, contractName, contractArtifact, networkExtras) {
337
+ function appendHistory(existing, reason) {
338
+ if (!existing || !reason) {
339
+ return existing?.history;
340
+ }
341
+ const supersededAt = (/* @__PURE__ */ new Date()).toISOString();
342
+ const entry = {
343
+ contractId: existing.contractId,
344
+ wasmHash: existing.wasmHash,
345
+ deployedAt: existing.deployedAt,
346
+ supersededAt,
347
+ reason
348
+ };
349
+ return [...existing.history ?? [], entry];
350
+ }
351
+ function updateArtifact(artifacts, networkName, contractName, contractArtifact, options = {}) {
315
352
  const existingNetwork = artifacts.networks[networkName] ?? { contracts: {}, dependencyGraph: {} };
353
+ const existingContract = existingNetwork.contracts[contractName];
354
+ const history = appendHistory(existingContract, options.supersedeReason);
355
+ const nextVersion = artifacts.version === 1 && options.supersedeReason ? 2 : artifacts.version;
316
356
  return {
317
357
  ...artifacts,
358
+ version: nextVersion,
318
359
  networks: {
319
360
  ...artifacts.networks,
320
361
  [networkName]: {
321
362
  ...existingNetwork,
322
- dependencyGraph: networkExtras?.dependencyGraph ?? existingNetwork.dependencyGraph ?? {},
363
+ dependencyGraph: options.dependencyGraph ?? existingNetwork.dependencyGraph ?? {},
323
364
  contracts: {
324
365
  ...existingNetwork.contracts,
325
- [contractName]: contractArtifact
366
+ [contractName]: {
367
+ ...contractArtifact,
368
+ history: history ?? contractArtifact.history
369
+ }
326
370
  }
327
371
  }
328
372
  }
329
373
  };
330
374
  }
375
+ function restoreArtifactFromHistory(input) {
376
+ const network = input.artifacts.networks[input.networkName];
377
+ const current = network?.contracts[input.contractName];
378
+ if (!current) {
379
+ throw new CaatingaError(
380
+ `No artifact for "${input.contractName}" on "${input.networkName}".`,
381
+ CaatingaErrorCode.ARTIFACT_NOT_FOUND,
382
+ "Deploy the contract before attempting rollback."
383
+ );
384
+ }
385
+ if (current.contractId === input.contractId) {
386
+ return input.artifacts;
387
+ }
388
+ const fromHistory = (current.history ?? []).find(
389
+ (entry) => entry.contractId === input.contractId
390
+ );
391
+ if (!fromHistory) {
392
+ throw new CaatingaError(
393
+ `Rollback target "${input.contractId}" was not found in artifact history for "${input.contractName}".`,
394
+ CaatingaErrorCode.ROLLBACK_TARGET_NOT_FOUND,
395
+ "Use caatinga inspect to list prior contract IDs, or redeploy manually."
396
+ );
397
+ }
398
+ const supersededAt = (/* @__PURE__ */ new Date()).toISOString();
399
+ const restoredArtifact = {
400
+ contractId: fromHistory.contractId,
401
+ wasmHash: fromHistory.wasmHash,
402
+ deployedAt: fromHistory.deployedAt,
403
+ sourcePath: current.sourcePath,
404
+ wasmPath: current.wasmPath,
405
+ dependencies: current.dependencies,
406
+ resolvedDeployArgs: current.resolvedDeployArgs,
407
+ history: [
408
+ ...current.history ?? [],
409
+ {
410
+ contractId: current.contractId,
411
+ wasmHash: current.wasmHash,
412
+ deployedAt: current.deployedAt,
413
+ supersededAt,
414
+ reason: "rollback"
415
+ }
416
+ ]
417
+ };
418
+ return {
419
+ ...updateArtifact(input.artifacts, input.networkName, input.contractName, restoredArtifact),
420
+ version: 2
421
+ };
422
+ }
423
+
424
+ // src/artifacts/migrate-artifacts.ts
425
+ function migrateArtifactsToV2(artifacts) {
426
+ if (artifacts.version === CURRENT_ARTIFACTS_SCHEMA_VERSION) {
427
+ return {
428
+ artifacts,
429
+ migrated: false
430
+ };
431
+ }
432
+ const v1 = artifacts;
433
+ return {
434
+ artifacts: {
435
+ project: v1.project,
436
+ version: CURRENT_ARTIFACTS_SCHEMA_VERSION,
437
+ networks: v1.networks
438
+ },
439
+ migrated: true
440
+ };
441
+ }
442
+
443
+ // src/artifacts/migrate-artifacts-file.ts
444
+ async function migrateArtifactsFile(cwd = process.cwd()) {
445
+ const artifacts = await readArtifacts(cwd);
446
+ const { artifacts: migrated, migrated: changed } = migrateArtifactsToV2(artifacts);
447
+ const path17 = await writeArtifacts(migrated, cwd);
448
+ return { path: path17, migrated: changed, artifacts: migrated };
449
+ }
450
+
451
+ // src/artifacts/rollback-artifact.ts
452
+ async function rollbackContractArtifact(input) {
453
+ const cwd = input.cwd ?? process.cwd();
454
+ const artifacts = await readArtifacts(cwd);
455
+ const next = restoreArtifactFromHistory({
456
+ artifacts,
457
+ networkName: input.networkName,
458
+ contractName: input.contractName,
459
+ contractId: input.contractId
460
+ });
461
+ const path17 = await writeArtifacts(next, cwd);
462
+ return { path: path17, artifacts: next };
463
+ }
331
464
 
332
465
  // src/networks/resolve-network.ts
333
466
  function resolveNetwork(config, networkName) {
@@ -594,6 +727,35 @@ function evaluateStellarCliCompatibility(input) {
594
727
  };
595
728
  }
596
729
 
730
+ // src/stellar-cli/probe-stellar-cli-features.ts
731
+ import semver3 from "semver";
732
+ var STELLAR_CLI_REQUIRED_FEATURES = [
733
+ "contract-build",
734
+ "contract-deploy",
735
+ "contract-invoke-sign"
736
+ ];
737
+ var FEATURE_COMMANDS = {
738
+ "contract-build": ["contract", "build", "--help"],
739
+ "contract-deploy": ["contract", "deploy", "--help"],
740
+ "contract-invoke-sign": ["contract", "invoke", "--help"]
741
+ };
742
+ async function probeMissingStellarCliFeatures(version) {
743
+ const missing = [];
744
+ if (semver3.valid(version) && semver3.lt(version, STELLAR_CLI_MIN_VERSION)) {
745
+ return ["contract-invoke-sign"];
746
+ }
747
+ for (const feature of STELLAR_CLI_REQUIRED_FEATURES) {
748
+ try {
749
+ await runCommand("stellar", FEATURE_COMMANDS[feature], {
750
+ skipStellarVersionCheck: true
751
+ });
752
+ } catch {
753
+ missing.push(feature);
754
+ }
755
+ }
756
+ return missing;
757
+ }
758
+
597
759
  // src/stellar-cli/check-stellar-cli-version.ts
598
760
  async function checkStellarCliVersion(input = {}) {
599
761
  let rawOutput;
@@ -613,9 +775,12 @@ async function checkStellarCliVersion(input = {}) {
613
775
  }
614
776
  throw error;
615
777
  }
778
+ const version = parseStellarCliVersion(rawOutput);
779
+ const probedMissing = input.probeFeatures === false ? [] : await probeMissingStellarCliFeatures(version);
780
+ const missingFeatures = [...input.features ?? [], ...probedMissing];
616
781
  const report = evaluateStellarCliCompatibility({
617
- version: parseStellarCliVersion(rawOutput),
618
- features: input.features,
782
+ version,
783
+ features: missingFeatures.length > 0 ? missingFeatures : void 0,
619
784
  lastTestedVersion: input.lastTestedVersion
620
785
  });
621
786
  for (const warning of report.warnings) {
@@ -761,6 +926,122 @@ function parseContractId(output) {
761
926
  return match[0];
762
927
  }
763
928
 
929
+ // src/stellar-sdk/check-stellar-sdk-version.ts
930
+ import { readFile as readFile3 } from "fs/promises";
931
+ import path7 from "path";
932
+
933
+ // src/stellar-sdk/compat.ts
934
+ import semver4 from "semver";
935
+
936
+ // src/stellar-sdk/version.ts
937
+ var STELLAR_SDK_MIN_VERSION = "16.0.1";
938
+ var STELLAR_SDK_LAST_TESTED_VERSION = "16.0.1";
939
+
940
+ // src/stellar-sdk/compat.ts
941
+ function evaluateStellarSdkCompatibility(input) {
942
+ const parsed = semver4.parse(input.version);
943
+ if (!parsed || !semver4.valid(input.version)) {
944
+ throw new CaatingaError(
945
+ "Could not parse @stellar/stellar-sdk version.",
946
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
947
+ "Use a semantic version such as 16.0.1."
948
+ );
949
+ }
950
+ const lastTestedVersion = semver4.valid(input.lastTestedVersion ?? STELLAR_SDK_LAST_TESTED_VERSION) ?? STELLAR_SDK_LAST_TESTED_VERSION;
951
+ const warnings = [];
952
+ let status = "supported";
953
+ if (semver4.lt(parsed, STELLAR_SDK_MIN_VERSION)) {
954
+ throw new CaatingaError(
955
+ `@stellar/stellar-sdk ${input.version} is below the supported minimum ${STELLAR_SDK_MIN_VERSION}.`,
956
+ CaatingaErrorCode.UNSUPPORTED_SDK_VERSION,
957
+ `Install @stellar/stellar-sdk ${STELLAR_SDK_MIN_VERSION} or newer.`
958
+ );
959
+ }
960
+ if (semver4.gt(parsed, lastTestedVersion)) {
961
+ status = "untested";
962
+ warnings.push({
963
+ code: "STELLAR_SDK_UNTESTED_VERSION",
964
+ message: `@stellar/stellar-sdk ${input.version} is newer than the last-tested ${lastTestedVersion}; binding output may differ.`,
965
+ remediation: "Pin @stellar/stellar-sdk to the last-tested version in package.json, or update Caatinga fixtures after validating generate output."
966
+ });
967
+ }
968
+ return {
969
+ version: input.version,
970
+ status,
971
+ minVersion: STELLAR_SDK_MIN_VERSION,
972
+ lastTestedVersion,
973
+ warnings
974
+ };
975
+ }
976
+ function parseStellarSdkVersion(raw) {
977
+ const trimmed = raw.trim();
978
+ const match = trimmed.match(/(\d+\.\d+\.\d+(?:[-+][\w.-]+)?)/);
979
+ if (!match) {
980
+ throw new CaatingaError(
981
+ "Could not parse @stellar/stellar-sdk version.",
982
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
983
+ "Expected output like 16.0.1."
984
+ );
985
+ }
986
+ return match[1];
987
+ }
988
+
989
+ // src/stellar-sdk/check-stellar-sdk-version.ts
990
+ async function readInstalledSdkVersion(cwd) {
991
+ try {
992
+ const pkgPath = path7.join(cwd, "node_modules", "@stellar", "stellar-sdk", "package.json");
993
+ const raw = await readFile3(pkgPath, "utf8");
994
+ const pkg = JSON.parse(raw);
995
+ return typeof pkg.version === "string" ? pkg.version : void 0;
996
+ } catch {
997
+ return void 0;
998
+ }
999
+ }
1000
+ async function resolveRegistrySdkVersion() {
1001
+ const result = await runCommand("npm", ["view", "@stellar/stellar-sdk", "version"], {
1002
+ skipStellarVersionCheck: true
1003
+ });
1004
+ return parseStellarSdkVersion(result.stdout || result.all);
1005
+ }
1006
+ async function checkStellarSdkVersion(input = {}) {
1007
+ const cwd = input.cwd ?? process.cwd();
1008
+ let version;
1009
+ try {
1010
+ const installed = await readInstalledSdkVersion(cwd);
1011
+ version = installed ?? await resolveRegistrySdkVersion();
1012
+ } catch (error) {
1013
+ if (error instanceof CaatingaError) {
1014
+ throw error;
1015
+ }
1016
+ throw new CaatingaError(
1017
+ "Could not resolve @stellar/stellar-sdk version.",
1018
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
1019
+ "Install @stellar/stellar-sdk in your project or ensure npm registry access.",
1020
+ error
1021
+ );
1022
+ }
1023
+ const report = evaluateStellarSdkCompatibility({
1024
+ version,
1025
+ lastTestedVersion: input.lastTestedVersion
1026
+ });
1027
+ for (const warning of report.warnings) {
1028
+ if (input.onWarning) {
1029
+ input.onWarning(warning);
1030
+ } else {
1031
+ defaultEmitWarning2(warning);
1032
+ }
1033
+ }
1034
+ return report;
1035
+ }
1036
+ function defaultEmitWarning2(warning) {
1037
+ const lines = [
1038
+ `Warning: ${warning.message}`,
1039
+ warning.remediation ? ` ${warning.remediation}` : void 0
1040
+ ].filter((line) => Boolean(line));
1041
+ process.stderr.write(`${lines.join("\n")}
1042
+ `);
1043
+ }
1044
+
764
1045
  // src/stellar-cli/build-stellar-network-args.ts
765
1046
  function matchesWellKnownNetwork(name, config) {
766
1047
  const known = WELL_KNOWN_NETWORKS[name];
@@ -899,7 +1180,7 @@ function validateSourceShape(source) {
899
1180
  }
900
1181
 
901
1182
  // src/contracts/resolve-contract.ts
902
- import path7 from "path";
1183
+ import path8 from "path";
903
1184
  function resolveContract(config, contractName, cwd = process.cwd()) {
904
1185
  const contract = config.contracts[contractName];
905
1186
  if (!contract) {
@@ -912,8 +1193,8 @@ function resolveContract(config, contractName, cwd = process.cwd()) {
912
1193
  return {
913
1194
  name: contractName,
914
1195
  config: contract,
915
- sourcePath: path7.resolve(cwd, contract.path),
916
- wasmPath: path7.resolve(cwd, contract.wasm)
1196
+ sourcePath: path8.resolve(cwd, contract.path),
1197
+ wasmPath: path8.resolve(cwd, contract.wasm)
917
1198
  };
918
1199
  }
919
1200
 
@@ -932,8 +1213,8 @@ function resolveDefaultContractName(config) {
932
1213
 
933
1214
  // src/contracts/wasm.ts
934
1215
  import { createHash } from "crypto";
935
- import { access as access2, readdir as readdir2, readFile as readFile3, stat } from "fs/promises";
936
- import path8 from "path";
1216
+ import { access as access2, readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
1217
+ import path9 from "path";
937
1218
  var LEGACY_RUST_WASM_TARGET = "wasm32-unknown-unknown";
938
1219
  var CURRENT_RUST_WASM_TARGET = "wasm32v1-none";
939
1220
  function toCurrentWasmTargetPath(wasmPath) {
@@ -964,18 +1245,18 @@ function wasmNotFoundError(configuredWasmPath, options) {
964
1245
  );
965
1246
  }
966
1247
  function toConfigRelativeWasmPath(absoluteWasmPath) {
967
- const relative = path8.relative(process.cwd(), absoluteWasmPath);
968
- return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(path8.sep).join("/")}`;
1248
+ const relative = path9.relative(process.cwd(), absoluteWasmPath);
1249
+ return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(path9.sep).join("/")}`;
969
1250
  }
970
1251
  function wasmFileName(configuredWasmPath) {
971
- return path8.basename(configuredWasmPath);
1252
+ return path9.basename(configuredWasmPath);
972
1253
  }
973
1254
  function buildAlternateWasmCandidates(configuredWasmPath, options) {
974
1255
  const fileName = wasmFileName(configuredWasmPath);
975
1256
  const candidates = [];
976
1257
  const seen = /* @__PURE__ */ new Set();
977
1258
  function addCandidate(candidate) {
978
- const resolved = path8.resolve(candidate);
1259
+ const resolved = path9.resolve(candidate);
979
1260
  if (seen.has(resolved)) {
980
1261
  return;
981
1262
  }
@@ -984,15 +1265,15 @@ function buildAlternateWasmCandidates(configuredWasmPath, options) {
984
1265
  }
985
1266
  const cargoTargetDir = process.env.CARGO_TARGET_DIR;
986
1267
  if (cargoTargetDir) {
987
- addCandidate(path8.join(cargoTargetDir, CURRENT_RUST_WASM_TARGET, "release", fileName));
988
- addCandidate(path8.join(cargoTargetDir, LEGACY_RUST_WASM_TARGET, "release", fileName));
1268
+ addCandidate(path9.join(cargoTargetDir, CURRENT_RUST_WASM_TARGET, "release", fileName));
1269
+ addCandidate(path9.join(cargoTargetDir, LEGACY_RUST_WASM_TARGET, "release", fileName));
989
1270
  }
990
1271
  if (options?.sourcePath) {
991
1272
  addCandidate(
992
- path8.join(options.sourcePath, "target", CURRENT_RUST_WASM_TARGET, "release", fileName)
1273
+ path9.join(options.sourcePath, "target", CURRENT_RUST_WASM_TARGET, "release", fileName)
993
1274
  );
994
1275
  addCandidate(
995
- path8.join(options.sourcePath, "target", LEGACY_RUST_WASM_TARGET, "release", fileName)
1276
+ path9.join(options.sourcePath, "target", LEGACY_RUST_WASM_TARGET, "release", fileName)
996
1277
  );
997
1278
  }
998
1279
  return candidates;
@@ -1009,7 +1290,7 @@ async function firstExistingPath(paths) {
1009
1290
  return void 0;
1010
1291
  }
1011
1292
  async function resolveWasmArtifactPath(configuredWasmPath, options) {
1012
- const resolvedConfiguredPath = path8.resolve(configuredWasmPath);
1293
+ const resolvedConfiguredPath = path9.resolve(configuredWasmPath);
1013
1294
  try {
1014
1295
  await access2(resolvedConfiguredPath);
1015
1296
  return resolvedConfiguredPath;
@@ -1033,7 +1314,7 @@ async function resolveWasmArtifactPath(configuredWasmPath, options) {
1033
1314
  }
1034
1315
  }
1035
1316
  async function hashWasm(wasmPath) {
1036
- const bytes = await readFile3(wasmPath);
1317
+ const bytes = await readFile4(wasmPath);
1037
1318
  return createHash("sha256").update(bytes).digest("hex");
1038
1319
  }
1039
1320
  async function getNewestMtimeInDirectory(directory) {
@@ -1046,7 +1327,7 @@ async function getNewestMtimeInDirectory(directory) {
1046
1327
  async function walk(dir) {
1047
1328
  const entries = await readdir2(dir, { withFileTypes: true });
1048
1329
  for (const entry of entries) {
1049
- const entryPath = path8.join(dir, entry.name);
1330
+ const entryPath = path9.join(dir, entry.name);
1050
1331
  if (entry.isDirectory()) {
1051
1332
  await walk(entryPath);
1052
1333
  continue;
@@ -1062,7 +1343,7 @@ async function getNewestMtimeInDirectory(directory) {
1062
1343
  return newest > 0 ? newest : void 0;
1063
1344
  }
1064
1345
  async function isWasmOlderThanSources(input) {
1065
- const srcDir = path8.join(input.contractPath, "src");
1346
+ const srcDir = path9.join(input.contractPath, "src");
1066
1347
  const newestSourceMtime = await getNewestMtimeInDirectory(srcDir);
1067
1348
  if (newestSourceMtime === void 0) {
1068
1349
  return false;
@@ -1137,7 +1418,38 @@ async function buildContract(options) {
1137
1418
  }
1138
1419
 
1139
1420
  // src/contracts/deploy-contract.ts
1140
- import path9 from "path";
1421
+ import path10 from "path";
1422
+
1423
+ // src/shell/is-transient-command-failure.ts
1424
+ var NO_RETRY_CAATINGA_SUBSTRINGS = [
1425
+ "CAATINGA_UNSUPPORTED_CLI_VERSION",
1426
+ "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
1427
+ "CAATINGA_STELLAR_CLI_NOT_FOUND",
1428
+ "CAATINGA_INVALID_CONFIG",
1429
+ "CAATINGA_CONFIG_NOT_FOUND"
1430
+ ];
1431
+ var TRANSIENT_COMMAND_FAILURE_PATTERN = /timeout|i\/o timeout|econnreset|connection reset|503|502|429|rate limit|temporar|bad gateway|fetch failed|network error|unavailable/i;
1432
+ function isTransientCommandFailure(logText) {
1433
+ if (!logText.trim()) {
1434
+ return false;
1435
+ }
1436
+ for (const marker of NO_RETRY_CAATINGA_SUBSTRINGS) {
1437
+ if (logText.includes(marker)) {
1438
+ return false;
1439
+ }
1440
+ }
1441
+ return TRANSIENT_COMMAND_FAILURE_PATTERN.test(logText);
1442
+ }
1443
+
1444
+ // src/contracts/is-transient-deploy-failure.ts
1445
+ function isTransientDeployFailure(error) {
1446
+ if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1447
+ return false;
1448
+ }
1449
+ const logText = `${error.message}
1450
+ ${error.hint ?? ""}`;
1451
+ return isTransientCommandFailure(logText);
1452
+ }
1141
1453
 
1142
1454
  // src/contracts/dependency-graph.ts
1143
1455
  function buildDependencyGraph(contracts) {
@@ -1199,6 +1511,12 @@ function resolveCliSource(explicit) {
1199
1511
  }
1200
1512
 
1201
1513
  // src/contracts/deploy-contract.ts
1514
+ var DEFAULT_DEPLOY_RETRY_DELAYS_MS = [2e3, 5e3];
1515
+ function sleep(ms) {
1516
+ return new Promise((resolve) => {
1517
+ setTimeout(resolve, ms);
1518
+ });
1519
+ }
1202
1520
  function toSnakeCaseFlag(key) {
1203
1521
  return key.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
1204
1522
  }
@@ -1243,7 +1561,7 @@ async function deployContract(options) {
1243
1561
  contract: contractWithWasm,
1244
1562
  network,
1245
1563
  contractId: existing.contractId,
1246
- artifactsPath: path9.resolve(cwd, "caatinga.artifacts.json"),
1564
+ artifactsPath: path10.resolve(cwd, "caatinga.artifacts.json"),
1247
1565
  output: "",
1248
1566
  skipped: true,
1249
1567
  staleWasmWarning
@@ -1283,40 +1601,69 @@ async function deployContract(options) {
1283
1601
  ...buildStellarNetworkArgs(network),
1284
1602
  ...constructorArgs
1285
1603
  ];
1286
- let output = "";
1287
- let contractId;
1288
- try {
1289
- const result = await runCommand("stellar", stellarArgs, {
1290
- cwd,
1291
- failureCode: CaatingaErrorCode.DEPLOY_FAILED
1292
- });
1293
- output = result.all || `${result.stdout}
1604
+ let deployOutcome;
1605
+ const retryDelaysMs = options.deployRetryDelaysMs ?? DEFAULT_DEPLOY_RETRY_DELAYS_MS;
1606
+ const maxDeployAttempts = retryDelaysMs.length + 1;
1607
+ for (let attempt = 0; attempt < maxDeployAttempts; attempt++) {
1608
+ try {
1609
+ const result = await runCommand("stellar", stellarArgs, {
1610
+ cwd,
1611
+ failureCode: CaatingaErrorCode.DEPLOY_FAILED
1612
+ });
1613
+ const output2 = result.all || `${result.stdout}
1294
1614
  ${result.stderr}`;
1295
- contractId = parseContractId(output);
1296
- } catch (error) {
1297
- if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1298
- throw error;
1299
- }
1300
- const recoveredContractId = await tryRecoverContractIdFromDeployFailure({
1301
- output: `${error.message}
1615
+ deployOutcome = {
1616
+ output: output2,
1617
+ contractId: parseContractId(output2)
1618
+ };
1619
+ break;
1620
+ } catch (error) {
1621
+ if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1622
+ throw error;
1623
+ }
1624
+ const recoveredContractId = await tryRecoverContractIdFromDeployFailure({
1625
+ output: `${error.message}
1302
1626
  ${error.hint ?? ""}`,
1303
- source,
1304
- network: network.config,
1305
- cwd
1306
- });
1307
- if (!recoveredContractId) {
1308
- throw error;
1627
+ source,
1628
+ network: network.config,
1629
+ cwd
1630
+ });
1631
+ if (recoveredContractId) {
1632
+ deployOutcome = {
1633
+ output: [
1634
+ error.hint ?? "",
1635
+ "Caatinga recovered the contract ID from the on-chain deploy transaction.",
1636
+ `Contract ID: ${recoveredContractId}`
1637
+ ].filter(Boolean).join("\n"),
1638
+ contractId: recoveredContractId
1639
+ };
1640
+ break;
1641
+ }
1642
+ const isLastAttempt = attempt === maxDeployAttempts - 1;
1643
+ if (!isTransientDeployFailure(error) || isLastAttempt) {
1644
+ throw error;
1645
+ }
1646
+ const delayMs = retryDelaysMs[attempt] ?? retryDelaysMs[retryDelaysMs.length - 1] ?? 0;
1647
+ options.onTransientDeployRetry?.({
1648
+ attempt: attempt + 1,
1649
+ maxAttempts: maxDeployAttempts,
1650
+ delayMs
1651
+ });
1652
+ await sleep(delayMs);
1309
1653
  }
1310
- contractId = recoveredContractId;
1311
- output = [
1312
- error.hint ?? "",
1313
- "Caatinga recovered the contract ID from the on-chain deploy transaction.",
1314
- `Contract ID: ${contractId}`
1315
- ].filter(Boolean).join("\n");
1316
1654
  }
1655
+ if (!deployOutcome) {
1656
+ throw new CaatingaError(
1657
+ "Deploy failed without a contract ID.",
1658
+ CaatingaErrorCode.DEPLOY_FAILED,
1659
+ "Re-run the deploy command with the underlying Stellar CLI for full diagnostics."
1660
+ );
1661
+ }
1662
+ const { output, contractId } = deployOutcome;
1317
1663
  const wasmHash = await hashWasm(wasmPath);
1318
1664
  const dependencyGraph = buildDependencyGraph(options.config.contracts);
1319
1665
  const dependencies = options.dependencies ?? contract.config.dependsOn;
1666
+ const supersedeReason = existing?.contractId && options.force ? options.upgrade ? "upgrade" : "force-redeploy" : void 0;
1320
1667
  const nextArtifacts = updateArtifact(
1321
1668
  artifactsBefore,
1322
1669
  network.name,
@@ -1330,7 +1677,7 @@ ${error.hint ?? ""}`,
1330
1677
  dependencies,
1331
1678
  resolvedDeployArgs
1332
1679
  },
1333
- { dependencyGraph }
1680
+ { dependencyGraph, supersedeReason }
1334
1681
  );
1335
1682
  const artifactsPath = await writeArtifacts(nextArtifacts, cwd);
1336
1683
  return {
@@ -1494,9 +1841,11 @@ async function deployContractGraph(options) {
1494
1841
  source: options.source,
1495
1842
  cwd,
1496
1843
  force: options.force,
1844
+ upgrade: options.upgrade,
1497
1845
  checkStaleWasm: options.checkStaleWasm,
1498
1846
  resolvedDeployArgs,
1499
- dependencies: contractConfig.dependsOn
1847
+ dependencies: contractConfig.dependsOn,
1848
+ onTransientDeployRetry: options.onTransientDeployRetry
1500
1849
  });
1501
1850
  if (result.staleWasmWarning) {
1502
1851
  staleWasmWarnings.push({
@@ -1520,11 +1869,11 @@ async function deployContractGraph(options) {
1520
1869
 
1521
1870
  // src/contracts/generate-bindings.ts
1522
1871
  import { access as access4, mkdir as mkdir2, unlink } from "fs/promises";
1523
- import path11 from "path";
1872
+ import path12 from "path";
1524
1873
 
1525
1874
  // src/bindings/patch-generated-binding-package.ts
1526
- import { access as access3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
1527
- import path10 from "path";
1875
+ import { access as access3, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
1876
+ import path11 from "path";
1528
1877
  var BUNDLER_ENTRY = "./src/index.ts";
1529
1878
  var ROOT_BINDING_INDEX_CONTENT = 'export * from "./src/index.js";\n';
1530
1879
  function resolveExportEntry(exportsField) {
@@ -1559,9 +1908,9 @@ function shouldPatchPackageJson(packageJson) {
1559
1908
  return pointsToDist(packageJson.main) || pointsToDist(packageJson.types) || !pointsToBundlerSource(exportEntry);
1560
1909
  }
1561
1910
  async function ensureRootBindingIndex(outputDir) {
1562
- const rootIndexPath = path10.join(outputDir, "index.ts");
1911
+ const rootIndexPath = path11.join(outputDir, "index.ts");
1563
1912
  try {
1564
- const existing = await readFile4(rootIndexPath, "utf8");
1913
+ const existing = await readFile5(rootIndexPath, "utf8");
1565
1914
  if (existing === ROOT_BINDING_INDEX_CONTENT) {
1566
1915
  return;
1567
1916
  }
@@ -1571,8 +1920,8 @@ async function ensureRootBindingIndex(outputDir) {
1571
1920
  }
1572
1921
  }
1573
1922
  async function patchGeneratedBindingPackage(outputDir) {
1574
- const packageJsonPath = path10.join(outputDir, "package.json");
1575
- const entryPath = path10.join(outputDir, "src", "index.ts");
1923
+ const packageJsonPath = path11.join(outputDir, "package.json");
1924
+ const entryPath = path11.join(outputDir, "src", "index.ts");
1576
1925
  try {
1577
1926
  await access3(entryPath);
1578
1927
  } catch {
@@ -1584,7 +1933,7 @@ async function patchGeneratedBindingPackage(outputDir) {
1584
1933
  }
1585
1934
  let raw;
1586
1935
  try {
1587
- raw = await readFile4(packageJsonPath, "utf8");
1936
+ raw = await readFile5(packageJsonPath, "utf8");
1588
1937
  } catch {
1589
1938
  throw new CaatingaError(
1590
1939
  "Generated binding package is missing package.json.",
@@ -1625,11 +1974,11 @@ function buildGenerateNetworkArgs(network) {
1625
1974
 
1626
1975
  // src/contracts/generate-bindings.ts
1627
1976
  function toBindingImportPath(bindingsOutput, contractName) {
1628
- const normalized = bindingsOutput.replace(/^\.\//, "").split(path11.sep).join("/");
1629
- return `./${path11.posix.join(normalized, contractName)}`;
1977
+ const normalized = bindingsOutput.replace(/^\.\//, "").split(path12.sep).join("/");
1978
+ return `./${path12.posix.join(normalized, contractName)}`;
1630
1979
  }
1631
1980
  async function removeLegacyBindingStub(cwd, bindingsOutput, contractName) {
1632
- const legacyPath = path11.resolve(cwd, bindingsOutput, `${contractName}.ts`);
1981
+ const legacyPath = path12.resolve(cwd, bindingsOutput, `${contractName}.ts`);
1633
1982
  try {
1634
1983
  await access4(legacyPath);
1635
1984
  await unlink(legacyPath);
@@ -1657,8 +2006,9 @@ async function generateBindings(options) {
1657
2006
  "Run caatinga deploy for this contract and network before generating bindings."
1658
2007
  );
1659
2008
  }
1660
- const outputDir = path11.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
2009
+ const outputDir = path12.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
1661
2010
  await mkdir2(outputDir, { recursive: true });
2011
+ await checkStellarSdkVersion({ cwd });
1662
2012
  const result = await runCommand(
1663
2013
  "npx",
1664
2014
  [
@@ -1883,14 +2233,172 @@ async function readContract(options) {
1883
2233
  };
1884
2234
  }
1885
2235
 
2236
+ // src/contracts/estimate-deploy-cost.ts
2237
+ import path13 from "path";
2238
+ function toSnakeCaseFlag2(key) {
2239
+ return key.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
2240
+ }
2241
+ function formatConstructorCliArgs2(resolved) {
2242
+ const entries = Object.entries(resolved);
2243
+ if (entries.length === 0) {
2244
+ return [];
2245
+ }
2246
+ const tail = ["--"];
2247
+ for (const [key, value] of entries) {
2248
+ tail.push(`--${toSnakeCaseFlag2(key)}`, String(value));
2249
+ }
2250
+ return tail;
2251
+ }
2252
+ function parseFeeStroops(output) {
2253
+ const inclusionMatch = output.match(/inclusion[_\s-]*fee[:\s]+(\d+)/i);
2254
+ const resourceMatch = output.match(/resource[_\s-]*fee[:\s]+(\d+)/i);
2255
+ const totalMatch = output.match(/total[_\s-]*fee[:\s]+(\d+)/i);
2256
+ return {
2257
+ inclusion: inclusionMatch ? Number(inclusionMatch[1]) : void 0,
2258
+ resource: resourceMatch ? Number(resourceMatch[1]) : void 0,
2259
+ ...totalMatch && !resourceMatch ? { resource: Number(totalMatch[1]) } : {}
2260
+ };
2261
+ }
2262
+ async function estimateDeployCost(options) {
2263
+ const cwd = options.cwd ?? process.cwd();
2264
+ const contract = resolveContract(options.config, options.contractName, cwd);
2265
+ const network = resolveNetwork(options.config, options.networkName);
2266
+ const source = assertSafeSourceAccount(options.source);
2267
+ await checkBinary("stellar", "Install Stellar CLI before running caatinga estimate.");
2268
+ const wasmPath = await resolveWasmArtifactPath(contract.wasmPath, {
2269
+ sourcePath: contract.sourcePath
2270
+ });
2271
+ const artifacts = await readArtifacts(cwd);
2272
+ const rawDeployArgs = contract.config.deployArgs;
2273
+ const resolvedDeployArgs = Object.keys(rawDeployArgs).length > 0 ? resolveDeployArgs({
2274
+ deployArgs: rawDeployArgs,
2275
+ artifacts,
2276
+ network: network.name
2277
+ }) : {};
2278
+ const constructorArgs = formatConstructorCliArgs2(resolvedDeployArgs);
2279
+ const deployArgs = [
2280
+ "contract",
2281
+ "deploy",
2282
+ "--wasm",
2283
+ wasmPath,
2284
+ "--source-account",
2285
+ source,
2286
+ "--build-only",
2287
+ ...buildStellarNetworkArgs(network),
2288
+ ...constructorArgs
2289
+ ];
2290
+ let buildOutput;
2291
+ try {
2292
+ const buildResult = await runCommand("stellar", deployArgs, {
2293
+ cwd,
2294
+ failureCode: CaatingaErrorCode.ESTIMATE_FAILED
2295
+ });
2296
+ buildOutput = (buildResult.stdout || buildResult.all).trim();
2297
+ } catch (error) {
2298
+ if (error instanceof CaatingaError) {
2299
+ throw new CaatingaError(
2300
+ `Deploy cost estimate failed for "${contract.name}".`,
2301
+ CaatingaErrorCode.ESTIMATE_FAILED,
2302
+ error.hint ?? "Ensure WASM is built and deploy args resolve correctly.",
2303
+ error.cause
2304
+ );
2305
+ }
2306
+ throw error;
2307
+ }
2308
+ const simulateArgs = ["tx", "simulate", "--source-account", source, buildOutput];
2309
+ let simulateOutput = "";
2310
+ try {
2311
+ const simulateResult = await runCommand("stellar", simulateArgs, {
2312
+ cwd,
2313
+ failureCode: CaatingaErrorCode.ESTIMATE_FAILED
2314
+ });
2315
+ simulateOutput = simulateResult.all || `${simulateResult.stdout}
2316
+ ${simulateResult.stderr}`;
2317
+ } catch {
2318
+ simulateOutput = "";
2319
+ }
2320
+ const parsed = parseFeeStroops(simulateOutput);
2321
+ const inclusionFeeStroops = parsed.inclusion ?? 100;
2322
+ const resourceFeeStroops = parsed.resource;
2323
+ const totalFeeStroops = inclusionFeeStroops + (resourceFeeStroops ?? 0);
2324
+ return {
2325
+ contractName: contract.name,
2326
+ network: network.name,
2327
+ wasmPath: path13.relative(cwd, wasmPath) || wasmPath,
2328
+ inclusionFeeStroops,
2329
+ resourceFeeStroops,
2330
+ totalFeeStroops,
2331
+ advisory: "Advisory estimate only \u2014 actual fees may differ under network congestion or contract complexity.",
2332
+ rawOutput: simulateOutput || buildOutput
2333
+ };
2334
+ }
2335
+
2336
+ // src/contracts/inspect-contract.ts
2337
+ async function inspectContract(options) {
2338
+ const cwd = options.cwd ?? process.cwd();
2339
+ const contract = resolveContract(options.config, options.contractName, cwd);
2340
+ const network = resolveNetwork(options.config, options.networkName);
2341
+ const artifacts = await readArtifacts(cwd);
2342
+ const artifact = artifacts.networks[network.name]?.contracts[contract.name];
2343
+ if (!artifact) {
2344
+ throw new CaatingaError(
2345
+ `No deployed artifact found for "${contract.name}" on "${network.name}".`,
2346
+ CaatingaErrorCode.ARTIFACT_NOT_FOUND,
2347
+ "Run caatinga deploy before inspect."
2348
+ );
2349
+ }
2350
+ await checkBinary("stellar", "Install Stellar CLI before running caatinga inspect.");
2351
+ let reachable = false;
2352
+ let detail;
2353
+ try {
2354
+ await verifyDependencyContract({
2355
+ dependencyName: contract.name,
2356
+ contractId: artifact.contractId,
2357
+ network,
2358
+ cwd
2359
+ });
2360
+ reachable = true;
2361
+ detail = "Contract interface reachable on network.";
2362
+ } catch (error) {
2363
+ reachable = false;
2364
+ detail = error instanceof CaatingaError ? error.message : "Contract not reachable on network.";
2365
+ }
2366
+ let localHash;
2367
+ try {
2368
+ const wasmPath = await resolveWasmArtifactPath(contract.wasmPath, {
2369
+ sourcePath: contract.sourcePath
2370
+ });
2371
+ localHash = await hashWasm(wasmPath);
2372
+ } catch {
2373
+ localHash = void 0;
2374
+ }
2375
+ return {
2376
+ contractName: contract.name,
2377
+ network: network.name,
2378
+ artifact: {
2379
+ contractId: artifact.contractId,
2380
+ wasmHash: artifact.wasmHash,
2381
+ deployedAt: artifact.deployedAt,
2382
+ historyCount: artifact.history?.length ?? 0
2383
+ },
2384
+ onChain: { reachable, detail },
2385
+ localWasm: {
2386
+ path: contract.config.wasm,
2387
+ hash: localHash,
2388
+ matchesArtifact: Boolean(localHash && localHash === artifact.wasmHash)
2389
+ },
2390
+ dependencies: artifact.dependencies ?? contract.config.dependsOn ?? []
2391
+ };
2392
+ }
2393
+
1886
2394
  // src/templates/create-project-from-template.ts
1887
- import { cp, mkdir as mkdir3, readFile as readFile5, readdir as readdir3, stat as stat2, writeFile as writeFile4 } from "fs/promises";
1888
- import path12 from "path";
2395
+ import { cp, mkdir as mkdir3, readFile as readFile6, readdir as readdir3, stat as stat2, writeFile as writeFile4 } from "fs/promises";
2396
+ import path14 from "path";
1889
2397
  import { z as z7 } from "zod";
1890
2398
 
1891
2399
  // src/templates/template-manifest.schema.ts
1892
2400
  import { z as z6 } from "zod";
1893
- import semver3 from "semver";
2401
+ import semver5 from "semver";
1894
2402
  var CURRENT_TEMPLATE_VERSION = 1;
1895
2403
  var TemplateManifestSchema = z6.object({
1896
2404
  name: z6.string().min(1),
@@ -1914,14 +2422,14 @@ var TemplateManifestSchema = z6.object({
1914
2422
  })
1915
2423
  });
1916
2424
  function defaultCompatibleCoreRange(coreVersion = CAATINGA_CORE_VERSION) {
1917
- const version = semver3.valid(semver3.coerce(coreVersion));
2425
+ const version = semver5.valid(semver5.coerce(coreVersion));
1918
2426
  if (!version) {
1919
2427
  throw new Error(`Invalid core version: ${coreVersion}`);
1920
2428
  }
1921
2429
  return `^${version}`;
1922
2430
  }
1923
2431
  function isCoreVersionCompatible(range, coreVersion = CAATINGA_CORE_VERSION) {
1924
- return semver3.satisfies(coreVersion, range);
2432
+ return semver5.satisfies(coreVersion, range);
1925
2433
  }
1926
2434
  function getTemplateCompatibilityIssue(manifest, coreVersion = CAATINGA_CORE_VERSION) {
1927
2435
  if (manifest.caatinga.templateVersion !== CURRENT_TEMPLATE_VERSION) {
@@ -1956,8 +2464,8 @@ function formatTemplateCompatibilityHint(issue) {
1956
2464
  // src/templates/create-project-from-template.ts
1957
2465
  var TEMPLATE_COPY_EXCLUDED_DIRS = /* @__PURE__ */ new Set(["target", "test_snapshots", "node_modules", ".git"]);
1958
2466
  async function createProjectFromTemplate(options) {
1959
- const targetDir = path12.resolve(options.targetDir);
1960
- const templateDir = path12.resolve(options.templateDir);
2467
+ const targetDir = path14.resolve(options.targetDir);
2468
+ const templateDir = path14.resolve(options.templateDir);
1961
2469
  try {
1962
2470
  await stat2(templateDir);
1963
2471
  } catch {
@@ -1998,9 +2506,9 @@ async function ensureArtifacts(targetDir, projectName) {
1998
2506
  }
1999
2507
  }
2000
2508
  async function readTemplateManifest(templateDir) {
2001
- const manifestPath = path12.join(templateDir, "caatinga.template.json");
2509
+ const manifestPath = path14.join(templateDir, "caatinga.template.json");
2002
2510
  try {
2003
- const rawManifest = await readFile5(manifestPath, "utf8");
2511
+ const rawManifest = await readFile6(manifestPath, "utf8");
2004
2512
  const manifest = TemplateManifestSchema.parse(JSON.parse(rawManifest));
2005
2513
  const compatibilityIssue = getTemplateCompatibilityIssue(manifest);
2006
2514
  if (compatibilityIssue) {
@@ -2036,7 +2544,7 @@ async function replaceTemplateVariables(dir, projectName) {
2036
2544
  const entries = await readdir3(dir);
2037
2545
  await Promise.all(
2038
2546
  entries.map(async (entry) => {
2039
- const entryPath = path12.join(dir, entry);
2547
+ const entryPath = path14.join(dir, entry);
2040
2548
  const entryStat = await stat2(entryPath);
2041
2549
  if (entryStat.isDirectory()) {
2042
2550
  await replaceTemplateVariables(entryPath, projectName);
@@ -2045,38 +2553,38 @@ async function replaceTemplateVariables(dir, projectName) {
2045
2553
  if (!isTextTemplateFile(entryPath)) {
2046
2554
  return;
2047
2555
  }
2048
- const content = await readFile5(entryPath, "utf8");
2556
+ const content = await readFile6(entryPath, "utf8");
2049
2557
  await writeFile4(entryPath, content.replaceAll("__PROJECT_NAME__", projectName), "utf8");
2050
2558
  })
2051
2559
  );
2052
2560
  }
2053
2561
  function shouldCopyTemplateEntry(templateDir, source, userFilter) {
2054
- const relativePath = path12.relative(templateDir, source);
2562
+ const relativePath = path14.relative(templateDir, source);
2055
2563
  if (!relativePath || relativePath === ".") {
2056
2564
  return true;
2057
2565
  }
2058
- const normalizedPath = relativePath.split(path12.sep).join("/");
2566
+ const normalizedPath = relativePath.split(path14.sep).join("/");
2059
2567
  if (userFilter && !userFilter(normalizedPath)) {
2060
2568
  return false;
2061
2569
  }
2062
- return !relativePath.split(path12.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
2570
+ return !relativePath.split(path14.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
2063
2571
  }
2064
2572
  function isTextTemplateFile(filePath) {
2065
2573
  return [".json", ".md", ".rs", ".toml", ".ts", ".tsx", ".css", ".html"].includes(
2066
- path12.extname(filePath)
2574
+ path14.extname(filePath)
2067
2575
  );
2068
2576
  }
2069
2577
 
2070
2578
  // src/scaffold/create-zk-project.ts
2071
2579
  import { cp as cp2, mkdir as mkdir4, writeFile as writeFile5 } from "fs/promises";
2072
2580
  import { existsSync as existsSync2 } from "fs";
2073
- import path13 from "path";
2581
+ import path15 from "path";
2074
2582
  import { fileURLToPath } from "url";
2075
- var moduleDir = typeof __dirname === "string" ? __dirname : path13.dirname(fileURLToPath(import.meta.url));
2583
+ var moduleDir = typeof __dirname === "string" ? __dirname : path15.dirname(fileURLToPath(import.meta.url));
2076
2584
  function scaffoldRoot() {
2077
2585
  const candidates = [
2078
- path13.resolve(moduleDir, "../../scaffolds"),
2079
- path13.resolve(moduleDir, "../scaffolds")
2586
+ path15.resolve(moduleDir, "../../scaffolds"),
2587
+ path15.resolve(moduleDir, "../scaffolds")
2080
2588
  ];
2081
2589
  const found = candidates.find((candidate) => existsSync2(candidate));
2082
2590
  return found ?? candidates[0];
@@ -2167,39 +2675,39 @@ Replace \`circuits/main.circom\` with your circuit. Keep the entry point named \
2167
2675
  `;
2168
2676
  }
2169
2677
  async function createZkProject(options) {
2170
- const targetDir = path13.resolve(options.targetDir);
2678
+ const targetDir = path15.resolve(options.targetDir);
2171
2679
  const force = options.force ?? false;
2172
2680
  const projectFiles = options.projectFiles ?? true;
2173
2681
  await mkdir4(targetDir, { recursive: true });
2174
2682
  if (projectFiles) {
2175
2683
  await Promise.all([
2176
- writeFile5(path13.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), {
2684
+ writeFile5(path15.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), {
2177
2685
  encoding: "utf8",
2178
2686
  flag: force ? "w" : "wx"
2179
2687
  }),
2180
- writeFile5(path13.join(targetDir, "package.json"), packageJsonSource(options.projectName), {
2688
+ writeFile5(path15.join(targetDir, "package.json"), packageJsonSource(options.projectName), {
2181
2689
  encoding: "utf8",
2182
2690
  flag: force ? "w" : "wx"
2183
2691
  }),
2184
- writeFile5(path13.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2692
+ writeFile5(path15.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2185
2693
  encoding: "utf8",
2186
2694
  flag: force ? "w" : "wx"
2187
2695
  }),
2188
- writeFile5(path13.join(targetDir, "README.md"), readmeSource(options.projectName), {
2696
+ writeFile5(path15.join(targetDir, "README.md"), readmeSource(options.projectName), {
2189
2697
  encoding: "utf8",
2190
2698
  flag: force ? "w" : "wx"
2191
2699
  })
2192
2700
  ]);
2193
2701
  }
2194
- await mkdir4(path13.join(targetDir, "contracts"), { recursive: true });
2195
- await cp2(path13.join(scaffoldRoot(), "zk-circuit-stub"), path13.join(targetDir, "circuits"), {
2702
+ await mkdir4(path15.join(targetDir, "contracts"), { recursive: true });
2703
+ await cp2(path15.join(scaffoldRoot(), "zk-circuit-stub"), path15.join(targetDir, "circuits"), {
2196
2704
  recursive: true,
2197
2705
  force,
2198
2706
  errorOnExist: !force
2199
2707
  });
2200
2708
  await cp2(
2201
- path13.join(scaffoldRoot(), "zk-verifier"),
2202
- path13.join(targetDir, "contracts", "verifier"),
2709
+ path15.join(scaffoldRoot(), "zk-verifier"),
2710
+ path15.join(targetDir, "contracts", "verifier"),
2203
2711
  {
2204
2712
  recursive: true,
2205
2713
  force,
@@ -2218,13 +2726,13 @@ async function createZkProject(options) {
2218
2726
  // src/scaffold/create-minimal-project.ts
2219
2727
  import { cp as cp3, mkdir as mkdir5, writeFile as writeFile6 } from "fs/promises";
2220
2728
  import { existsSync as existsSync3 } from "fs";
2221
- import path14 from "path";
2729
+ import path16 from "path";
2222
2730
  import { fileURLToPath as fileURLToPath2 } from "url";
2223
- var moduleDir2 = typeof __dirname === "string" ? __dirname : path14.dirname(fileURLToPath2(import.meta.url));
2731
+ var moduleDir2 = typeof __dirname === "string" ? __dirname : path16.dirname(fileURLToPath2(import.meta.url));
2224
2732
  function scaffoldRoot2() {
2225
2733
  const candidates = [
2226
- path14.resolve(moduleDir2, "../../scaffolds"),
2227
- path14.resolve(moduleDir2, "../scaffolds")
2734
+ path16.resolve(moduleDir2, "../../scaffolds"),
2735
+ path16.resolve(moduleDir2, "../scaffolds")
2228
2736
  ];
2229
2737
  const found = candidates.find((candidate) => existsSync3(candidate));
2230
2738
  return found ?? candidates[0];
@@ -2315,31 +2823,31 @@ Edit \`contracts/app/src/lib.rs\` to customize the contract. Add a frontend late
2315
2823
  `;
2316
2824
  }
2317
2825
  async function createMinimalProject(options) {
2318
- const targetDir = path14.resolve(options.targetDir);
2826
+ const targetDir = path16.resolve(options.targetDir);
2319
2827
  const force = options.force ?? false;
2320
2828
  await mkdir5(targetDir, { recursive: true });
2321
2829
  await Promise.all([
2322
- writeFile6(path14.join(targetDir, "caatinga.config.ts"), configSource2(options.projectName), {
2830
+ writeFile6(path16.join(targetDir, "caatinga.config.ts"), configSource2(options.projectName), {
2323
2831
  encoding: "utf8",
2324
2832
  flag: force ? "w" : "wx"
2325
2833
  }),
2326
- writeFile6(path14.join(targetDir, "package.json"), packageJsonSource2(options.projectName), {
2834
+ writeFile6(path16.join(targetDir, "package.json"), packageJsonSource2(options.projectName), {
2327
2835
  encoding: "utf8",
2328
2836
  flag: force ? "w" : "wx"
2329
2837
  }),
2330
- writeFile6(path14.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2838
+ writeFile6(path16.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2331
2839
  encoding: "utf8",
2332
2840
  flag: force ? "w" : "wx"
2333
2841
  }),
2334
- writeFile6(path14.join(targetDir, "README.md"), readmeSource2(options.projectName), {
2842
+ writeFile6(path16.join(targetDir, "README.md"), readmeSource2(options.projectName), {
2335
2843
  encoding: "utf8",
2336
2844
  flag: force ? "w" : "wx"
2337
2845
  })
2338
2846
  ]);
2339
- await mkdir5(path14.join(targetDir, "contracts"), { recursive: true });
2847
+ await mkdir5(path16.join(targetDir, "contracts"), { recursive: true });
2340
2848
  await cp3(
2341
- path14.join(scaffoldRoot2(), "soroban-contract-stub"),
2342
- path14.join(targetDir, "contracts", "app"),
2849
+ path16.join(scaffoldRoot2(), "soroban-contract-stub"),
2850
+ path16.join(targetDir, "contracts", "app"),
2343
2851
  {
2344
2852
  recursive: true,
2345
2853
  force,
@@ -2354,29 +2862,14 @@ async function createMinimalProject(options) {
2354
2862
  }
2355
2863
 
2356
2864
  // src/ci/is-transient-testnet-smoke-failure.ts
2357
- var NO_RETRY_CAATINGA_SUBSTRINGS = [
2358
- "CAATINGA_UNSUPPORTED_CLI_VERSION",
2359
- "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
2360
- "CAATINGA_STELLAR_CLI_NOT_FOUND",
2361
- "CAATINGA_INVALID_CONFIG",
2362
- "CAATINGA_CONFIG_NOT_FOUND"
2363
- ];
2364
- var TRANSIENT_PATTERN = /timeout|i\/o timeout|econnreset|connection reset|503|502|429|rate limit|temporar|bad gateway|fetch failed|network error|unavailable/i;
2365
2865
  function isTransientTestnetSmokeFailure(logText) {
2366
- if (!logText.trim()) {
2367
- return false;
2368
- }
2369
- for (const marker of NO_RETRY_CAATINGA_SUBSTRINGS) {
2370
- if (logText.includes(marker)) {
2371
- return false;
2372
- }
2373
- }
2374
- return TRANSIENT_PATTERN.test(logText);
2866
+ return isTransientCommandFailure(logText);
2375
2867
  }
2376
2868
  export {
2377
2869
  BINDING_MARKER_FILENAME,
2378
2870
  BindingMarkerSchema,
2379
2871
  CAATINGA_CORE_VERSION,
2872
+ CURRENT_ARTIFACTS_SCHEMA_VERSION,
2380
2873
  CaatingaArtifactsSchema,
2381
2874
  CaatingaConfigSchema,
2382
2875
  CaatingaError,
@@ -2384,6 +2877,8 @@ export {
2384
2877
  READ_CALL_FAILURE_REGEX,
2385
2878
  STELLAR_CLI_LAST_TESTED_VERSION,
2386
2879
  STELLAR_CLI_MIN_VERSION,
2880
+ STELLAR_SDK_LAST_TESTED_VERSION,
2881
+ STELLAR_SDK_MIN_VERSION,
2387
2882
  TemplateManifestSchema,
2388
2883
  WELL_KNOWN_NETWORKS,
2389
2884
  buildContract,
@@ -2391,6 +2886,7 @@ export {
2391
2886
  buildReadCallHint,
2392
2887
  checkBinary,
2393
2888
  checkStellarCliVersion,
2889
+ checkStellarSdkVersion,
2394
2890
  collectProjectStatus,
2395
2891
  createInitialArtifacts,
2396
2892
  createMinimalProject,
@@ -2399,20 +2895,26 @@ export {
2399
2895
  defineConfig,
2400
2896
  deployContract,
2401
2897
  deployContractGraph,
2898
+ estimateDeployCost,
2402
2899
  evaluateBindingFreshness,
2403
2900
  evaluateBindingsFreshness,
2404
2901
  evaluateStellarCliCompatibility,
2902
+ evaluateStellarSdkCompatibility,
2405
2903
  formatCaatingaError,
2406
2904
  generateBindings,
2407
2905
  generateBindingsGraph,
2906
+ inspectContract,
2408
2907
  invokeContract,
2409
2908
  isCargoBinMissingFromPath,
2410
2909
  isReadCallFailure,
2411
2910
  isTransientTestnetSmokeFailure,
2412
2911
  loadConfig,
2912
+ migrateArtifactsFile,
2913
+ migrateArtifactsToV2,
2413
2914
  parseContractId,
2414
2915
  parseInvokeTarget,
2415
2916
  parseStellarCliVersion,
2917
+ parseStellarSdkVersion,
2416
2918
  readArtifacts,
2417
2919
  readBindingMarker,
2418
2920
  readContract,
@@ -2422,6 +2924,8 @@ export {
2422
2924
  resolveDeployOrder,
2423
2925
  resolveNetwork,
2424
2926
  resolveSubprocessEnv,
2927
+ restoreArtifactFromHistory,
2928
+ rollbackContractArtifact,
2425
2929
  runCommand,
2426
2930
  toCaatingaError,
2427
2931
  updateArtifact,