@caatinga/core 2.2.1 → 2.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.js CHANGED
@@ -105,7 +105,7 @@ function formatCause(cause) {
105
105
  }
106
106
 
107
107
  // src/version.ts
108
- var CAATINGA_CORE_VERSION = "2.2.1";
108
+ var CAATINGA_CORE_VERSION = "2.3.1";
109
109
 
110
110
  // src/config/config.schema.ts
111
111
  import { z } from "zod";
@@ -120,6 +120,15 @@ var NetworkConfigSchema = z.object({
120
120
  rpcUrl: z.string().url(),
121
121
  networkPassphrase: z.string().min(1)
122
122
  });
123
+ var ZkCircuitSchema = z.object({
124
+ path: z.string().min(1),
125
+ protocol: z.literal("groth16"),
126
+ curve: z.literal("bls12381"),
127
+ verifierContract: z.string().optional()
128
+ });
129
+ var ZkConfigSchema = z.object({
130
+ circuits: z.record(z.string().min(1), ZkCircuitSchema)
131
+ }).optional();
123
132
  var CaatingaConfigSchema = z.object({
124
133
  project: z.string().min(1),
125
134
  defaultNetwork: z.string().min(1).default("testnet"),
@@ -134,7 +143,8 @@ var CaatingaConfigSchema = z.object({
134
143
  frontend: z.object({
135
144
  framework: z.enum(["vite-react", "next", "astro"]).default("vite-react"),
136
145
  bindingsOutput: z.string().min(1)
137
- })
146
+ }).optional(),
147
+ zk: ZkConfigSchema
138
148
  });
139
149
 
140
150
  // src/config/define-config.ts
@@ -331,6 +341,15 @@ async function listGeneratedEntries(outputDir) {
331
341
  }
332
342
  async function evaluateBindingFreshness(options) {
333
343
  const cwd = options.cwd ?? process.cwd();
344
+ if (!options.config.frontend) {
345
+ return {
346
+ contractName: options.contractName,
347
+ status: "unknown",
348
+ outputDir: "",
349
+ marker: null,
350
+ reason: "frontend bindings are not configured"
351
+ };
352
+ }
334
353
  const outputDir = path5.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
335
354
  const contractArtifact = options.artifacts.networks[options.networkName]?.contracts[options.contractName];
336
355
  if (!contractArtifact) {
@@ -577,6 +596,7 @@ async function runCommand(command, args, options = {}) {
577
596
  const result = await execa(command, args, {
578
597
  cwd: options.cwd,
579
598
  env: options.env,
599
+ input: options.input,
580
600
  all: true,
581
601
  reject: true
582
602
  });
@@ -791,6 +811,19 @@ function resolveContract(config, contractName, cwd = process.cwd()) {
791
811
  };
792
812
  }
793
813
 
814
+ // src/contracts/resolve-default-contract.ts
815
+ function resolveDefaultContractName(config) {
816
+ const names = Object.keys(config.contracts);
817
+ if (names.length === 1) {
818
+ return names[0];
819
+ }
820
+ throw new CaatingaError(
821
+ "Pass a contract name to build.",
822
+ CaatingaErrorCode.CONTRACT_NOT_FOUND,
823
+ `Configured contracts: ${names.join(", ")}. Example: caatinga build ${names[0]}`
824
+ );
825
+ }
826
+
794
827
  // src/contracts/wasm.ts
795
828
  import { createHash } from "crypto";
796
829
  import { access as access2, readdir as readdir2, readFile as readFile3, stat } from "fs/promises";
@@ -1335,6 +1368,13 @@ async function removeLegacyBindingStub(cwd, bindingsOutput, contractName) {
1335
1368
  }
1336
1369
  async function generateBindings(options) {
1337
1370
  const cwd = options.cwd ?? process.cwd();
1371
+ if (!options.config.frontend) {
1372
+ throw new CaatingaError(
1373
+ "Frontend bindings are not configured.",
1374
+ CaatingaErrorCode.INVALID_CONFIG,
1375
+ "Add a frontend.bindingsOutput entry to caatinga.config.ts before running caatinga generate."
1376
+ );
1377
+ }
1338
1378
  const network = resolveNetwork(options.config, options.networkName);
1339
1379
  const artifacts = await readArtifacts(cwd);
1340
1380
  const contractArtifact = artifacts.networks[network.name]?.contracts[options.contractName];
@@ -1581,15 +1621,18 @@ async function createProjectFromTemplate(options) {
1581
1621
  );
1582
1622
  }
1583
1623
  const manifest = await readTemplateManifest(templateDir);
1624
+ const mergeIntoExisting = Boolean(options.filter);
1584
1625
  await mkdir3(targetDir, { recursive: true });
1585
1626
  await cp(templateDir, targetDir, {
1586
1627
  recursive: true,
1587
- force: false,
1588
- errorOnExist: true,
1589
- filter: (source) => shouldCopyTemplateEntry(templateDir, source)
1628
+ force: mergeIntoExisting,
1629
+ errorOnExist: !mergeIntoExisting,
1630
+ filter: (source) => shouldCopyTemplateEntry(templateDir, source, options.filter)
1590
1631
  });
1591
1632
  await replaceTemplateVariables(targetDir, options.projectName);
1592
- await ensureArtifacts(targetDir, options.projectName);
1633
+ if (!mergeIntoExisting) {
1634
+ await ensureArtifacts(targetDir, options.projectName);
1635
+ }
1593
1636
  return { targetDir, template: manifest };
1594
1637
  }
1595
1638
  async function ensureArtifacts(targetDir, projectName) {
@@ -1655,11 +1698,15 @@ async function replaceTemplateVariables(dir, projectName) {
1655
1698
  await writeFile3(entryPath, content.replaceAll("__PROJECT_NAME__", projectName), "utf8");
1656
1699
  }));
1657
1700
  }
1658
- function shouldCopyTemplateEntry(templateDir, source) {
1701
+ function shouldCopyTemplateEntry(templateDir, source, userFilter) {
1659
1702
  const relativePath = path10.relative(templateDir, source);
1660
1703
  if (!relativePath || relativePath === ".") {
1661
1704
  return true;
1662
1705
  }
1706
+ const normalizedPath = relativePath.split(path10.sep).join("/");
1707
+ if (userFilter && !userFilter(normalizedPath)) {
1708
+ return false;
1709
+ }
1663
1710
  return !relativePath.split(path10.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
1664
1711
  }
1665
1712
  function isTextTemplateFile(filePath) {
@@ -1675,6 +1722,118 @@ function isTextTemplateFile(filePath) {
1675
1722
  ].includes(path10.extname(filePath));
1676
1723
  }
1677
1724
 
1725
+ // src/scaffold/create-zk-project.ts
1726
+ import { cp as cp2, mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
1727
+ import { existsSync } from "fs";
1728
+ import path11 from "path";
1729
+ import { fileURLToPath } from "url";
1730
+ var moduleDir = typeof __dirname === "string" ? __dirname : path11.dirname(fileURLToPath(import.meta.url));
1731
+ function scaffoldRoot() {
1732
+ const candidates = [
1733
+ path11.resolve(moduleDir, "../../scaffolds"),
1734
+ path11.resolve(moduleDir, "../scaffolds")
1735
+ ];
1736
+ const found = candidates.find((candidate) => existsSync(candidate));
1737
+ return found ?? candidates[0];
1738
+ }
1739
+ function configSource(projectName) {
1740
+ return `import { defineConfig } from "@caatinga/core";
1741
+
1742
+ export default defineConfig({
1743
+ project: "${projectName}",
1744
+ defaultNetwork: "testnet",
1745
+ contracts: {
1746
+ verifier: {
1747
+ path: "./contracts/verifier",
1748
+ wasm: "./contracts/verifier/target/wasm32v1-none/release/verifier.wasm"
1749
+ }
1750
+ },
1751
+ networks: {
1752
+ testnet: {
1753
+ rpcUrl: "https://soroban-testnet.stellar.org",
1754
+ networkPassphrase: "Test SDF Network ; September 2015"
1755
+ }
1756
+ },
1757
+ zk: {
1758
+ circuits: {
1759
+ main: {
1760
+ path: "./circuits",
1761
+ protocol: "groth16",
1762
+ curve: "bls12381",
1763
+ verifierContract: "verifier"
1764
+ }
1765
+ }
1766
+ }
1767
+ });
1768
+ `;
1769
+ }
1770
+ function packageJsonSource(projectName) {
1771
+ return `${JSON.stringify({
1772
+ name: projectName,
1773
+ version: "0.1.0",
1774
+ private: true,
1775
+ type: "module",
1776
+ scripts: {
1777
+ "zk:build": "caatinga zk build main",
1778
+ "zk:prove": "caatinga zk prove main",
1779
+ build: "caatinga build verifier",
1780
+ deploy: "caatinga deploy verifier"
1781
+ },
1782
+ devDependencies: {
1783
+ "@caatinga/cli": `^${CAATINGA_CORE_VERSION}`,
1784
+ "@caatinga/core": `^${CAATINGA_CORE_VERSION}`
1785
+ }
1786
+ }, null, 2)}
1787
+ `;
1788
+ }
1789
+ function readmeSource(projectName) {
1790
+ return `# ${projectName}
1791
+
1792
+ Minimal Caatinga ZK project.
1793
+
1794
+ ## Workflow
1795
+
1796
+ \`\`\`bash
1797
+ npm install
1798
+ npx caatinga zk build main
1799
+ npx caatinga build verifier
1800
+ npx caatinga deploy verifier --network testnet
1801
+ npx caatinga zk prove main
1802
+ \`\`\`
1803
+
1804
+ Replace \`circuits/main.circom\` with your circuit. Keep the entry point named \`main\`.
1805
+ `;
1806
+ }
1807
+ async function createZkProject(options) {
1808
+ const targetDir = path11.resolve(options.targetDir);
1809
+ const force = options.force ?? false;
1810
+ const projectFiles = options.projectFiles ?? true;
1811
+ await mkdir4(targetDir, { recursive: true });
1812
+ if (projectFiles) {
1813
+ await Promise.all([
1814
+ writeFile4(path11.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" }),
1815
+ writeFile4(path11.join(targetDir, "package.json"), packageJsonSource(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" }),
1816
+ writeFile4(path11.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", { encoding: "utf8", flag: force ? "w" : "wx" }),
1817
+ writeFile4(path11.join(targetDir, "README.md"), readmeSource(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" })
1818
+ ]);
1819
+ }
1820
+ await mkdir4(path11.join(targetDir, "contracts"), { recursive: true });
1821
+ await cp2(path11.join(scaffoldRoot(), "zk-circuit-stub"), path11.join(targetDir, "circuits"), {
1822
+ recursive: true,
1823
+ force,
1824
+ errorOnExist: !force
1825
+ });
1826
+ await cp2(path11.join(scaffoldRoot(), "zk-verifier"), path11.join(targetDir, "contracts", "verifier"), {
1827
+ recursive: true,
1828
+ force,
1829
+ errorOnExist: !force
1830
+ });
1831
+ if (projectFiles) {
1832
+ await writeArtifacts(createInitialArtifacts(options.projectName, { networks: ["testnet"] }), targetDir);
1833
+ }
1834
+ return { targetDir };
1835
+ }
1836
+
1678
1837
  // src/ci/is-transient-testnet-smoke-failure.ts
1679
1838
  var NO_RETRY_CAATINGA_SUBSTRINGS = [
1680
1839
  "CAATINGA_UNSUPPORTED_CLI_VERSION",
@@ -1714,6 +1873,7 @@ export {
1714
1873
  collectProjectStatus,
1715
1874
  createInitialArtifacts,
1716
1875
  createProjectFromTemplate,
1876
+ createZkProject,
1717
1877
  defineConfig,
1718
1878
  deployContract,
1719
1879
  deployContractGraph,
@@ -1732,6 +1892,7 @@ export {
1732
1892
  readArtifacts,
1733
1893
  readBindingMarker,
1734
1894
  resolveContract,
1895
+ resolveDefaultContractName,
1735
1896
  resolveDeployArgs,
1736
1897
  resolveDeployOrder,
1737
1898
  resolveNetwork,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caatinga/core",
3
- "version": "2.2.1",
3
+ "version": "2.3.1",
4
4
  "description": "Core config, artifacts, command orchestration, and error primitives for Caatinga/Soroban toolkit",
5
5
  "keywords": [
6
6
  "stellar",
@@ -45,6 +45,7 @@
45
45
  },
46
46
  "files": [
47
47
  "dist",
48
+ "scaffolds",
48
49
  "README.md",
49
50
  "LICENSE"
50
51
  ],
@@ -0,0 +1,3 @@
1
+ {
2
+ "a": "1"
3
+ }
@@ -0,0 +1,9 @@
1
+ pragma circom 2.1.6;
2
+
3
+ template Main() {
4
+ signal input a;
5
+ signal output b;
6
+ b <== a;
7
+ }
8
+
9
+ component main = Main();