@caatinga/core 3.2.0 → 3.3.1

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.cjs CHANGED
@@ -33,13 +33,17 @@ __export(index_exports, {
33
33
  BINDING_MARKER_FILENAME: () => BINDING_MARKER_FILENAME,
34
34
  BindingMarkerSchema: () => BindingMarkerSchema,
35
35
  CAATINGA_CORE_VERSION: () => CAATINGA_CORE_VERSION,
36
+ CURRENT_ARTIFACTS_SCHEMA_VERSION: () => CURRENT_ARTIFACTS_SCHEMA_VERSION,
36
37
  CaatingaArtifactsSchema: () => CaatingaArtifactsSchema,
37
38
  CaatingaConfigSchema: () => CaatingaConfigSchema,
38
39
  CaatingaError: () => CaatingaError,
39
40
  CaatingaErrorCode: () => CaatingaErrorCode,
41
+ DEFAULT_CLI_SOURCE: () => DEFAULT_CLI_SOURCE,
40
42
  READ_CALL_FAILURE_REGEX: () => READ_CALL_FAILURE_REGEX,
41
43
  STELLAR_CLI_LAST_TESTED_VERSION: () => STELLAR_CLI_LAST_TESTED_VERSION,
42
44
  STELLAR_CLI_MIN_VERSION: () => STELLAR_CLI_MIN_VERSION,
45
+ STELLAR_SDK_LAST_TESTED_VERSION: () => STELLAR_SDK_LAST_TESTED_VERSION,
46
+ STELLAR_SDK_MIN_VERSION: () => STELLAR_SDK_MIN_VERSION,
43
47
  TemplateManifestSchema: () => TemplateManifestSchema,
44
48
  WELL_KNOWN_NETWORKS: () => WELL_KNOWN_NETWORKS,
45
49
  buildContract: () => buildContract,
@@ -47,6 +51,7 @@ __export(index_exports, {
47
51
  buildReadCallHint: () => buildReadCallHint,
48
52
  checkBinary: () => checkBinary,
49
53
  checkStellarCliVersion: () => checkStellarCliVersion,
54
+ checkStellarSdkVersion: () => checkStellarSdkVersion,
50
55
  collectProjectStatus: () => collectProjectStatus,
51
56
  createInitialArtifacts: () => createInitialArtifacts,
52
57
  createMinimalProject: () => createMinimalProject,
@@ -55,20 +60,27 @@ __export(index_exports, {
55
60
  defineConfig: () => defineConfig,
56
61
  deployContract: () => deployContract,
57
62
  deployContractGraph: () => deployContractGraph,
63
+ describeCliSource: () => describeCliSource,
64
+ estimateDeployCost: () => estimateDeployCost,
58
65
  evaluateBindingFreshness: () => evaluateBindingFreshness,
59
66
  evaluateBindingsFreshness: () => evaluateBindingsFreshness,
60
67
  evaluateStellarCliCompatibility: () => evaluateStellarCliCompatibility,
68
+ evaluateStellarSdkCompatibility: () => evaluateStellarSdkCompatibility,
61
69
  formatCaatingaError: () => formatCaatingaError,
62
70
  generateBindings: () => generateBindings,
63
71
  generateBindingsGraph: () => generateBindingsGraph,
72
+ inspectContract: () => inspectContract,
64
73
  invokeContract: () => invokeContract,
65
74
  isCargoBinMissingFromPath: () => isCargoBinMissingFromPath,
66
75
  isReadCallFailure: () => isReadCallFailure,
67
76
  isTransientTestnetSmokeFailure: () => isTransientTestnetSmokeFailure,
68
77
  loadConfig: () => loadConfig,
78
+ migrateArtifactsFile: () => migrateArtifactsFile,
79
+ migrateArtifactsToV2: () => migrateArtifactsToV2,
69
80
  parseContractId: () => parseContractId,
70
81
  parseInvokeTarget: () => parseInvokeTarget,
71
82
  parseStellarCliVersion: () => parseStellarCliVersion,
83
+ parseStellarSdkVersion: () => parseStellarSdkVersion,
72
84
  readArtifacts: () => readArtifacts,
73
85
  readBindingMarker: () => readBindingMarker,
74
86
  readContract: () => readContract,
@@ -78,6 +90,8 @@ __export(index_exports, {
78
90
  resolveDeployOrder: () => resolveDeployOrder,
79
91
  resolveNetwork: () => resolveNetwork,
80
92
  resolveSubprocessEnv: () => resolveSubprocessEnv,
93
+ restoreArtifactFromHistory: () => restoreArtifactFromHistory,
94
+ rollbackContractArtifact: () => rollbackContractArtifact,
81
95
  runCommand: () => runCommand,
82
96
  toCaatingaError: () => toCaatingaError,
83
97
  updateArtifact: () => updateArtifact,
@@ -97,6 +111,8 @@ var CaatingaErrorCode = {
97
111
  STELLAR_CLI_NOT_FOUND: "CAATINGA_STELLAR_CLI_NOT_FOUND",
98
112
  STELLAR_CLI_VERSION_PARSE_FAILED: "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
99
113
  UNSUPPORTED_CLI_VERSION: "CAATINGA_UNSUPPORTED_CLI_VERSION",
114
+ STELLAR_SDK_VERSION_PARSE_FAILED: "CAATINGA_STELLAR_SDK_VERSION_PARSE_FAILED",
115
+ UNSUPPORTED_SDK_VERSION: "CAATINGA_UNSUPPORTED_SDK_VERSION",
100
116
  RUST_NOT_FOUND: "CAATINGA_RUST_NOT_FOUND",
101
117
  RUST_TARGET_NOT_FOUND: "CAATINGA_RUST_TARGET_NOT_FOUND",
102
118
  DEPLOY_FAILED: "CAATINGA_DEPLOY_FAILED",
@@ -139,6 +155,8 @@ var CaatingaErrorCode = {
139
155
  ZK_VERIFICATION_FAILED: "CAATINGA_ZK_VERIFICATION_FAILED",
140
156
  ZK_DEV_CEREMONY_BLOCKED: "CAATINGA_ZK_DEV_CEREMONY_BLOCKED",
141
157
  DOCTOR_PARTIAL_DEPLOY: "CAATINGA_DOCTOR_PARTIAL_DEPLOY",
158
+ ROLLBACK_TARGET_NOT_FOUND: "CAATINGA_ROLLBACK_TARGET_NOT_FOUND",
159
+ ESTIMATE_FAILED: "CAATINGA_ESTIMATE_FAILED",
142
160
  MULTI_AUTH_REQUIRED: "CAATINGA_MULTI_AUTH_REQUIRED"
143
161
  };
144
162
 
@@ -327,6 +345,14 @@ async function loadConfig(options = {}) {
327
345
 
328
346
  // src/artifacts/artifact.schema.ts
329
347
  var import_zod3 = require("zod");
348
+ var ArtifactSupersedeReasonSchema = import_zod3.z.enum(["upgrade", "rollback", "force-redeploy"]);
349
+ var ContractArtifactHistoryEntrySchema = import_zod3.z.object({
350
+ contractId: import_zod3.z.string().min(1),
351
+ wasmHash: import_zod3.z.string().min(1),
352
+ deployedAt: import_zod3.z.string().datetime(),
353
+ supersededAt: import_zod3.z.string().datetime(),
354
+ reason: ArtifactSupersedeReasonSchema.optional()
355
+ });
330
356
  var ContractArtifactSchema = import_zod3.z.object({
331
357
  contractId: import_zod3.z.string().min(1),
332
358
  wasmHash: import_zod3.z.string().min(1),
@@ -334,17 +360,28 @@ var ContractArtifactSchema = import_zod3.z.object({
334
360
  sourcePath: import_zod3.z.string().min(1),
335
361
  wasmPath: import_zod3.z.string().min(1),
336
362
  dependencies: import_zod3.z.array(import_zod3.z.string().min(1)).default([]),
337
- resolvedDeployArgs: import_zod3.z.record(import_zod3.z.string().min(1), import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean()])).default({})
363
+ resolvedDeployArgs: import_zod3.z.record(import_zod3.z.string().min(1), import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean()])).default({}),
364
+ history: import_zod3.z.array(ContractArtifactHistoryEntrySchema).optional()
338
365
  });
339
366
  var NetworkArtifactsSchema = import_zod3.z.object({
340
367
  contracts: import_zod3.z.record(import_zod3.z.string().min(1), ContractArtifactSchema).default({}),
341
368
  dependencyGraph: import_zod3.z.record(import_zod3.z.string().min(1), import_zod3.z.array(import_zod3.z.string().min(1))).default({})
342
369
  });
343
- var CaatingaArtifactsSchema = import_zod3.z.object({
370
+ var CaatingaArtifactsBaseSchema = import_zod3.z.object({
344
371
  project: import_zod3.z.string().min(1),
345
- version: import_zod3.z.literal(1),
346
372
  networks: import_zod3.z.record(import_zod3.z.string().min(1), NetworkArtifactsSchema).default({})
347
373
  });
374
+ var CaatingaArtifactsV1Schema = CaatingaArtifactsBaseSchema.extend({
375
+ version: import_zod3.z.literal(1)
376
+ });
377
+ var CaatingaArtifactsV2Schema = CaatingaArtifactsBaseSchema.extend({
378
+ version: import_zod3.z.literal(2)
379
+ });
380
+ var CaatingaArtifactsSchema = import_zod3.z.union([
381
+ CaatingaArtifactsV1Schema,
382
+ CaatingaArtifactsV2Schema
383
+ ]);
384
+ var CURRENT_ARTIFACTS_SCHEMA_VERSION = 2;
348
385
 
349
386
  // src/artifacts/read-artifacts.ts
350
387
  var import_promises2 = require("fs/promises");
@@ -396,29 +433,139 @@ function createInitialArtifacts(project, options = {}) {
396
433
  );
397
434
  return {
398
435
  project,
399
- version: 1,
436
+ version: 2,
400
437
  networks
401
438
  };
402
439
  }
403
440
 
404
441
  // src/artifacts/update-artifact.ts
405
- function updateArtifact(artifacts, networkName, contractName, contractArtifact, networkExtras) {
442
+ function appendHistory(existing, reason) {
443
+ if (!existing || !reason) {
444
+ return existing?.history;
445
+ }
446
+ const supersededAt = (/* @__PURE__ */ new Date()).toISOString();
447
+ const entry = {
448
+ contractId: existing.contractId,
449
+ wasmHash: existing.wasmHash,
450
+ deployedAt: existing.deployedAt,
451
+ supersededAt,
452
+ reason
453
+ };
454
+ return [...existing.history ?? [], entry];
455
+ }
456
+ function updateArtifact(artifacts, networkName, contractName, contractArtifact, options = {}) {
406
457
  const existingNetwork = artifacts.networks[networkName] ?? { contracts: {}, dependencyGraph: {} };
458
+ const existingContract = existingNetwork.contracts[contractName];
459
+ const history = appendHistory(existingContract, options.supersedeReason);
460
+ const nextVersion = artifacts.version === 1 && options.supersedeReason ? 2 : artifacts.version;
407
461
  return {
408
462
  ...artifacts,
463
+ version: nextVersion,
409
464
  networks: {
410
465
  ...artifacts.networks,
411
466
  [networkName]: {
412
467
  ...existingNetwork,
413
- dependencyGraph: networkExtras?.dependencyGraph ?? existingNetwork.dependencyGraph ?? {},
468
+ dependencyGraph: options.dependencyGraph ?? existingNetwork.dependencyGraph ?? {},
414
469
  contracts: {
415
470
  ...existingNetwork.contracts,
416
- [contractName]: contractArtifact
471
+ [contractName]: {
472
+ ...contractArtifact,
473
+ history: history ?? contractArtifact.history
474
+ }
417
475
  }
418
476
  }
419
477
  }
420
478
  };
421
479
  }
480
+ function restoreArtifactFromHistory(input) {
481
+ const network = input.artifacts.networks[input.networkName];
482
+ const current = network?.contracts[input.contractName];
483
+ if (!current) {
484
+ throw new CaatingaError(
485
+ `No artifact for "${input.contractName}" on "${input.networkName}".`,
486
+ CaatingaErrorCode.ARTIFACT_NOT_FOUND,
487
+ "Deploy the contract before attempting rollback."
488
+ );
489
+ }
490
+ if (current.contractId === input.contractId) {
491
+ return input.artifacts;
492
+ }
493
+ const fromHistory = (current.history ?? []).find(
494
+ (entry) => entry.contractId === input.contractId
495
+ );
496
+ if (!fromHistory) {
497
+ throw new CaatingaError(
498
+ `Rollback target "${input.contractId}" was not found in artifact history for "${input.contractName}".`,
499
+ CaatingaErrorCode.ROLLBACK_TARGET_NOT_FOUND,
500
+ "Use caatinga inspect to list prior contract IDs, or redeploy manually."
501
+ );
502
+ }
503
+ const supersededAt = (/* @__PURE__ */ new Date()).toISOString();
504
+ const restoredArtifact = {
505
+ contractId: fromHistory.contractId,
506
+ wasmHash: fromHistory.wasmHash,
507
+ deployedAt: fromHistory.deployedAt,
508
+ sourcePath: current.sourcePath,
509
+ wasmPath: current.wasmPath,
510
+ dependencies: current.dependencies,
511
+ resolvedDeployArgs: current.resolvedDeployArgs,
512
+ history: [
513
+ ...current.history ?? [],
514
+ {
515
+ contractId: current.contractId,
516
+ wasmHash: current.wasmHash,
517
+ deployedAt: current.deployedAt,
518
+ supersededAt,
519
+ reason: "rollback"
520
+ }
521
+ ]
522
+ };
523
+ return {
524
+ ...updateArtifact(input.artifacts, input.networkName, input.contractName, restoredArtifact),
525
+ version: 2
526
+ };
527
+ }
528
+
529
+ // src/artifacts/migrate-artifacts.ts
530
+ function migrateArtifactsToV2(artifacts) {
531
+ if (artifacts.version === CURRENT_ARTIFACTS_SCHEMA_VERSION) {
532
+ return {
533
+ artifacts,
534
+ migrated: false
535
+ };
536
+ }
537
+ const v1 = artifacts;
538
+ return {
539
+ artifacts: {
540
+ project: v1.project,
541
+ version: CURRENT_ARTIFACTS_SCHEMA_VERSION,
542
+ networks: v1.networks
543
+ },
544
+ migrated: true
545
+ };
546
+ }
547
+
548
+ // src/artifacts/migrate-artifacts-file.ts
549
+ async function migrateArtifactsFile(cwd = process.cwd()) {
550
+ const artifacts = await readArtifacts(cwd);
551
+ const { artifacts: migrated, migrated: changed } = migrateArtifactsToV2(artifacts);
552
+ const path17 = await writeArtifacts(migrated, cwd);
553
+ return { path: path17, migrated: changed, artifacts: migrated };
554
+ }
555
+
556
+ // src/artifacts/rollback-artifact.ts
557
+ async function rollbackContractArtifact(input) {
558
+ const cwd = input.cwd ?? process.cwd();
559
+ const artifacts = await readArtifacts(cwd);
560
+ const next = restoreArtifactFromHistory({
561
+ artifacts,
562
+ networkName: input.networkName,
563
+ contractName: input.contractName,
564
+ contractId: input.contractId
565
+ });
566
+ const path17 = await writeArtifacts(next, cwd);
567
+ return { path: path17, artifacts: next };
568
+ }
422
569
 
423
570
  // src/networks/resolve-network.ts
424
571
  function resolveNetwork(config, networkName) {
@@ -685,6 +832,35 @@ function evaluateStellarCliCompatibility(input) {
685
832
  };
686
833
  }
687
834
 
835
+ // src/stellar-cli/probe-stellar-cli-features.ts
836
+ var import_semver3 = __toESM(require("semver"), 1);
837
+ var STELLAR_CLI_REQUIRED_FEATURES = [
838
+ "contract-build",
839
+ "contract-deploy",
840
+ "contract-invoke-sign"
841
+ ];
842
+ var FEATURE_COMMANDS = {
843
+ "contract-build": ["contract", "build", "--help"],
844
+ "contract-deploy": ["contract", "deploy", "--help"],
845
+ "contract-invoke-sign": ["contract", "invoke", "--help"]
846
+ };
847
+ async function probeMissingStellarCliFeatures(version) {
848
+ const missing = [];
849
+ if (import_semver3.default.valid(version) && import_semver3.default.lt(version, STELLAR_CLI_MIN_VERSION)) {
850
+ return ["contract-invoke-sign"];
851
+ }
852
+ for (const feature of STELLAR_CLI_REQUIRED_FEATURES) {
853
+ try {
854
+ await runCommand("stellar", FEATURE_COMMANDS[feature], {
855
+ skipStellarVersionCheck: true
856
+ });
857
+ } catch {
858
+ missing.push(feature);
859
+ }
860
+ }
861
+ return missing;
862
+ }
863
+
688
864
  // src/stellar-cli/check-stellar-cli-version.ts
689
865
  async function checkStellarCliVersion(input = {}) {
690
866
  let rawOutput;
@@ -704,9 +880,12 @@ async function checkStellarCliVersion(input = {}) {
704
880
  }
705
881
  throw error;
706
882
  }
883
+ const version = parseStellarCliVersion(rawOutput);
884
+ const probedMissing = input.probeFeatures === false ? [] : await probeMissingStellarCliFeatures(version);
885
+ const missingFeatures = [...input.features ?? [], ...probedMissing];
707
886
  const report = evaluateStellarCliCompatibility({
708
- version: parseStellarCliVersion(rawOutput),
709
- features: input.features,
887
+ version,
888
+ features: missingFeatures.length > 0 ? missingFeatures : void 0,
710
889
  lastTestedVersion: input.lastTestedVersion
711
890
  });
712
891
  for (const warning of report.warnings) {
@@ -852,6 +1031,122 @@ function parseContractId(output) {
852
1031
  return match[0];
853
1032
  }
854
1033
 
1034
+ // src/stellar-sdk/check-stellar-sdk-version.ts
1035
+ var import_promises6 = require("fs/promises");
1036
+ var import_node_path7 = __toESM(require("path"), 1);
1037
+
1038
+ // src/stellar-sdk/compat.ts
1039
+ var import_semver4 = __toESM(require("semver"), 1);
1040
+
1041
+ // src/stellar-sdk/version.ts
1042
+ var STELLAR_SDK_MIN_VERSION = "16.0.1";
1043
+ var STELLAR_SDK_LAST_TESTED_VERSION = "16.0.1";
1044
+
1045
+ // src/stellar-sdk/compat.ts
1046
+ function evaluateStellarSdkCompatibility(input) {
1047
+ const parsed = import_semver4.default.parse(input.version);
1048
+ if (!parsed || !import_semver4.default.valid(input.version)) {
1049
+ throw new CaatingaError(
1050
+ "Could not parse @stellar/stellar-sdk version.",
1051
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
1052
+ "Use a semantic version such as 16.0.1."
1053
+ );
1054
+ }
1055
+ const lastTestedVersion = import_semver4.default.valid(input.lastTestedVersion ?? STELLAR_SDK_LAST_TESTED_VERSION) ?? STELLAR_SDK_LAST_TESTED_VERSION;
1056
+ const warnings = [];
1057
+ let status = "supported";
1058
+ if (import_semver4.default.lt(parsed, STELLAR_SDK_MIN_VERSION)) {
1059
+ throw new CaatingaError(
1060
+ `@stellar/stellar-sdk ${input.version} is below the supported minimum ${STELLAR_SDK_MIN_VERSION}.`,
1061
+ CaatingaErrorCode.UNSUPPORTED_SDK_VERSION,
1062
+ `Install @stellar/stellar-sdk ${STELLAR_SDK_MIN_VERSION} or newer.`
1063
+ );
1064
+ }
1065
+ if (import_semver4.default.gt(parsed, lastTestedVersion)) {
1066
+ status = "untested";
1067
+ warnings.push({
1068
+ code: "STELLAR_SDK_UNTESTED_VERSION",
1069
+ message: `@stellar/stellar-sdk ${input.version} is newer than the last-tested ${lastTestedVersion}; binding output may differ.`,
1070
+ remediation: "Pin @stellar/stellar-sdk to the last-tested version in package.json, or update Caatinga fixtures after validating generate output."
1071
+ });
1072
+ }
1073
+ return {
1074
+ version: input.version,
1075
+ status,
1076
+ minVersion: STELLAR_SDK_MIN_VERSION,
1077
+ lastTestedVersion,
1078
+ warnings
1079
+ };
1080
+ }
1081
+ function parseStellarSdkVersion(raw) {
1082
+ const trimmed = raw.trim();
1083
+ const match = trimmed.match(/(\d+\.\d+\.\d+(?:[-+][\w.-]+)?)/);
1084
+ if (!match) {
1085
+ throw new CaatingaError(
1086
+ "Could not parse @stellar/stellar-sdk version.",
1087
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
1088
+ "Expected output like 16.0.1."
1089
+ );
1090
+ }
1091
+ return match[1];
1092
+ }
1093
+
1094
+ // src/stellar-sdk/check-stellar-sdk-version.ts
1095
+ async function readInstalledSdkVersion(cwd) {
1096
+ try {
1097
+ const pkgPath = import_node_path7.default.join(cwd, "node_modules", "@stellar", "stellar-sdk", "package.json");
1098
+ const raw = await (0, import_promises6.readFile)(pkgPath, "utf8");
1099
+ const pkg = JSON.parse(raw);
1100
+ return typeof pkg.version === "string" ? pkg.version : void 0;
1101
+ } catch {
1102
+ return void 0;
1103
+ }
1104
+ }
1105
+ async function resolveRegistrySdkVersion() {
1106
+ const result = await runCommand("npm", ["view", "@stellar/stellar-sdk", "version"], {
1107
+ skipStellarVersionCheck: true
1108
+ });
1109
+ return parseStellarSdkVersion(result.stdout || result.all);
1110
+ }
1111
+ async function checkStellarSdkVersion(input = {}) {
1112
+ const cwd = input.cwd ?? process.cwd();
1113
+ let version;
1114
+ try {
1115
+ const installed = await readInstalledSdkVersion(cwd);
1116
+ version = installed ?? await resolveRegistrySdkVersion();
1117
+ } catch (error) {
1118
+ if (error instanceof CaatingaError) {
1119
+ throw error;
1120
+ }
1121
+ throw new CaatingaError(
1122
+ "Could not resolve @stellar/stellar-sdk version.",
1123
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
1124
+ "Install @stellar/stellar-sdk in your project or ensure npm registry access.",
1125
+ error
1126
+ );
1127
+ }
1128
+ const report = evaluateStellarSdkCompatibility({
1129
+ version,
1130
+ lastTestedVersion: input.lastTestedVersion
1131
+ });
1132
+ for (const warning of report.warnings) {
1133
+ if (input.onWarning) {
1134
+ input.onWarning(warning);
1135
+ } else {
1136
+ defaultEmitWarning2(warning);
1137
+ }
1138
+ }
1139
+ return report;
1140
+ }
1141
+ function defaultEmitWarning2(warning) {
1142
+ const lines = [
1143
+ `Warning: ${warning.message}`,
1144
+ warning.remediation ? ` ${warning.remediation}` : void 0
1145
+ ].filter((line) => Boolean(line));
1146
+ process.stderr.write(`${lines.join("\n")}
1147
+ `);
1148
+ }
1149
+
855
1150
  // src/stellar-cli/build-stellar-network-args.ts
856
1151
  function matchesWellKnownNetwork(name, config) {
857
1152
  const known = WELL_KNOWN_NETWORKS[name];
@@ -989,8 +1284,38 @@ function validateSourceShape(source) {
989
1284
  return void 0;
990
1285
  }
991
1286
 
1287
+ // src/contracts/source-account.ts
1288
+ function assertSafeSourceAccount(source) {
1289
+ if (!source) {
1290
+ throw new CaatingaError(
1291
+ "A source account or Stellar CLI identity is required.",
1292
+ CaatingaErrorCode.SOURCE_ACCOUNT_REQUIRED,
1293
+ "Pass a Stellar CLI identity alias, for example: --source alice"
1294
+ );
1295
+ }
1296
+ const unsafeSource = validateSourceShape(source);
1297
+ if (unsafeSource) {
1298
+ throw unsafeSource;
1299
+ }
1300
+ return source;
1301
+ }
1302
+ var DEFAULT_CLI_SOURCE = "alice";
1303
+ function describeCliSource(explicit) {
1304
+ if (explicit) {
1305
+ return { source: assertSafeSourceAccount(explicit), origin: "explicit" };
1306
+ }
1307
+ const fromEnv = process.env.CAATINGA_SOURCE;
1308
+ if (fromEnv) {
1309
+ return { source: assertSafeSourceAccount(fromEnv), origin: "env" };
1310
+ }
1311
+ return { source: assertSafeSourceAccount(DEFAULT_CLI_SOURCE), origin: "default" };
1312
+ }
1313
+ function resolveCliSource(explicit) {
1314
+ return describeCliSource(explicit).source;
1315
+ }
1316
+
992
1317
  // src/contracts/resolve-contract.ts
993
- var import_node_path7 = __toESM(require("path"), 1);
1318
+ var import_node_path8 = __toESM(require("path"), 1);
994
1319
  function resolveContract(config, contractName, cwd = process.cwd()) {
995
1320
  const contract = config.contracts[contractName];
996
1321
  if (!contract) {
@@ -1003,8 +1328,8 @@ function resolveContract(config, contractName, cwd = process.cwd()) {
1003
1328
  return {
1004
1329
  name: contractName,
1005
1330
  config: contract,
1006
- sourcePath: import_node_path7.default.resolve(cwd, contract.path),
1007
- wasmPath: import_node_path7.default.resolve(cwd, contract.wasm)
1331
+ sourcePath: import_node_path8.default.resolve(cwd, contract.path),
1332
+ wasmPath: import_node_path8.default.resolve(cwd, contract.wasm)
1008
1333
  };
1009
1334
  }
1010
1335
 
@@ -1023,8 +1348,8 @@ function resolveDefaultContractName(config) {
1023
1348
 
1024
1349
  // src/contracts/wasm.ts
1025
1350
  var import_node_crypto = require("crypto");
1026
- var import_promises6 = require("fs/promises");
1027
- var import_node_path8 = __toESM(require("path"), 1);
1351
+ var import_promises7 = require("fs/promises");
1352
+ var import_node_path9 = __toESM(require("path"), 1);
1028
1353
  var LEGACY_RUST_WASM_TARGET = "wasm32-unknown-unknown";
1029
1354
  var CURRENT_RUST_WASM_TARGET = "wasm32v1-none";
1030
1355
  function toCurrentWasmTargetPath(wasmPath) {
@@ -1055,18 +1380,18 @@ function wasmNotFoundError(configuredWasmPath, options) {
1055
1380
  );
1056
1381
  }
1057
1382
  function toConfigRelativeWasmPath(absoluteWasmPath) {
1058
- const relative = import_node_path8.default.relative(process.cwd(), absoluteWasmPath);
1059
- return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(import_node_path8.default.sep).join("/")}`;
1383
+ const relative = import_node_path9.default.relative(process.cwd(), absoluteWasmPath);
1384
+ return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(import_node_path9.default.sep).join("/")}`;
1060
1385
  }
1061
1386
  function wasmFileName(configuredWasmPath) {
1062
- return import_node_path8.default.basename(configuredWasmPath);
1387
+ return import_node_path9.default.basename(configuredWasmPath);
1063
1388
  }
1064
1389
  function buildAlternateWasmCandidates(configuredWasmPath, options) {
1065
1390
  const fileName = wasmFileName(configuredWasmPath);
1066
1391
  const candidates = [];
1067
1392
  const seen = /* @__PURE__ */ new Set();
1068
1393
  function addCandidate(candidate) {
1069
- const resolved = import_node_path8.default.resolve(candidate);
1394
+ const resolved = import_node_path9.default.resolve(candidate);
1070
1395
  if (seen.has(resolved)) {
1071
1396
  return;
1072
1397
  }
@@ -1075,15 +1400,15 @@ function buildAlternateWasmCandidates(configuredWasmPath, options) {
1075
1400
  }
1076
1401
  const cargoTargetDir = process.env.CARGO_TARGET_DIR;
1077
1402
  if (cargoTargetDir) {
1078
- addCandidate(import_node_path8.default.join(cargoTargetDir, CURRENT_RUST_WASM_TARGET, "release", fileName));
1079
- addCandidate(import_node_path8.default.join(cargoTargetDir, LEGACY_RUST_WASM_TARGET, "release", fileName));
1403
+ addCandidate(import_node_path9.default.join(cargoTargetDir, CURRENT_RUST_WASM_TARGET, "release", fileName));
1404
+ addCandidate(import_node_path9.default.join(cargoTargetDir, LEGACY_RUST_WASM_TARGET, "release", fileName));
1080
1405
  }
1081
1406
  if (options?.sourcePath) {
1082
1407
  addCandidate(
1083
- import_node_path8.default.join(options.sourcePath, "target", CURRENT_RUST_WASM_TARGET, "release", fileName)
1408
+ import_node_path9.default.join(options.sourcePath, "target", CURRENT_RUST_WASM_TARGET, "release", fileName)
1084
1409
  );
1085
1410
  addCandidate(
1086
- import_node_path8.default.join(options.sourcePath, "target", LEGACY_RUST_WASM_TARGET, "release", fileName)
1411
+ import_node_path9.default.join(options.sourcePath, "target", LEGACY_RUST_WASM_TARGET, "release", fileName)
1087
1412
  );
1088
1413
  }
1089
1414
  return candidates;
@@ -1091,7 +1416,7 @@ function buildAlternateWasmCandidates(configuredWasmPath, options) {
1091
1416
  async function firstExistingPath(paths) {
1092
1417
  for (const candidate of paths) {
1093
1418
  try {
1094
- await (0, import_promises6.access)(candidate);
1419
+ await (0, import_promises7.access)(candidate);
1095
1420
  return candidate;
1096
1421
  } catch {
1097
1422
  continue;
@@ -1100,9 +1425,9 @@ async function firstExistingPath(paths) {
1100
1425
  return void 0;
1101
1426
  }
1102
1427
  async function resolveWasmArtifactPath(configuredWasmPath, options) {
1103
- const resolvedConfiguredPath = import_node_path8.default.resolve(configuredWasmPath);
1428
+ const resolvedConfiguredPath = import_node_path9.default.resolve(configuredWasmPath);
1104
1429
  try {
1105
- await (0, import_promises6.access)(resolvedConfiguredPath);
1430
+ await (0, import_promises7.access)(resolvedConfiguredPath);
1106
1431
  return resolvedConfiguredPath;
1107
1432
  } catch {
1108
1433
  const currentTargetPath = toCurrentWasmTargetPath(resolvedConfiguredPath);
@@ -1124,20 +1449,20 @@ async function resolveWasmArtifactPath(configuredWasmPath, options) {
1124
1449
  }
1125
1450
  }
1126
1451
  async function hashWasm(wasmPath) {
1127
- const bytes = await (0, import_promises6.readFile)(wasmPath);
1452
+ const bytes = await (0, import_promises7.readFile)(wasmPath);
1128
1453
  return (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex");
1129
1454
  }
1130
1455
  async function getNewestMtimeInDirectory(directory) {
1131
1456
  try {
1132
- await (0, import_promises6.access)(directory);
1457
+ await (0, import_promises7.access)(directory);
1133
1458
  } catch {
1134
1459
  return void 0;
1135
1460
  }
1136
1461
  let newest = 0;
1137
1462
  async function walk(dir) {
1138
- const entries = await (0, import_promises6.readdir)(dir, { withFileTypes: true });
1463
+ const entries = await (0, import_promises7.readdir)(dir, { withFileTypes: true });
1139
1464
  for (const entry of entries) {
1140
- const entryPath = import_node_path8.default.join(dir, entry.name);
1465
+ const entryPath = import_node_path9.default.join(dir, entry.name);
1141
1466
  if (entry.isDirectory()) {
1142
1467
  await walk(entryPath);
1143
1468
  continue;
@@ -1145,7 +1470,7 @@ async function getNewestMtimeInDirectory(directory) {
1145
1470
  if (!entry.isFile()) {
1146
1471
  continue;
1147
1472
  }
1148
- const fileStat = await (0, import_promises6.stat)(entryPath);
1473
+ const fileStat = await (0, import_promises7.stat)(entryPath);
1149
1474
  newest = Math.max(newest, fileStat.mtimeMs);
1150
1475
  }
1151
1476
  }
@@ -1153,14 +1478,14 @@ async function getNewestMtimeInDirectory(directory) {
1153
1478
  return newest > 0 ? newest : void 0;
1154
1479
  }
1155
1480
  async function isWasmOlderThanSources(input) {
1156
- const srcDir = import_node_path8.default.join(input.contractPath, "src");
1481
+ const srcDir = import_node_path9.default.join(input.contractPath, "src");
1157
1482
  const newestSourceMtime = await getNewestMtimeInDirectory(srcDir);
1158
1483
  if (newestSourceMtime === void 0) {
1159
1484
  return false;
1160
1485
  }
1161
1486
  let wasmStat;
1162
1487
  try {
1163
- wasmStat = await (0, import_promises6.stat)(input.wasmPath);
1488
+ wasmStat = await (0, import_promises7.stat)(input.wasmPath);
1164
1489
  } catch {
1165
1490
  return false;
1166
1491
  }
@@ -1228,7 +1553,38 @@ async function buildContract(options) {
1228
1553
  }
1229
1554
 
1230
1555
  // src/contracts/deploy-contract.ts
1231
- var import_node_path9 = __toESM(require("path"), 1);
1556
+ var import_node_path10 = __toESM(require("path"), 1);
1557
+
1558
+ // src/shell/is-transient-command-failure.ts
1559
+ var NO_RETRY_CAATINGA_SUBSTRINGS = [
1560
+ "CAATINGA_UNSUPPORTED_CLI_VERSION",
1561
+ "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
1562
+ "CAATINGA_STELLAR_CLI_NOT_FOUND",
1563
+ "CAATINGA_INVALID_CONFIG",
1564
+ "CAATINGA_CONFIG_NOT_FOUND"
1565
+ ];
1566
+ 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;
1567
+ function isTransientCommandFailure(logText) {
1568
+ if (!logText.trim()) {
1569
+ return false;
1570
+ }
1571
+ for (const marker of NO_RETRY_CAATINGA_SUBSTRINGS) {
1572
+ if (logText.includes(marker)) {
1573
+ return false;
1574
+ }
1575
+ }
1576
+ return TRANSIENT_COMMAND_FAILURE_PATTERN.test(logText);
1577
+ }
1578
+
1579
+ // src/contracts/is-transient-deploy-failure.ts
1580
+ function isTransientDeployFailure(error) {
1581
+ if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1582
+ return false;
1583
+ }
1584
+ const logText = `${error.message}
1585
+ ${error.hint ?? ""}`;
1586
+ return isTransientCommandFailure(logText);
1587
+ }
1232
1588
 
1233
1589
  // src/contracts/dependency-graph.ts
1234
1590
  function buildDependencyGraph(contracts) {
@@ -1270,26 +1626,13 @@ function resolveDeployArgs(input) {
1270
1626
  return resolved;
1271
1627
  }
1272
1628
 
1273
- // src/contracts/source-account.ts
1274
- function assertSafeSourceAccount(source) {
1275
- if (!source) {
1276
- throw new CaatingaError(
1277
- "A source account or Stellar CLI identity is required.",
1278
- CaatingaErrorCode.SOURCE_ACCOUNT_REQUIRED,
1279
- "Pass a Stellar CLI identity alias, for example: --source alice"
1280
- );
1281
- }
1282
- const unsafeSource = validateSourceShape(source);
1283
- if (unsafeSource) {
1284
- throw unsafeSource;
1285
- }
1286
- return source;
1287
- }
1288
- function resolveCliSource(explicit) {
1289
- return assertSafeSourceAccount(explicit ?? process.env.CAATINGA_SOURCE ?? "alice");
1290
- }
1291
-
1292
1629
  // src/contracts/deploy-contract.ts
1630
+ var DEFAULT_DEPLOY_RETRY_DELAYS_MS = [2e3, 5e3];
1631
+ function sleep(ms) {
1632
+ return new Promise((resolve) => {
1633
+ setTimeout(resolve, ms);
1634
+ });
1635
+ }
1293
1636
  function toSnakeCaseFlag(key) {
1294
1637
  return key.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
1295
1638
  }
@@ -1334,7 +1677,7 @@ async function deployContract(options) {
1334
1677
  contract: contractWithWasm,
1335
1678
  network,
1336
1679
  contractId: existing.contractId,
1337
- artifactsPath: import_node_path9.default.resolve(cwd, "caatinga.artifacts.json"),
1680
+ artifactsPath: import_node_path10.default.resolve(cwd, "caatinga.artifacts.json"),
1338
1681
  output: "",
1339
1682
  skipped: true,
1340
1683
  staleWasmWarning
@@ -1374,40 +1717,69 @@ async function deployContract(options) {
1374
1717
  ...buildStellarNetworkArgs(network),
1375
1718
  ...constructorArgs
1376
1719
  ];
1377
- let output = "";
1378
- let contractId;
1379
- try {
1380
- const result = await runCommand("stellar", stellarArgs, {
1381
- cwd,
1382
- failureCode: CaatingaErrorCode.DEPLOY_FAILED
1383
- });
1384
- output = result.all || `${result.stdout}
1720
+ let deployOutcome;
1721
+ const retryDelaysMs = options.deployRetryDelaysMs ?? DEFAULT_DEPLOY_RETRY_DELAYS_MS;
1722
+ const maxDeployAttempts = retryDelaysMs.length + 1;
1723
+ for (let attempt = 0; attempt < maxDeployAttempts; attempt++) {
1724
+ try {
1725
+ const result = await runCommand("stellar", stellarArgs, {
1726
+ cwd,
1727
+ failureCode: CaatingaErrorCode.DEPLOY_FAILED
1728
+ });
1729
+ const output2 = result.all || `${result.stdout}
1385
1730
  ${result.stderr}`;
1386
- contractId = parseContractId(output);
1387
- } catch (error) {
1388
- if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1389
- throw error;
1390
- }
1391
- const recoveredContractId = await tryRecoverContractIdFromDeployFailure({
1392
- output: `${error.message}
1731
+ deployOutcome = {
1732
+ output: output2,
1733
+ contractId: parseContractId(output2)
1734
+ };
1735
+ break;
1736
+ } catch (error) {
1737
+ if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1738
+ throw error;
1739
+ }
1740
+ const recoveredContractId = await tryRecoverContractIdFromDeployFailure({
1741
+ output: `${error.message}
1393
1742
  ${error.hint ?? ""}`,
1394
- source,
1395
- network: network.config,
1396
- cwd
1397
- });
1398
- if (!recoveredContractId) {
1399
- throw error;
1743
+ source,
1744
+ network: network.config,
1745
+ cwd
1746
+ });
1747
+ if (recoveredContractId) {
1748
+ deployOutcome = {
1749
+ output: [
1750
+ error.hint ?? "",
1751
+ "Caatinga recovered the contract ID from the on-chain deploy transaction.",
1752
+ `Contract ID: ${recoveredContractId}`
1753
+ ].filter(Boolean).join("\n"),
1754
+ contractId: recoveredContractId
1755
+ };
1756
+ break;
1757
+ }
1758
+ const isLastAttempt = attempt === maxDeployAttempts - 1;
1759
+ if (!isTransientDeployFailure(error) || isLastAttempt) {
1760
+ throw error;
1761
+ }
1762
+ const delayMs = retryDelaysMs[attempt] ?? retryDelaysMs[retryDelaysMs.length - 1] ?? 0;
1763
+ options.onTransientDeployRetry?.({
1764
+ attempt: attempt + 1,
1765
+ maxAttempts: maxDeployAttempts,
1766
+ delayMs
1767
+ });
1768
+ await sleep(delayMs);
1400
1769
  }
1401
- contractId = recoveredContractId;
1402
- output = [
1403
- error.hint ?? "",
1404
- "Caatinga recovered the contract ID from the on-chain deploy transaction.",
1405
- `Contract ID: ${contractId}`
1406
- ].filter(Boolean).join("\n");
1407
1770
  }
1771
+ if (!deployOutcome) {
1772
+ throw new CaatingaError(
1773
+ "Deploy failed without a contract ID.",
1774
+ CaatingaErrorCode.DEPLOY_FAILED,
1775
+ "Re-run the deploy command with the underlying Stellar CLI for full diagnostics."
1776
+ );
1777
+ }
1778
+ const { output, contractId } = deployOutcome;
1408
1779
  const wasmHash = await hashWasm(wasmPath);
1409
1780
  const dependencyGraph = buildDependencyGraph(options.config.contracts);
1410
1781
  const dependencies = options.dependencies ?? contract.config.dependsOn;
1782
+ const supersedeReason = existing?.contractId && options.force ? options.upgrade ? "upgrade" : "force-redeploy" : void 0;
1411
1783
  const nextArtifacts = updateArtifact(
1412
1784
  artifactsBefore,
1413
1785
  network.name,
@@ -1421,7 +1793,7 @@ ${error.hint ?? ""}`,
1421
1793
  dependencies,
1422
1794
  resolvedDeployArgs
1423
1795
  },
1424
- { dependencyGraph }
1796
+ { dependencyGraph, supersedeReason }
1425
1797
  );
1426
1798
  const artifactsPath = await writeArtifacts(nextArtifacts, cwd);
1427
1799
  return {
@@ -1585,9 +1957,11 @@ async function deployContractGraph(options) {
1585
1957
  source: options.source,
1586
1958
  cwd,
1587
1959
  force: options.force,
1960
+ upgrade: options.upgrade,
1588
1961
  checkStaleWasm: options.checkStaleWasm,
1589
1962
  resolvedDeployArgs,
1590
- dependencies: contractConfig.dependsOn
1963
+ dependencies: contractConfig.dependsOn,
1964
+ onTransientDeployRetry: options.onTransientDeployRetry
1591
1965
  });
1592
1966
  if (result.staleWasmWarning) {
1593
1967
  staleWasmWarnings.push({
@@ -1610,12 +1984,12 @@ async function deployContractGraph(options) {
1610
1984
  }
1611
1985
 
1612
1986
  // src/contracts/generate-bindings.ts
1613
- var import_promises8 = require("fs/promises");
1614
- var import_node_path11 = __toESM(require("path"), 1);
1987
+ var import_promises9 = require("fs/promises");
1988
+ var import_node_path12 = __toESM(require("path"), 1);
1615
1989
 
1616
1990
  // src/bindings/patch-generated-binding-package.ts
1617
- var import_promises7 = require("fs/promises");
1618
- var import_node_path10 = __toESM(require("path"), 1);
1991
+ var import_promises8 = require("fs/promises");
1992
+ var import_node_path11 = __toESM(require("path"), 1);
1619
1993
  var BUNDLER_ENTRY = "./src/index.ts";
1620
1994
  var ROOT_BINDING_INDEX_CONTENT = 'export * from "./src/index.js";\n';
1621
1995
  function resolveExportEntry(exportsField) {
@@ -1650,22 +2024,22 @@ function shouldPatchPackageJson(packageJson) {
1650
2024
  return pointsToDist(packageJson.main) || pointsToDist(packageJson.types) || !pointsToBundlerSource(exportEntry);
1651
2025
  }
1652
2026
  async function ensureRootBindingIndex(outputDir) {
1653
- const rootIndexPath = import_node_path10.default.join(outputDir, "index.ts");
2027
+ const rootIndexPath = import_node_path11.default.join(outputDir, "index.ts");
1654
2028
  try {
1655
- const existing = await (0, import_promises7.readFile)(rootIndexPath, "utf8");
2029
+ const existing = await (0, import_promises8.readFile)(rootIndexPath, "utf8");
1656
2030
  if (existing === ROOT_BINDING_INDEX_CONTENT) {
1657
2031
  return;
1658
2032
  }
1659
2033
  return;
1660
2034
  } catch {
1661
- await (0, import_promises7.writeFile)(rootIndexPath, ROOT_BINDING_INDEX_CONTENT, "utf8");
2035
+ await (0, import_promises8.writeFile)(rootIndexPath, ROOT_BINDING_INDEX_CONTENT, "utf8");
1662
2036
  }
1663
2037
  }
1664
2038
  async function patchGeneratedBindingPackage(outputDir) {
1665
- const packageJsonPath = import_node_path10.default.join(outputDir, "package.json");
1666
- const entryPath = import_node_path10.default.join(outputDir, "src", "index.ts");
2039
+ const packageJsonPath = import_node_path11.default.join(outputDir, "package.json");
2040
+ const entryPath = import_node_path11.default.join(outputDir, "src", "index.ts");
1667
2041
  try {
1668
- await (0, import_promises7.access)(entryPath);
2042
+ await (0, import_promises8.access)(entryPath);
1669
2043
  } catch {
1670
2044
  throw new CaatingaError(
1671
2045
  "Generated binding package is missing src/index.ts.",
@@ -1675,7 +2049,7 @@ async function patchGeneratedBindingPackage(outputDir) {
1675
2049
  }
1676
2050
  let raw;
1677
2051
  try {
1678
- raw = await (0, import_promises7.readFile)(packageJsonPath, "utf8");
2052
+ raw = await (0, import_promises8.readFile)(packageJsonPath, "utf8");
1679
2053
  } catch {
1680
2054
  throw new CaatingaError(
1681
2055
  "Generated binding package is missing package.json.",
@@ -1700,7 +2074,7 @@ async function patchGeneratedBindingPackage(outputDir) {
1700
2074
  ...typeof packageJson.exports === "object" && packageJson.exports !== null && !Array.isArray(packageJson.exports) ? packageJson.exports : {},
1701
2075
  ".": BUNDLER_ENTRY
1702
2076
  };
1703
- await (0, import_promises7.writeFile)(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
2077
+ await (0, import_promises8.writeFile)(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
1704
2078
  `, "utf8");
1705
2079
  }
1706
2080
  await ensureRootBindingIndex(outputDir);
@@ -1716,14 +2090,14 @@ function buildGenerateNetworkArgs(network) {
1716
2090
 
1717
2091
  // src/contracts/generate-bindings.ts
1718
2092
  function toBindingImportPath(bindingsOutput, contractName) {
1719
- const normalized = bindingsOutput.replace(/^\.\//, "").split(import_node_path11.default.sep).join("/");
1720
- return `./${import_node_path11.default.posix.join(normalized, contractName)}`;
2093
+ const normalized = bindingsOutput.replace(/^\.\//, "").split(import_node_path12.default.sep).join("/");
2094
+ return `./${import_node_path12.default.posix.join(normalized, contractName)}`;
1721
2095
  }
1722
2096
  async function removeLegacyBindingStub(cwd, bindingsOutput, contractName) {
1723
- const legacyPath = import_node_path11.default.resolve(cwd, bindingsOutput, `${contractName}.ts`);
2097
+ const legacyPath = import_node_path12.default.resolve(cwd, bindingsOutput, `${contractName}.ts`);
1724
2098
  try {
1725
- await (0, import_promises8.access)(legacyPath);
1726
- await (0, import_promises8.unlink)(legacyPath);
2099
+ await (0, import_promises9.access)(legacyPath);
2100
+ await (0, import_promises9.unlink)(legacyPath);
1727
2101
  return true;
1728
2102
  } catch {
1729
2103
  return false;
@@ -1748,8 +2122,9 @@ async function generateBindings(options) {
1748
2122
  "Run caatinga deploy for this contract and network before generating bindings."
1749
2123
  );
1750
2124
  }
1751
- const outputDir = import_node_path11.default.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
1752
- await (0, import_promises8.mkdir)(outputDir, { recursive: true });
2125
+ const outputDir = import_node_path12.default.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
2126
+ await (0, import_promises9.mkdir)(outputDir, { recursive: true });
2127
+ await checkStellarSdkVersion({ cwd });
1753
2128
  const result = await runCommand(
1754
2129
  "npx",
1755
2130
  [
@@ -1974,14 +2349,172 @@ async function readContract(options) {
1974
2349
  };
1975
2350
  }
1976
2351
 
2352
+ // src/contracts/estimate-deploy-cost.ts
2353
+ var import_node_path13 = __toESM(require("path"), 1);
2354
+ function toSnakeCaseFlag2(key) {
2355
+ return key.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
2356
+ }
2357
+ function formatConstructorCliArgs2(resolved) {
2358
+ const entries = Object.entries(resolved);
2359
+ if (entries.length === 0) {
2360
+ return [];
2361
+ }
2362
+ const tail = ["--"];
2363
+ for (const [key, value] of entries) {
2364
+ tail.push(`--${toSnakeCaseFlag2(key)}`, String(value));
2365
+ }
2366
+ return tail;
2367
+ }
2368
+ function parseFeeStroops(output) {
2369
+ const inclusionMatch = output.match(/inclusion[_\s-]*fee[:\s]+(\d+)/i);
2370
+ const resourceMatch = output.match(/resource[_\s-]*fee[:\s]+(\d+)/i);
2371
+ const totalMatch = output.match(/total[_\s-]*fee[:\s]+(\d+)/i);
2372
+ return {
2373
+ inclusion: inclusionMatch ? Number(inclusionMatch[1]) : void 0,
2374
+ resource: resourceMatch ? Number(resourceMatch[1]) : void 0,
2375
+ ...totalMatch && !resourceMatch ? { resource: Number(totalMatch[1]) } : {}
2376
+ };
2377
+ }
2378
+ async function estimateDeployCost(options) {
2379
+ const cwd = options.cwd ?? process.cwd();
2380
+ const contract = resolveContract(options.config, options.contractName, cwd);
2381
+ const network = resolveNetwork(options.config, options.networkName);
2382
+ const source = assertSafeSourceAccount(options.source);
2383
+ await checkBinary("stellar", "Install Stellar CLI before running caatinga estimate.");
2384
+ const wasmPath = await resolveWasmArtifactPath(contract.wasmPath, {
2385
+ sourcePath: contract.sourcePath
2386
+ });
2387
+ const artifacts = await readArtifacts(cwd);
2388
+ const rawDeployArgs = contract.config.deployArgs;
2389
+ const resolvedDeployArgs = Object.keys(rawDeployArgs).length > 0 ? resolveDeployArgs({
2390
+ deployArgs: rawDeployArgs,
2391
+ artifacts,
2392
+ network: network.name
2393
+ }) : {};
2394
+ const constructorArgs = formatConstructorCliArgs2(resolvedDeployArgs);
2395
+ const deployArgs = [
2396
+ "contract",
2397
+ "deploy",
2398
+ "--wasm",
2399
+ wasmPath,
2400
+ "--source-account",
2401
+ source,
2402
+ "--build-only",
2403
+ ...buildStellarNetworkArgs(network),
2404
+ ...constructorArgs
2405
+ ];
2406
+ let buildOutput;
2407
+ try {
2408
+ const buildResult = await runCommand("stellar", deployArgs, {
2409
+ cwd,
2410
+ failureCode: CaatingaErrorCode.ESTIMATE_FAILED
2411
+ });
2412
+ buildOutput = (buildResult.stdout || buildResult.all).trim();
2413
+ } catch (error) {
2414
+ if (error instanceof CaatingaError) {
2415
+ throw new CaatingaError(
2416
+ `Deploy cost estimate failed for "${contract.name}".`,
2417
+ CaatingaErrorCode.ESTIMATE_FAILED,
2418
+ error.hint ?? "Ensure WASM is built and deploy args resolve correctly.",
2419
+ error.cause
2420
+ );
2421
+ }
2422
+ throw error;
2423
+ }
2424
+ const simulateArgs = ["tx", "simulate", "--source-account", source, buildOutput];
2425
+ let simulateOutput = "";
2426
+ try {
2427
+ const simulateResult = await runCommand("stellar", simulateArgs, {
2428
+ cwd,
2429
+ failureCode: CaatingaErrorCode.ESTIMATE_FAILED
2430
+ });
2431
+ simulateOutput = simulateResult.all || `${simulateResult.stdout}
2432
+ ${simulateResult.stderr}`;
2433
+ } catch {
2434
+ simulateOutput = "";
2435
+ }
2436
+ const parsed = parseFeeStroops(simulateOutput);
2437
+ const inclusionFeeStroops = parsed.inclusion ?? 100;
2438
+ const resourceFeeStroops = parsed.resource;
2439
+ const totalFeeStroops = inclusionFeeStroops + (resourceFeeStroops ?? 0);
2440
+ return {
2441
+ contractName: contract.name,
2442
+ network: network.name,
2443
+ wasmPath: import_node_path13.default.relative(cwd, wasmPath) || wasmPath,
2444
+ inclusionFeeStroops,
2445
+ resourceFeeStroops,
2446
+ totalFeeStroops,
2447
+ advisory: "Advisory estimate only \u2014 actual fees may differ under network congestion or contract complexity.",
2448
+ rawOutput: simulateOutput || buildOutput
2449
+ };
2450
+ }
2451
+
2452
+ // src/contracts/inspect-contract.ts
2453
+ async function inspectContract(options) {
2454
+ const cwd = options.cwd ?? process.cwd();
2455
+ const contract = resolveContract(options.config, options.contractName, cwd);
2456
+ const network = resolveNetwork(options.config, options.networkName);
2457
+ const artifacts = await readArtifacts(cwd);
2458
+ const artifact = artifacts.networks[network.name]?.contracts[contract.name];
2459
+ if (!artifact) {
2460
+ throw new CaatingaError(
2461
+ `No deployed artifact found for "${contract.name}" on "${network.name}".`,
2462
+ CaatingaErrorCode.ARTIFACT_NOT_FOUND,
2463
+ "Run caatinga deploy before inspect."
2464
+ );
2465
+ }
2466
+ await checkBinary("stellar", "Install Stellar CLI before running caatinga inspect.");
2467
+ let reachable = false;
2468
+ let detail;
2469
+ try {
2470
+ await verifyDependencyContract({
2471
+ dependencyName: contract.name,
2472
+ contractId: artifact.contractId,
2473
+ network,
2474
+ cwd
2475
+ });
2476
+ reachable = true;
2477
+ detail = "Contract interface reachable on network.";
2478
+ } catch (error) {
2479
+ reachable = false;
2480
+ detail = error instanceof CaatingaError ? error.message : "Contract not reachable on network.";
2481
+ }
2482
+ let localHash;
2483
+ try {
2484
+ const wasmPath = await resolveWasmArtifactPath(contract.wasmPath, {
2485
+ sourcePath: contract.sourcePath
2486
+ });
2487
+ localHash = await hashWasm(wasmPath);
2488
+ } catch {
2489
+ localHash = void 0;
2490
+ }
2491
+ return {
2492
+ contractName: contract.name,
2493
+ network: network.name,
2494
+ artifact: {
2495
+ contractId: artifact.contractId,
2496
+ wasmHash: artifact.wasmHash,
2497
+ deployedAt: artifact.deployedAt,
2498
+ historyCount: artifact.history?.length ?? 0
2499
+ },
2500
+ onChain: { reachable, detail },
2501
+ localWasm: {
2502
+ path: contract.config.wasm,
2503
+ hash: localHash,
2504
+ matchesArtifact: Boolean(localHash && localHash === artifact.wasmHash)
2505
+ },
2506
+ dependencies: artifact.dependencies ?? contract.config.dependsOn ?? []
2507
+ };
2508
+ }
2509
+
1977
2510
  // src/templates/create-project-from-template.ts
1978
- var import_promises9 = require("fs/promises");
1979
- var import_node_path12 = __toESM(require("path"), 1);
2511
+ var import_promises10 = require("fs/promises");
2512
+ var import_node_path14 = __toESM(require("path"), 1);
1980
2513
  var import_zod7 = require("zod");
1981
2514
 
1982
2515
  // src/templates/template-manifest.schema.ts
1983
2516
  var import_zod6 = require("zod");
1984
- var import_semver3 = __toESM(require("semver"), 1);
2517
+ var import_semver5 = __toESM(require("semver"), 1);
1985
2518
  var CURRENT_TEMPLATE_VERSION = 1;
1986
2519
  var TemplateManifestSchema = import_zod6.z.object({
1987
2520
  name: import_zod6.z.string().min(1),
@@ -2005,14 +2538,14 @@ var TemplateManifestSchema = import_zod6.z.object({
2005
2538
  })
2006
2539
  });
2007
2540
  function defaultCompatibleCoreRange(coreVersion = CAATINGA_CORE_VERSION) {
2008
- const version = import_semver3.default.valid(import_semver3.default.coerce(coreVersion));
2541
+ const version = import_semver5.default.valid(import_semver5.default.coerce(coreVersion));
2009
2542
  if (!version) {
2010
2543
  throw new Error(`Invalid core version: ${coreVersion}`);
2011
2544
  }
2012
2545
  return `^${version}`;
2013
2546
  }
2014
2547
  function isCoreVersionCompatible(range, coreVersion = CAATINGA_CORE_VERSION) {
2015
- return import_semver3.default.satisfies(coreVersion, range);
2548
+ return import_semver5.default.satisfies(coreVersion, range);
2016
2549
  }
2017
2550
  function getTemplateCompatibilityIssue(manifest, coreVersion = CAATINGA_CORE_VERSION) {
2018
2551
  if (manifest.caatinga.templateVersion !== CURRENT_TEMPLATE_VERSION) {
@@ -2047,10 +2580,10 @@ function formatTemplateCompatibilityHint(issue) {
2047
2580
  // src/templates/create-project-from-template.ts
2048
2581
  var TEMPLATE_COPY_EXCLUDED_DIRS = /* @__PURE__ */ new Set(["target", "test_snapshots", "node_modules", ".git"]);
2049
2582
  async function createProjectFromTemplate(options) {
2050
- const targetDir = import_node_path12.default.resolve(options.targetDir);
2051
- const templateDir = import_node_path12.default.resolve(options.templateDir);
2583
+ const targetDir = import_node_path14.default.resolve(options.targetDir);
2584
+ const templateDir = import_node_path14.default.resolve(options.templateDir);
2052
2585
  try {
2053
- await (0, import_promises9.stat)(templateDir);
2586
+ await (0, import_promises10.stat)(templateDir);
2054
2587
  } catch {
2055
2588
  throw new CaatingaError(
2056
2589
  `Template directory was not found: ${templateDir}`,
@@ -2060,8 +2593,8 @@ async function createProjectFromTemplate(options) {
2060
2593
  }
2061
2594
  const manifest = await readTemplateManifest(templateDir);
2062
2595
  const mergeIntoExisting = Boolean(options.filter);
2063
- await (0, import_promises9.mkdir)(targetDir, { recursive: true });
2064
- await (0, import_promises9.cp)(templateDir, targetDir, {
2596
+ await (0, import_promises10.mkdir)(targetDir, { recursive: true });
2597
+ await (0, import_promises10.cp)(templateDir, targetDir, {
2065
2598
  recursive: true,
2066
2599
  force: true,
2067
2600
  errorOnExist: false,
@@ -2089,9 +2622,9 @@ async function ensureArtifacts(targetDir, projectName) {
2089
2622
  }
2090
2623
  }
2091
2624
  async function readTemplateManifest(templateDir) {
2092
- const manifestPath = import_node_path12.default.join(templateDir, "caatinga.template.json");
2625
+ const manifestPath = import_node_path14.default.join(templateDir, "caatinga.template.json");
2093
2626
  try {
2094
- const rawManifest = await (0, import_promises9.readFile)(manifestPath, "utf8");
2627
+ const rawManifest = await (0, import_promises10.readFile)(manifestPath, "utf8");
2095
2628
  const manifest = TemplateManifestSchema.parse(JSON.parse(rawManifest));
2096
2629
  const compatibilityIssue = getTemplateCompatibilityIssue(manifest);
2097
2630
  if (compatibilityIssue) {
@@ -2124,51 +2657,57 @@ async function readTemplateManifest(templateDir) {
2124
2657
  }
2125
2658
  }
2126
2659
  async function replaceTemplateVariables(dir, projectName) {
2127
- const entries = await (0, import_promises9.readdir)(dir);
2660
+ const entries = await (0, import_promises10.readdir)(dir);
2128
2661
  await Promise.all(
2129
2662
  entries.map(async (entry) => {
2130
- const entryPath = import_node_path12.default.join(dir, entry);
2131
- const entryStat = await (0, import_promises9.stat)(entryPath);
2663
+ if (TEMPLATE_COPY_EXCLUDED_DIRS.has(entry)) {
2664
+ return;
2665
+ }
2666
+ const entryPath = import_node_path14.default.join(dir, entry);
2667
+ const entryStat = await (0, import_promises10.lstat)(entryPath);
2668
+ if (entryStat.isSymbolicLink()) {
2669
+ return;
2670
+ }
2132
2671
  if (entryStat.isDirectory()) {
2133
2672
  await replaceTemplateVariables(entryPath, projectName);
2134
2673
  return;
2135
2674
  }
2136
- if (!isTextTemplateFile(entryPath)) {
2675
+ if (!entryStat.isFile() || !isTextTemplateFile(entryPath)) {
2137
2676
  return;
2138
2677
  }
2139
- const content = await (0, import_promises9.readFile)(entryPath, "utf8");
2140
- await (0, import_promises9.writeFile)(entryPath, content.replaceAll("__PROJECT_NAME__", projectName), "utf8");
2678
+ const content = await (0, import_promises10.readFile)(entryPath, "utf8");
2679
+ await (0, import_promises10.writeFile)(entryPath, content.replaceAll("__PROJECT_NAME__", projectName), "utf8");
2141
2680
  })
2142
2681
  );
2143
2682
  }
2144
2683
  function shouldCopyTemplateEntry(templateDir, source, userFilter) {
2145
- const relativePath = import_node_path12.default.relative(templateDir, source);
2684
+ const relativePath = import_node_path14.default.relative(templateDir, source);
2146
2685
  if (!relativePath || relativePath === ".") {
2147
2686
  return true;
2148
2687
  }
2149
- const normalizedPath = relativePath.split(import_node_path12.default.sep).join("/");
2688
+ const normalizedPath = relativePath.split(import_node_path14.default.sep).join("/");
2150
2689
  if (userFilter && !userFilter(normalizedPath)) {
2151
2690
  return false;
2152
2691
  }
2153
- return !relativePath.split(import_node_path12.default.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
2692
+ return !relativePath.split(import_node_path14.default.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
2154
2693
  }
2155
2694
  function isTextTemplateFile(filePath) {
2156
2695
  return [".json", ".md", ".rs", ".toml", ".ts", ".tsx", ".css", ".html"].includes(
2157
- import_node_path12.default.extname(filePath)
2696
+ import_node_path14.default.extname(filePath)
2158
2697
  );
2159
2698
  }
2160
2699
 
2161
2700
  // src/scaffold/create-zk-project.ts
2162
- var import_promises10 = require("fs/promises");
2701
+ var import_promises11 = require("fs/promises");
2163
2702
  var import_node_fs2 = require("fs");
2164
- var import_node_path13 = __toESM(require("path"), 1);
2703
+ var import_node_path15 = __toESM(require("path"), 1);
2165
2704
  var import_node_url = require("url");
2166
2705
  var import_meta3 = {};
2167
- var moduleDir = typeof __dirname === "string" ? __dirname : import_node_path13.default.dirname((0, import_node_url.fileURLToPath)(import_meta3.url));
2706
+ var moduleDir = typeof __dirname === "string" ? __dirname : import_node_path15.default.dirname((0, import_node_url.fileURLToPath)(import_meta3.url));
2168
2707
  function scaffoldRoot() {
2169
2708
  const candidates = [
2170
- import_node_path13.default.resolve(moduleDir, "../../scaffolds"),
2171
- import_node_path13.default.resolve(moduleDir, "../scaffolds")
2709
+ import_node_path15.default.resolve(moduleDir, "../../scaffolds"),
2710
+ import_node_path15.default.resolve(moduleDir, "../scaffolds")
2172
2711
  ];
2173
2712
  const found = candidates.find((candidate) => (0, import_node_fs2.existsSync)(candidate));
2174
2713
  return found ?? candidates[0];
@@ -2259,39 +2798,39 @@ Replace \`circuits/main.circom\` with your circuit. Keep the entry point named \
2259
2798
  `;
2260
2799
  }
2261
2800
  async function createZkProject(options) {
2262
- const targetDir = import_node_path13.default.resolve(options.targetDir);
2801
+ const targetDir = import_node_path15.default.resolve(options.targetDir);
2263
2802
  const force = options.force ?? false;
2264
2803
  const projectFiles = options.projectFiles ?? true;
2265
- await (0, import_promises10.mkdir)(targetDir, { recursive: true });
2804
+ await (0, import_promises11.mkdir)(targetDir, { recursive: true });
2266
2805
  if (projectFiles) {
2267
2806
  await Promise.all([
2268
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), {
2807
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), {
2269
2808
  encoding: "utf8",
2270
2809
  flag: force ? "w" : "wx"
2271
2810
  }),
2272
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, "package.json"), packageJsonSource(options.projectName), {
2811
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, "package.json"), packageJsonSource(options.projectName), {
2273
2812
  encoding: "utf8",
2274
2813
  flag: force ? "w" : "wx"
2275
2814
  }),
2276
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2815
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2277
2816
  encoding: "utf8",
2278
2817
  flag: force ? "w" : "wx"
2279
2818
  }),
2280
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, "README.md"), readmeSource(options.projectName), {
2819
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, "README.md"), readmeSource(options.projectName), {
2281
2820
  encoding: "utf8",
2282
2821
  flag: force ? "w" : "wx"
2283
2822
  })
2284
2823
  ]);
2285
2824
  }
2286
- await (0, import_promises10.mkdir)(import_node_path13.default.join(targetDir, "contracts"), { recursive: true });
2287
- await (0, import_promises10.cp)(import_node_path13.default.join(scaffoldRoot(), "zk-circuit-stub"), import_node_path13.default.join(targetDir, "circuits"), {
2825
+ await (0, import_promises11.mkdir)(import_node_path15.default.join(targetDir, "contracts"), { recursive: true });
2826
+ await (0, import_promises11.cp)(import_node_path15.default.join(scaffoldRoot(), "zk-circuit-stub"), import_node_path15.default.join(targetDir, "circuits"), {
2288
2827
  recursive: true,
2289
2828
  force,
2290
2829
  errorOnExist: !force
2291
2830
  });
2292
- await (0, import_promises10.cp)(
2293
- import_node_path13.default.join(scaffoldRoot(), "zk-verifier"),
2294
- import_node_path13.default.join(targetDir, "contracts", "verifier"),
2831
+ await (0, import_promises11.cp)(
2832
+ import_node_path15.default.join(scaffoldRoot(), "zk-verifier"),
2833
+ import_node_path15.default.join(targetDir, "contracts", "verifier"),
2295
2834
  {
2296
2835
  recursive: true,
2297
2836
  force,
@@ -2308,16 +2847,16 @@ async function createZkProject(options) {
2308
2847
  }
2309
2848
 
2310
2849
  // src/scaffold/create-minimal-project.ts
2311
- var import_promises11 = require("fs/promises");
2850
+ var import_promises12 = require("fs/promises");
2312
2851
  var import_node_fs3 = require("fs");
2313
- var import_node_path14 = __toESM(require("path"), 1);
2852
+ var import_node_path16 = __toESM(require("path"), 1);
2314
2853
  var import_node_url2 = require("url");
2315
2854
  var import_meta4 = {};
2316
- var moduleDir2 = typeof __dirname === "string" ? __dirname : import_node_path14.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
2855
+ var moduleDir2 = typeof __dirname === "string" ? __dirname : import_node_path16.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
2317
2856
  function scaffoldRoot2() {
2318
2857
  const candidates = [
2319
- import_node_path14.default.resolve(moduleDir2, "../../scaffolds"),
2320
- import_node_path14.default.resolve(moduleDir2, "../scaffolds")
2858
+ import_node_path16.default.resolve(moduleDir2, "../../scaffolds"),
2859
+ import_node_path16.default.resolve(moduleDir2, "../scaffolds")
2321
2860
  ];
2322
2861
  const found = candidates.find((candidate) => (0, import_node_fs3.existsSync)(candidate));
2323
2862
  return found ?? candidates[0];
@@ -2408,31 +2947,31 @@ Edit \`contracts/app/src/lib.rs\` to customize the contract. Add a frontend late
2408
2947
  `;
2409
2948
  }
2410
2949
  async function createMinimalProject(options) {
2411
- const targetDir = import_node_path14.default.resolve(options.targetDir);
2950
+ const targetDir = import_node_path16.default.resolve(options.targetDir);
2412
2951
  const force = options.force ?? false;
2413
- await (0, import_promises11.mkdir)(targetDir, { recursive: true });
2952
+ await (0, import_promises12.mkdir)(targetDir, { recursive: true });
2414
2953
  await Promise.all([
2415
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, "caatinga.config.ts"), configSource2(options.projectName), {
2954
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, "caatinga.config.ts"), configSource2(options.projectName), {
2416
2955
  encoding: "utf8",
2417
2956
  flag: force ? "w" : "wx"
2418
2957
  }),
2419
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, "package.json"), packageJsonSource2(options.projectName), {
2958
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, "package.json"), packageJsonSource2(options.projectName), {
2420
2959
  encoding: "utf8",
2421
2960
  flag: force ? "w" : "wx"
2422
2961
  }),
2423
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2962
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2424
2963
  encoding: "utf8",
2425
2964
  flag: force ? "w" : "wx"
2426
2965
  }),
2427
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, "README.md"), readmeSource2(options.projectName), {
2966
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, "README.md"), readmeSource2(options.projectName), {
2428
2967
  encoding: "utf8",
2429
2968
  flag: force ? "w" : "wx"
2430
2969
  })
2431
2970
  ]);
2432
- await (0, import_promises11.mkdir)(import_node_path14.default.join(targetDir, "contracts"), { recursive: true });
2433
- await (0, import_promises11.cp)(
2434
- import_node_path14.default.join(scaffoldRoot2(), "soroban-contract-stub"),
2435
- import_node_path14.default.join(targetDir, "contracts", "app"),
2971
+ await (0, import_promises12.mkdir)(import_node_path16.default.join(targetDir, "contracts"), { recursive: true });
2972
+ await (0, import_promises12.cp)(
2973
+ import_node_path16.default.join(scaffoldRoot2(), "soroban-contract-stub"),
2974
+ import_node_path16.default.join(targetDir, "contracts", "app"),
2436
2975
  {
2437
2976
  recursive: true,
2438
2977
  force,
@@ -2447,37 +2986,25 @@ async function createMinimalProject(options) {
2447
2986
  }
2448
2987
 
2449
2988
  // src/ci/is-transient-testnet-smoke-failure.ts
2450
- var NO_RETRY_CAATINGA_SUBSTRINGS = [
2451
- "CAATINGA_UNSUPPORTED_CLI_VERSION",
2452
- "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
2453
- "CAATINGA_STELLAR_CLI_NOT_FOUND",
2454
- "CAATINGA_INVALID_CONFIG",
2455
- "CAATINGA_CONFIG_NOT_FOUND"
2456
- ];
2457
- var TRANSIENT_PATTERN = /timeout|i\/o timeout|econnreset|connection reset|503|502|429|rate limit|temporar|bad gateway|fetch failed|network error|unavailable/i;
2458
2989
  function isTransientTestnetSmokeFailure(logText) {
2459
- if (!logText.trim()) {
2460
- return false;
2461
- }
2462
- for (const marker of NO_RETRY_CAATINGA_SUBSTRINGS) {
2463
- if (logText.includes(marker)) {
2464
- return false;
2465
- }
2466
- }
2467
- return TRANSIENT_PATTERN.test(logText);
2990
+ return isTransientCommandFailure(logText);
2468
2991
  }
2469
2992
  // Annotate the CommonJS export names for ESM import in node:
2470
2993
  0 && (module.exports = {
2471
2994
  BINDING_MARKER_FILENAME,
2472
2995
  BindingMarkerSchema,
2473
2996
  CAATINGA_CORE_VERSION,
2997
+ CURRENT_ARTIFACTS_SCHEMA_VERSION,
2474
2998
  CaatingaArtifactsSchema,
2475
2999
  CaatingaConfigSchema,
2476
3000
  CaatingaError,
2477
3001
  CaatingaErrorCode,
3002
+ DEFAULT_CLI_SOURCE,
2478
3003
  READ_CALL_FAILURE_REGEX,
2479
3004
  STELLAR_CLI_LAST_TESTED_VERSION,
2480
3005
  STELLAR_CLI_MIN_VERSION,
3006
+ STELLAR_SDK_LAST_TESTED_VERSION,
3007
+ STELLAR_SDK_MIN_VERSION,
2481
3008
  TemplateManifestSchema,
2482
3009
  WELL_KNOWN_NETWORKS,
2483
3010
  buildContract,
@@ -2485,6 +3012,7 @@ function isTransientTestnetSmokeFailure(logText) {
2485
3012
  buildReadCallHint,
2486
3013
  checkBinary,
2487
3014
  checkStellarCliVersion,
3015
+ checkStellarSdkVersion,
2488
3016
  collectProjectStatus,
2489
3017
  createInitialArtifacts,
2490
3018
  createMinimalProject,
@@ -2493,20 +3021,27 @@ function isTransientTestnetSmokeFailure(logText) {
2493
3021
  defineConfig,
2494
3022
  deployContract,
2495
3023
  deployContractGraph,
3024
+ describeCliSource,
3025
+ estimateDeployCost,
2496
3026
  evaluateBindingFreshness,
2497
3027
  evaluateBindingsFreshness,
2498
3028
  evaluateStellarCliCompatibility,
3029
+ evaluateStellarSdkCompatibility,
2499
3030
  formatCaatingaError,
2500
3031
  generateBindings,
2501
3032
  generateBindingsGraph,
3033
+ inspectContract,
2502
3034
  invokeContract,
2503
3035
  isCargoBinMissingFromPath,
2504
3036
  isReadCallFailure,
2505
3037
  isTransientTestnetSmokeFailure,
2506
3038
  loadConfig,
3039
+ migrateArtifactsFile,
3040
+ migrateArtifactsToV2,
2507
3041
  parseContractId,
2508
3042
  parseInvokeTarget,
2509
3043
  parseStellarCliVersion,
3044
+ parseStellarSdkVersion,
2510
3045
  readArtifacts,
2511
3046
  readBindingMarker,
2512
3047
  readContract,
@@ -2516,6 +3051,8 @@ function isTransientTestnetSmokeFailure(logText) {
2516
3051
  resolveDeployOrder,
2517
3052
  resolveNetwork,
2518
3053
  resolveSubprocessEnv,
3054
+ restoreArtifactFromHistory,
3055
+ rollbackContractArtifact,
2519
3056
  runCommand,
2520
3057
  toCaatingaError,
2521
3058
  updateArtifact,