@sage-protocol/sdk 0.1.18 → 0.1.23

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.
@@ -20,7 +20,7 @@ var require_package = __commonJS({
20
20
  "package.json"(exports2, module2) {
21
21
  module2.exports = {
22
22
  name: "@sage-protocol/sdk",
23
- version: "0.1.18",
23
+ version: "0.1.23",
24
24
  description: "Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).",
25
25
  main: "dist/index.cjs",
26
26
  module: "dist/index.mjs",
@@ -125,7 +125,12 @@ var require_abi = __commonJS({
125
125
  "function userForkCount(address) view returns (uint256)",
126
126
  "function forkCount(string) view returns (uint256)",
127
127
  "function stake(uint256)",
128
- "function unstake(uint256)"
128
+ "function unstake(uint256)",
129
+ // Fork functions
130
+ "function forkSubDAO(string,string)",
131
+ "function forkSubDAO(string,string,bool)",
132
+ "function forkSubDAOWithStable(string,string,(uint256,uint256,uint8,bytes32,bytes32))",
133
+ "function forkSubDAOWithStable(string,string,(uint256,uint256,uint8,bytes32,bytes32),bool)"
129
134
  ];
130
135
  var Factory = [
131
136
  "event SubDAOGovernanceDeployed(address indexed subDAO, address indexed governor, address timelock, address treasury)"
@@ -136,7 +141,6 @@ var require_abi = __commonJS({
136
141
  "function stableCreationFee() view returns (uint256)",
137
142
  "function stableFeeReceiver() view returns (address)",
138
143
  "function stableCreationEnabled() view returns (bool)",
139
- "function stablePromptForkFee() view returns (uint256)",
140
144
  "function stableForkFee() view returns (uint256)",
141
145
  // Core factory reads
142
146
  "function timelockMinDelay() view returns (uint256)",
@@ -166,8 +170,8 @@ var require_abi = __commonJS({
166
170
  "function createSubDAOOperatorWithStableAdvanced(string name, string description, uint8 accessModel, uint256 minStakeAmount, address operatorExecutor, address operatorAdmin, bool anyoneExec, bool governorProposer, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit) returns (address subDAO, address registry)",
167
171
  "function createSubDAOOperator(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount, address operatorExecutor, address operatorAdmin) returns (address subDAO, address registry)",
168
172
  "function createSubDAOOperatorAdvanced(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount, address operatorExecutor, address operatorAdmin, bool anyoneExec, bool governorProposer) returns (address subDAO, address registry)",
169
- "function createForkedSubDAO(string newName, string newDescription, string originalName, address originalSubDAO, address forker) returns (address subDAO, address registry)",
170
- "function createForkedSubDAOWithStable(string newName, string newDescription, string originalName, address originalSubDAO, address forker, uint64 authorizationNonce, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit) returns (address subDAO, address registry)"
173
+ "function createForkedSubDAO(string newName, string newDescription, string originalName, address originalSubDAO, address forker, bool copyLibrary) returns (address subDAO, address registry)",
174
+ "function createForkedSubDAOWithStable(string newName, string newDescription, string originalName, address originalSubDAO, address forker, uint64 authorizationNonce, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit, bool copyLibrary) returns (address subDAO, address registry)"
171
175
  ];
172
176
  var TemplateModule = [
173
177
  "function getActiveTemplates() view returns (uint256[])",
@@ -178,13 +182,19 @@ var require_abi = __commonJS({
178
182
  "function maxCreationBurn() view returns (uint256)"
179
183
  ];
180
184
  var LibraryRegistry = [
181
- "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version)",
185
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
182
186
  "function daoTimelock(address) view returns (address)",
183
- "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version))",
187
+ "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee))",
188
+ "function getLibraryForkFee(address dao) view returns (uint256)",
189
+ "function setLibraryForkFee(address dao, uint256 fee)",
184
190
  "function updateLibrary(address dao, string manifestCID, string version)",
185
191
  "function registerDAO(address dao, address timelock)",
192
+ "function registerForkedDAO(address childDAO, address childTimelock, address parentDAO, string manifestCID, string version)",
193
+ "function initializeLibraryFromFork(address sourceDao, address forkedDao)",
186
194
  "event LibraryUpdated(address indexed dao, string manifestCID, address indexed timelock, string version)",
187
- "event DAORegistered(address indexed dao, address indexed timelock)"
195
+ "event DAORegistered(address indexed dao, address indexed timelock)",
196
+ "event LibraryForked(address indexed sourceDao, address indexed forkedDao, string manifestCID)",
197
+ "event LibraryForkFeeUpdated(address indexed dao, uint256 fee)"
188
198
  ];
189
199
  var PromptRegistry = [
190
200
  "function prompts(string key) view returns (string cid, uint256 version, uint256 timestamp, address author, string forkedFromCID, address originalAuthor, bool isFork, uint256 forkDepth)",
@@ -1513,19 +1523,656 @@ var require_subgraph = __commonJS({
1513
1523
  updatedAt: Number(p.updatedAt || 0)
1514
1524
  };
1515
1525
  },
1516
- async getProposalById({ url, id: id2 }) {
1526
+ async getProposalById({ url, id: id2 }) {
1527
+ if (!url) throw new Error("subgraph url required");
1528
+ const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
1529
+ const data = await query(url, doc, { id: String(id2) });
1530
+ const p = data?.proposal;
1531
+ if (!p) return null;
1532
+ try {
1533
+ const proposer = safeGetAddress(p.proposer);
1534
+ if (!proposer) return null;
1535
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1536
+ if (!targets.length && (p.targets || []).length) return null;
1537
+ return {
1538
+ id: BigInt(p.id),
1539
+ proposer,
1540
+ description: p.description || "",
1541
+ createdAt: Number(p.createdAt || 0),
1542
+ updatedAt: Number(p.updatedAt || 0),
1543
+ state: String(p.state || ""),
1544
+ eta: p.eta ? BigInt(String(p.eta)) : null,
1545
+ targets,
1546
+ values: (p.values || []).map((v) => BigInt(String(v))),
1547
+ calldatas: p.calldatas || []
1548
+ };
1549
+ } catch {
1550
+ return null;
1551
+ }
1552
+ }
1553
+ };
1554
+ }
1555
+ });
1556
+
1557
+ // src/adapters/transports.js
1558
+ var require_transports = __commonJS({
1559
+ "src/adapters/transports.js"(exports2, module2) {
1560
+ function createTransports({ provider, signer = null, subgraph = null }) {
1561
+ return function resolve(kind) {
1562
+ switch (kind) {
1563
+ case "rpc":
1564
+ return provider;
1565
+ case "signer":
1566
+ return { signer };
1567
+ case "subgraph":
1568
+ return { url: subgraph };
1569
+ default:
1570
+ return null;
1571
+ }
1572
+ };
1573
+ }
1574
+ module2.exports = {
1575
+ createTransports
1576
+ };
1577
+ }
1578
+ });
1579
+
1580
+ // src/browser/utils.js
1581
+ var require_utils = __commonJS({
1582
+ "src/browser/utils.js"(exports2, module2) {
1583
+ function getAddress(address) {
1584
+ if (!address) return address;
1585
+ const addr = String(address).trim();
1586
+ const normalized = addr.startsWith("0x") ? addr.slice(2).toLowerCase() : addr.toLowerCase();
1587
+ return `0x${normalized}`;
1588
+ }
1589
+ async function keccak256Async(data) {
1590
+ const encoder = new TextEncoder();
1591
+ const dataBuffer = typeof data === "string" ? encoder.encode(data) : data;
1592
+ const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
1593
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1594
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1595
+ return `0x${hashHex}`;
1596
+ }
1597
+ function keccak256Sync(data) {
1598
+ const str = typeof data === "string" ? data : JSON.stringify(data);
1599
+ let hash = 0;
1600
+ for (let i = 0; i < str.length; i++) {
1601
+ const char = str.charCodeAt(i);
1602
+ hash = (hash << 5) - hash + char;
1603
+ hash = hash & hash;
1604
+ }
1605
+ const hex = Math.abs(hash).toString(16).padStart(8, "0");
1606
+ return `0x${hex.repeat(8)}`.slice(0, 66);
1607
+ }
1608
+ module2.exports = {
1609
+ getAddress,
1610
+ keccak256Async,
1611
+ keccak256Sync
1612
+ };
1613
+ }
1614
+ });
1615
+
1616
+ // src/browser/subgraph.js
1617
+ var require_subgraph2 = __commonJS({
1618
+ "src/browser/subgraph.js"(exports2, module2) {
1619
+ var { getAddress } = require_utils();
1620
+ function sanitizeOrderBy(orderBy, allowed, fallback) {
1621
+ const value = (orderBy || "").toString();
1622
+ return allowed.includes(value) ? value : fallback;
1623
+ }
1624
+ function sanitizeOrderDirection(direction, fallback = "desc") {
1625
+ const v = (direction || "").toString().toLowerCase();
1626
+ return v === "asc" ? "asc" : "desc";
1627
+ }
1628
+ function safeGetAddress(value) {
1629
+ try {
1630
+ return getAddress(value);
1631
+ } catch {
1632
+ return null;
1633
+ }
1634
+ }
1635
+ function mapSafe(list, mapper) {
1636
+ const out = [];
1637
+ for (const item of list || []) {
1638
+ try {
1639
+ const v = mapper(item);
1640
+ if (v != null) out.push(v);
1641
+ } catch {
1642
+ }
1643
+ }
1644
+ return out;
1645
+ }
1646
+ async function query(url, document, variables) {
1647
+ if (!url) throw new Error("subgraph url required");
1648
+ const controller = new AbortController();
1649
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
1650
+ try {
1651
+ const resp = await fetch(url, {
1652
+ method: "POST",
1653
+ headers: { "Content-Type": "application/json" },
1654
+ body: JSON.stringify({ query: document, variables }),
1655
+ signal: controller.signal
1656
+ });
1657
+ clearTimeout(timeoutId);
1658
+ if (!resp.ok) {
1659
+ throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
1660
+ }
1661
+ const data = await resp.json();
1662
+ if (data && data.errors) {
1663
+ throw new Error(data.errors.map((e) => e.message).join("; "));
1664
+ }
1665
+ return data.data;
1666
+ } catch (error) {
1667
+ clearTimeout(timeoutId);
1668
+ throw error;
1669
+ }
1670
+ }
1671
+ async function listProposals({ url, governor, first = 20, skip = 0 }) {
1672
+ const data = await query(url, `
1673
+ query($governor: Bytes!, $first: Int!, $skip: Int!) {
1674
+ proposals(where: { governor: $governor }, first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
1675
+ id
1676
+ proposer
1677
+ description
1678
+ createdAt
1679
+ targets
1680
+ values
1681
+ calldatas
1682
+ }
1683
+ }
1684
+ `, { governor: String(governor).toLowerCase(), first, skip });
1685
+ return mapSafe(data?.proposals, (p) => {
1686
+ const proposer = safeGetAddress(p.proposer);
1687
+ if (!proposer) return null;
1688
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1689
+ if (!targets.length && (p.targets || []).length) return null;
1690
+ return {
1691
+ id: BigInt(p.id),
1692
+ proposer,
1693
+ description: p.description,
1694
+ createdAt: Number(p.createdAt || 0),
1695
+ targets,
1696
+ values: (p.values || []).map((value) => BigInt(String(value))),
1697
+ calldatas: p.calldatas || []
1698
+ };
1699
+ });
1700
+ }
1701
+ var STATE_STRING_TO_NUMBER = {
1702
+ PENDING: 0,
1703
+ ACTIVE: 1,
1704
+ CANCELED: 2,
1705
+ CANCELLED: 2,
1706
+ // some indexes may use British spelling
1707
+ DEFEATED: 3,
1708
+ SUCCEEDED: 4,
1709
+ QUEUED: 5,
1710
+ EXPIRED: 6,
1711
+ EXECUTED: 7
1712
+ };
1713
+ async function listProposalsFiltered({ url, governor, states, fromTimestamp, toTimestamp, first = 20, skip = 0, orderBy = "createdAt", orderDirection = "desc" }) {
1714
+ const govLower = governor ? String(governor).toLowerCase() : null;
1715
+ const statesUpper = Array.isArray(states) && states.length ? states.map((s) => String(s).toUpperCase()) : null;
1716
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["createdAt", "updatedAt", "eta"], "createdAt");
1717
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
1718
+ const doc = `
1719
+ query($first: Int!, $skip: Int!, $governor: Bytes, $states: [String!], $from: Int, $to: Int) {
1720
+ proposals(
1721
+ where: {
1722
+ ${governor ? "governor: $governor," : ""}
1723
+ ${statesUpper ? "state_in: $states," : ""}
1724
+ ${fromTimestamp !== void 0 ? "createdAt_gte: $from," : ""}
1725
+ ${toTimestamp !== void 0 ? "createdAt_lte: $to," : ""}
1726
+ }
1727
+ first: $first
1728
+ skip: $skip
1729
+ orderBy: ${safeOrderBy}
1730
+ orderDirection: ${safeOrderDirection}
1731
+ ) {
1732
+ id
1733
+ proposer
1734
+ description
1735
+ createdAt
1736
+ updatedAt
1737
+ state
1738
+ eta
1739
+ targets
1740
+ values
1741
+ calldatas
1742
+ }
1743
+ }
1744
+ `;
1745
+ const variables = { first, skip };
1746
+ if (govLower) variables.governor = govLower;
1747
+ if (statesUpper) variables.states = statesUpper;
1748
+ if (fromTimestamp !== void 0) variables.from = Number(fromTimestamp);
1749
+ if (toTimestamp !== void 0) variables.to = Number(toTimestamp);
1750
+ const data = await query(url, doc, variables);
1751
+ return mapSafe(data?.proposals, (p) => {
1752
+ const stateStr = String(p.state || "").toUpperCase();
1753
+ const stateNum = STATE_STRING_TO_NUMBER[stateStr] != null ? STATE_STRING_TO_NUMBER[stateStr] : null;
1754
+ const proposer = safeGetAddress(p.proposer);
1755
+ if (!proposer) return null;
1756
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1757
+ if (!targets.length && (p.targets || []).length) return null;
1758
+ return {
1759
+ id: BigInt(p.id),
1760
+ proposer,
1761
+ description: p.description || "",
1762
+ createdAt: Number(p.createdAt || 0),
1763
+ updatedAt: Number(p.updatedAt || 0),
1764
+ state: stateStr,
1765
+ stateNum,
1766
+ eta: p.eta ? BigInt(String(p.eta)) : null,
1767
+ targets,
1768
+ values: (p.values || []).map((value) => BigInt(String(value))),
1769
+ calldatas: p.calldatas || []
1770
+ };
1771
+ });
1772
+ }
1773
+ async function listLibraries({ url, subdao, first = 50, skip = 0 }) {
1774
+ const where = subdao ? `where: { subDAO: "${String(subdao).toLowerCase()}" }` : "";
1775
+ const data = await query(url, `
1776
+ query($first: Int!, $skip: Int!) {
1777
+ libraries(${where} first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
1778
+ id
1779
+ manifestCID
1780
+ subDAO
1781
+ proposer
1782
+ createdAt
1783
+ }
1784
+ }
1785
+ `, { first, skip });
1786
+ return mapSafe(data?.libraries, (lib) => {
1787
+ const sub = safeGetAddress(lib.subDAO);
1788
+ const proposer = safeGetAddress(lib.proposer);
1789
+ if (!sub || !proposer) return null;
1790
+ return {
1791
+ id: lib.id,
1792
+ manifestCID: lib.manifestCID,
1793
+ subdao: sub,
1794
+ proposer,
1795
+ createdAt: Number(lib.createdAt || 0)
1796
+ };
1797
+ });
1798
+ }
1799
+ async function getSubdaoLibraries({ url, subdao, first = 20, skip = 0 }) {
1800
+ if (!url) throw new Error("subgraph url required");
1801
+ const hasFilter = !!subdao;
1802
+ const whereClause = hasFilter ? "where:{ subdao:$subdao }" : "";
1803
+ const doc = `
1804
+ query($subdao:Bytes,$first:Int!,$skip:Int!){
1805
+ subDAOLibraryPointers(
1806
+ ${whereClause}
1807
+ first:$first,
1808
+ skip:$skip,
1809
+ orderBy: updatedAt,
1810
+ orderDirection: desc
1811
+ ){
1812
+ id
1813
+ subdao
1814
+ libraryId
1815
+ manifestCID
1816
+ previousCID
1817
+ promptCount
1818
+ updatedAt
1819
+ }
1820
+ }
1821
+ `;
1822
+ const variables = {
1823
+ first: Math.min(Math.max(1, Number(first || 20)), 100),
1824
+ skip
1825
+ };
1826
+ if (hasFilter) {
1827
+ const addr = safeGetAddress(subdao);
1828
+ if (!addr) throw new Error("invalid subdao address");
1829
+ variables.subdao = addr.toLowerCase();
1830
+ }
1831
+ const data = await query(url, doc, variables);
1832
+ return mapSafe(data?.subDAOLibraryPointers, (row) => {
1833
+ const id2 = row?.id;
1834
+ const manifestCID = row?.manifestCID;
1835
+ const sub = safeGetAddress(row?.subdao);
1836
+ if (!id2 || !manifestCID || !sub) return null;
1837
+ return {
1838
+ id: String(id2),
1839
+ subdao: sub,
1840
+ libraryId: String(row.libraryId || "main"),
1841
+ manifestCID: String(manifestCID),
1842
+ previousCID: row.previousCID || null,
1843
+ promptCount: row.promptCount != null ? Number(row.promptCount) : null,
1844
+ updatedAt: row.updatedAt != null ? Number(row.updatedAt) : null
1845
+ };
1846
+ });
1847
+ }
1848
+ async function getSubdaoPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
1849
+ if (!url) throw new Error("subgraph url required");
1850
+ const reg = safeGetAddress(registry);
1851
+ if (!reg) throw new Error("invalid registry address");
1852
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
1853
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
1854
+ const doc = `
1855
+ query($registry:Bytes!,$first:Int!,$skip:Int!){
1856
+ prompts(
1857
+ where:{ registry:$registry },
1858
+ first:$first,
1859
+ skip:$skip,
1860
+ orderBy: ${safeOrderBy},
1861
+ orderDirection: ${safeOrderDirection}
1862
+ ){
1863
+ id
1864
+ key
1865
+ cid
1866
+ version
1867
+ author
1868
+ registry
1869
+ updatedAt
1870
+ }
1871
+ }
1872
+ `;
1873
+ const data = await query(url, doc, {
1874
+ registry: reg.toLowerCase(),
1875
+ first: Math.min(Math.max(1, Number(first || 50)), 100),
1876
+ skip
1877
+ });
1878
+ return mapSafe(data?.prompts, (p) => {
1879
+ const author = safeGetAddress(p.author);
1880
+ const regAddr = safeGetAddress(p.registry);
1881
+ if (!author || !regAddr) return null;
1882
+ return {
1883
+ id: String(p.id),
1884
+ key: String(p.key),
1885
+ cid: String(p.cid),
1886
+ version: BigInt(p.version || "0"),
1887
+ author,
1888
+ registry: regAddr,
1889
+ updatedAt: Number(p.updatedAt || 0)
1890
+ };
1891
+ });
1892
+ }
1893
+ module2.exports = {
1894
+ query,
1895
+ listProposals,
1896
+ listProposalsFiltered,
1897
+ listLibraries,
1898
+ getSubdaoLibraries,
1899
+ getSubdaoPrompts,
1900
+ /**
1901
+ * Canonical proposal timeline. Tries common fields first, then event-style fallbacks.
1902
+ * Returns { id, createdAt, queuedAt, executedAt, canceledAt, eta, state } (numbers/strings may be null when unavailable).
1903
+ */
1904
+ async getProposalTimeline({ url, id: id2 }) {
1905
+ if (!url) throw new Error("subgraph url required");
1906
+ const pid = typeof id2 === "bigint" ? id2.toString() : String(id2);
1907
+ try {
1908
+ const data = await query(url, `
1909
+ query($id: ID!) {
1910
+ proposal(id: $id) {
1911
+ id
1912
+ createdAt
1913
+ updatedAt
1914
+ state
1915
+ eta
1916
+ queuedAt
1917
+ executedAt
1918
+ canceledAt
1919
+ }
1920
+ }
1921
+ `, { id: pid });
1922
+ if (data && data.proposal) {
1923
+ const p = data.proposal;
1924
+ return {
1925
+ id: p.id,
1926
+ createdAt: Number(p.createdAt || 0),
1927
+ queuedAt: p.queuedAt != null ? Number(p.queuedAt) : null,
1928
+ executedAt: p.executedAt != null ? Number(p.executedAt) : null,
1929
+ canceledAt: p.canceledAt != null ? Number(p.canceledAt) : null,
1930
+ eta: p.eta != null ? BigInt(String(p.eta)) : null,
1931
+ state: String(p.state || "")
1932
+ };
1933
+ }
1934
+ } catch (_) {
1935
+ }
1936
+ try {
1937
+ const data = await query(url, `
1938
+ query($id: String!) {
1939
+ proposalEvents(where: { proposal: $id }, orderBy: timestamp, orderDirection: asc) {
1940
+ type
1941
+ timestamp
1942
+ }
1943
+ proposals(where: { id: $id }, first:1) { id createdAt state eta }
1944
+ }
1945
+ `, { id: pid });
1946
+ const events = (data?.proposalEvents || []).map((e) => ({ type: String(e.type || ""), timestamp: Number(e.timestamp || 0) }));
1947
+ const base = data?.proposals?.[0] || {};
1948
+ const find = (t) => events.find((e) => e.type.toLowerCase() === t)?.timestamp || null;
1949
+ return {
1950
+ id: base.id || pid,
1951
+ createdAt: Number(base.createdAt || 0),
1952
+ queuedAt: find("queued"),
1953
+ executedAt: find("executed"),
1954
+ canceledAt: find("canceled") || find("cancelled") || null,
1955
+ eta: base.eta != null ? BigInt(String(base.eta)) : null,
1956
+ state: String(base.state || "")
1957
+ };
1958
+ } catch (_) {
1959
+ }
1960
+ return { id: pid, createdAt: 0, queuedAt: null, executedAt: null, canceledAt: null, eta: null, state: "" };
1961
+ },
1962
+ async listLiquidityAddPlans({ url, subdao = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
1963
+ if (!url) throw new Error("subgraph url required");
1964
+ const filters = [];
1965
+ if (subdao) {
1966
+ const addr = safeGetAddress(subdao);
1967
+ if (!addr) throw new Error("invalid subdao address");
1968
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
1969
+ }
1970
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
1971
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
1972
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
1973
+ const doc = `
1974
+ query($first:Int!,$skip:Int!){
1975
+ liquidityAddPlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
1976
+ id subdao pool sxxxToken stableToken sxxxAmount stableAmount lpRecipient blockNumber blockTimestamp transactionHash
1977
+ }
1978
+ }
1979
+ `;
1980
+ const data = await query(url, doc, { first, skip });
1981
+ return mapSafe(data?.liquidityAddPlans, (e) => {
1982
+ const sub = safeGetAddress(e.subdao);
1983
+ const pool = safeGetAddress(e.pool);
1984
+ const sxxxToken = safeGetAddress(e.sxxxToken);
1985
+ const stableToken = safeGetAddress(e.stableToken);
1986
+ const lpRecipient = safeGetAddress(e.lpRecipient);
1987
+ if (!sub || !pool || !sxxxToken || !stableToken || !lpRecipient) return null;
1988
+ return {
1989
+ id: String(e.id),
1990
+ subdao: sub,
1991
+ pool,
1992
+ sxxxToken,
1993
+ stableToken,
1994
+ sxxxAmount: BigInt(String(e.sxxxAmount)),
1995
+ stableAmount: BigInt(String(e.stableAmount)),
1996
+ lpRecipient,
1997
+ blockNumber: Number(e.blockNumber || 0),
1998
+ blockTimestamp: Number(e.blockTimestamp || 0),
1999
+ transactionHash: e.transactionHash
2000
+ };
2001
+ });
2002
+ },
2003
+ async listLiquidityRemovePlans({ url, subdao = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
2004
+ if (!url) throw new Error("subgraph url required");
2005
+ const filters = [];
2006
+ if (subdao) {
2007
+ const addr = safeGetAddress(subdao);
2008
+ if (!addr) throw new Error("invalid subdao address");
2009
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
2010
+ }
2011
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
2012
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
2013
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
2014
+ const doc = `
2015
+ query($first:Int!,$skip:Int!){
2016
+ liquidityRemovePlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
2017
+ id subdao pool lpToken lpAmount recipient blockNumber blockTimestamp transactionHash
2018
+ }
2019
+ }
2020
+ `;
2021
+ const data = await query(url, doc, { first, skip });
2022
+ return mapSafe(data?.liquidityRemovePlans, (e) => {
2023
+ const sub = safeGetAddress(e.subdao);
2024
+ const pool = safeGetAddress(e.pool);
2025
+ const lpToken = safeGetAddress(e.lpToken);
2026
+ const recipient = safeGetAddress(e.recipient);
2027
+ if (!sub || !pool || !lpToken || !recipient) return null;
2028
+ return {
2029
+ id: String(e.id),
2030
+ subdao: sub,
2031
+ pool,
2032
+ lpToken,
2033
+ lpAmount: BigInt(String(e.lpAmount)),
2034
+ recipient,
2035
+ blockNumber: Number(e.blockNumber || 0),
2036
+ blockTimestamp: Number(e.blockTimestamp || 0),
2037
+ transactionHash: e.transactionHash
2038
+ };
2039
+ });
2040
+ },
2041
+ async listPromptsByTag({ url, tagsHash, registry = null, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
2042
+ if (!url) throw new Error("subgraph url required");
2043
+ const clauses = [`tagsHash: "${String(tagsHash)}"`];
2044
+ if (registry) {
2045
+ const addr = safeGetAddress(registry);
2046
+ if (!addr) throw new Error("invalid registry address");
2047
+ clauses.push(`registry: "${addr.toLowerCase()}"`);
2048
+ }
2049
+ const where = `where: { ${clauses.join(", ")} }`;
2050
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
2051
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
2052
+ const doc = `
2053
+ query($first:Int!,$skip:Int!) {
2054
+ prompts(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
2055
+ id key cid version author registry updatedAt tagsHash
2056
+ }
2057
+ }
2058
+ `;
2059
+ const data = await query(url, doc, { first, skip });
2060
+ return mapSafe(data?.prompts, (p) => {
2061
+ const author = safeGetAddress(p.author);
2062
+ const regAddr = safeGetAddress(p.registry);
2063
+ if (!author || !regAddr) return null;
2064
+ return {
2065
+ id: String(p.id),
2066
+ key: String(p.key),
2067
+ cid: String(p.cid),
2068
+ version: BigInt(p.version || "0"),
2069
+ author,
2070
+ registry: regAddr,
2071
+ updatedAt: Number(p.updatedAt || 0),
2072
+ tagsHash: String(p.tagsHash || "")
2073
+ };
2074
+ });
2075
+ },
2076
+ // Prompt helpers (registry scoped)
2077
+ async listRegistryPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
2078
+ if (!url) throw new Error("subgraph url required");
2079
+ const reg = safeGetAddress(registry);
2080
+ if (!reg) throw new Error("invalid registry address");
2081
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
2082
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
2083
+ const doc = `
2084
+ query($first:Int!,$skip:Int!,$registry:Bytes!) {
2085
+ prompts(where:{ registry: $registry }, first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
2086
+ id
2087
+ key
2088
+ cid
2089
+ version
2090
+ author
2091
+ registry
2092
+ updatedAt
2093
+ }
2094
+ }
2095
+ `;
2096
+ const data = await query(url, doc, { first, skip, registry: reg.toLowerCase() });
2097
+ return mapSafe(data?.prompts, (p) => {
2098
+ const author = safeGetAddress(p.author);
2099
+ const regAddr = safeGetAddress(p.registry);
2100
+ if (!author || !regAddr) return null;
2101
+ return {
2102
+ id: String(p.id),
2103
+ key: String(p.key),
2104
+ cid: String(p.cid),
2105
+ version: BigInt(p.version || "0"),
2106
+ author,
2107
+ registry: regAddr,
2108
+ updatedAt: Number(p.updatedAt || 0)
2109
+ };
2110
+ });
2111
+ },
2112
+ async getPromptByKey({ url, registry, key }) {
2113
+ if (!url) throw new Error("subgraph url required");
2114
+ const reg = safeGetAddress(registry);
2115
+ if (!reg) throw new Error("invalid registry address");
2116
+ const doc = `
2117
+ query($registry:Bytes!,$key:String!) {
2118
+ prompts(where:{ registry: $registry, key: $key }, first:1) {
2119
+ id
2120
+ key
2121
+ cid
2122
+ version
2123
+ author
2124
+ registry
2125
+ updatedAt
2126
+ }
2127
+ }
2128
+ `;
2129
+ const data = await query(url, doc, { registry: reg.toLowerCase(), key: String(key) });
2130
+ const p = (data?.prompts || [])[0];
2131
+ if (!p) return null;
2132
+ const author = safeGetAddress(p.author);
2133
+ const regAddr = safeGetAddress(p.registry);
2134
+ if (!author || !regAddr) return null;
2135
+ return {
2136
+ id: String(p.id),
2137
+ key: String(p.key),
2138
+ cid: String(p.cid),
2139
+ version: BigInt(p.version || "0"),
2140
+ author,
2141
+ registry: regAddr,
2142
+ updatedAt: Number(p.updatedAt || 0)
2143
+ };
2144
+ },
2145
+ async getProposalById({ url, id: id2, governor }) {
1517
2146
  if (!url) throw new Error("subgraph url required");
1518
- const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
1519
- const data = await query(url, doc, { id: String(id2) });
1520
- const p = data?.proposal;
2147
+ let p = null;
2148
+ if (governor) {
2149
+ const govLower = String(governor).toLowerCase();
2150
+ const compositeId = `${govLower}-${String(id2)}`;
2151
+ const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
2152
+ const data = await query(url, doc, { id: compositeId });
2153
+ p = data?.proposal;
2154
+ }
2155
+ if (!p && governor) {
2156
+ const govLower = String(governor).toLowerCase();
2157
+ const doc = `query($gov: Bytes!, $first: Int!){ proposals(where:{governor:$gov}, first:$first, orderBy:createdAt, orderDirection:desc){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
2158
+ const data = await query(url, doc, { gov: govLower, first: 100 });
2159
+ const proposals = data?.proposals || [];
2160
+ p = proposals.find((prop) => {
2161
+ const parts = String(prop.id || "").split("-");
2162
+ const propId = parts.length > 1 ? parts[parts.length - 1] : prop.id;
2163
+ return String(propId) === String(id2) || propId && String(BigInt(propId)) === String(BigInt(id2));
2164
+ });
2165
+ }
1521
2166
  if (!p) return null;
1522
2167
  try {
1523
2168
  const proposer = safeGetAddress(p.proposer);
1524
2169
  if (!proposer) return null;
1525
2170
  const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1526
2171
  if (!targets.length && (p.targets || []).length) return null;
2172
+ const idParts = String(p.id || "").split("-");
2173
+ const actualId = idParts.length > 1 ? idParts[idParts.length - 1] : p.id;
1527
2174
  return {
1528
- id: BigInt(p.id),
2175
+ id: BigInt(actualId),
1529
2176
  proposer,
1530
2177
  description: p.description || "",
1531
2178
  createdAt: Number(p.createdAt || 0),
@@ -1544,29 +2191,6 @@ var require_subgraph = __commonJS({
1544
2191
  }
1545
2192
  });
1546
2193
 
1547
- // src/adapters/transports.js
1548
- var require_transports = __commonJS({
1549
- "src/adapters/transports.js"(exports2, module2) {
1550
- function createTransports({ provider, signer = null, subgraph = null }) {
1551
- return function resolve(kind) {
1552
- switch (kind) {
1553
- case "rpc":
1554
- return provider;
1555
- case "signer":
1556
- return { signer };
1557
- case "subgraph":
1558
- return { url: subgraph };
1559
- default:
1560
- return null;
1561
- }
1562
- };
1563
- }
1564
- module2.exports = {
1565
- createTransports
1566
- };
1567
- }
1568
- });
1569
-
1570
2194
  // src/ipfs/index.js
1571
2195
  var require_ipfs = __commonJS({
1572
2196
  "src/ipfs/index.js"(exports2, module2) {
@@ -1756,7 +2380,6 @@ var require_ipfs = __commonJS({
1756
2380
  headers["X-Wallet-Address"] = auth.address;
1757
2381
  headers["X-Wallet-Signature"] = auth.signature;
1758
2382
  headers["X-Wallet-Nonce"] = auth.nonce;
1759
- headers["X-Wallet-Message"] = auth.message;
1760
2383
  }
1761
2384
  return { headers, auth };
1762
2385
  }
@@ -1777,8 +2400,7 @@ var require_ipfs = __commonJS({
1777
2400
  ...extraHeaders,
1778
2401
  "X-Wallet-Address": auth.address,
1779
2402
  "X-Wallet-Signature": auth.signature,
1780
- "X-Wallet-Nonce": auth.nonce,
1781
- "X-Wallet-Message": auth.message
2403
+ "X-Wallet-Nonce": auth.nonce
1782
2404
  };
1783
2405
  return { headers, auth };
1784
2406
  }
@@ -1799,6 +2421,13 @@ var require_ipfs = __commonJS({
1799
2421
  order.push(name);
1800
2422
  };
1801
2423
  const normalizedPreference = Array.isArray(preference) ? preference.map((p) => toLowerSafe(p)).filter(Boolean) : preference ? [toLowerSafe(preference)].filter(Boolean) : [];
2424
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2425
+ console.log("[SDK DEBUG] resolveProviderOrder preference:", preference);
2426
+ console.log("[SDK DEBUG] normalizedPreference:", normalizedPreference);
2427
+ console.log("[SDK DEBUG] config.provider:", config.provider);
2428
+ console.log("[SDK DEBUG] shouldUseWorker():", shouldUseWorker());
2429
+ console.log("[SDK DEBUG] hasPinataCreds():", hasPinataCreds());
2430
+ }
1802
2431
  normalizedPreference.forEach(append);
1803
2432
  if (shouldUseWorker()) append("worker");
1804
2433
  if (hasPinataCreds()) append("pinata");
@@ -1806,17 +2435,90 @@ var require_ipfs = __commonJS({
1806
2435
  if (config.simulate) append("simulate");
1807
2436
  return order;
1808
2437
  }
1809
- async function uploadViaWorker(payload, { warm, gateways } = {}) {
2438
+ async function uploadViaWorker(payload, { warm, gateways, pin: pin2 } = {}) {
2439
+ const uploadUrl = workerUrl("upload");
2440
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2441
+ console.log("[SDK DEBUG] uploadViaWorker called");
2442
+ console.log("[SDK DEBUG] workerBaseUrl:", workerBaseUrl());
2443
+ console.log("[SDK DEBUG] uploadUrl:", uploadUrl);
2444
+ console.log("[SDK DEBUG] workerHasAuth:", workerHasAuth());
2445
+ }
1810
2446
  const { headers, auth } = await buildWorkerAuthHeaders({ "Content-Type": "application/json" });
1811
2447
  const body = { ...payload };
1812
2448
  if (auth) body.auth = auth;
1813
- const response = await axiosInstance.post(workerUrl("upload"), body, { headers, timeout: config.timeoutMs });
1814
- const cid = response?.data?.cid || response?.data?.IpfsHash;
2449
+ if (pin2) {
2450
+ body.pin = typeof pin2 === "string" ? { duration: pin2 } : pin2;
2451
+ }
2452
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2453
+ console.log("[SDK DEBUG] headers:", Object.keys(headers));
2454
+ console.log("[SDK DEBUG] hasAuth:", !!auth);
2455
+ if (pin2) console.log("[SDK DEBUG] pin:", JSON.stringify(body.pin));
2456
+ }
2457
+ let response;
2458
+ try {
2459
+ response = await axiosInstance.post(uploadUrl, body, { headers, timeout: config.timeoutMs });
2460
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2461
+ console.log("[SDK DEBUG] Upload response status:", response?.status);
2462
+ console.log("[SDK DEBUG] Upload response data:", JSON.stringify(response?.data || {}));
2463
+ }
2464
+ } catch (uploadErr) {
2465
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2466
+ console.log("[SDK DEBUG] Upload error:", uploadErr.message);
2467
+ console.log("[SDK DEBUG] Response status:", uploadErr.response?.status);
2468
+ console.log("[SDK DEBUG] Response data:", JSON.stringify(uploadErr.response?.data || {}));
2469
+ }
2470
+ const status = uploadErr.response?.status;
2471
+ const data2 = uploadErr.response?.data;
2472
+ if (status === 400 && data2?.error === "content_blocked") {
2473
+ const error = new Error("content_blocked");
2474
+ error.code = "CONTENT_BLOCKED";
2475
+ error.categories = data2.categories || [];
2476
+ error.reason = data2.reason;
2477
+ error.response = data2;
2478
+ throw error;
2479
+ }
2480
+ if (status === 402) {
2481
+ const error = new Error("payment_required");
2482
+ error.code = "PAYMENT_REQUIRED";
2483
+ error.creditsNeeded = data2?.creditsNeeded;
2484
+ error.balance = data2?.balance;
2485
+ error.duration = data2?.duration;
2486
+ error.accepts = data2?.accepts;
2487
+ error.response = data2;
2488
+ throw error;
2489
+ }
2490
+ throw uploadErr;
2491
+ }
2492
+ const data = response?.data || {};
2493
+ const cid = data.cid || data.IpfsHash;
2494
+ if (response?.status === 202 || data.status === "pending_review") {
2495
+ return {
2496
+ cid: cid || null,
2497
+ provider: "worker",
2498
+ status: "pending_review",
2499
+ categories: data.categories || [],
2500
+ response: data
2501
+ };
2502
+ }
1815
2503
  if (!cid) {
1816
2504
  throw new Error("Worker response missing cid");
1817
2505
  }
1818
2506
  if (warm || config.shouldWarm) await warmGateways(cid, { gateways });
1819
- return { cid, provider: "worker", response: response?.data || null };
2507
+ const result = {
2508
+ cid,
2509
+ provider: "worker",
2510
+ response: data
2511
+ };
2512
+ if (data.moderation) {
2513
+ result.moderation = data.moderation;
2514
+ }
2515
+ if (data.pinned !== void 0) {
2516
+ result.pinned = data.pinned;
2517
+ result.expiresAt = data.expiresAt;
2518
+ result.creditsPaid = data.creditsPaid;
2519
+ result.urls = data.urls;
2520
+ }
2521
+ return result;
1820
2522
  }
1821
2523
  async function uploadToPinata(payload, { filename = "payload.json", metadata, warm, gateways } = {}) {
1822
2524
  if (!hasPinataCreds()) {
@@ -1894,7 +2596,7 @@ var require_ipfs = __commonJS({
1894
2596
  return { cid, provider: "simulate" };
1895
2597
  }
1896
2598
  async function uploadPayload(payload, options2 = {}) {
1897
- const { providers, provider, warm, gateways, filename, metadata } = options2;
2599
+ const { providers, provider, warm, gateways, filename, metadata, pin: pin2 } = options2;
1898
2600
  const order = resolveProviderOrder(providers || provider);
1899
2601
  if (!order.length) {
1900
2602
  throw new Error("No IPFS providers configured. Set Pinata credentials, worker upload, or enable test mode");
@@ -1903,7 +2605,7 @@ var require_ipfs = __commonJS({
1903
2605
  for (const candidate of order) {
1904
2606
  try {
1905
2607
  if (candidate === "worker") {
1906
- return await uploadViaWorker(payload, { warm, gateways });
2608
+ return await uploadViaWorker(payload, { warm, gateways, pin: pin2 });
1907
2609
  }
1908
2610
  if (candidate === "pinata") {
1909
2611
  return await uploadToPinata(payload, { filename, metadata, warm, gateways });
@@ -1915,6 +2617,9 @@ var require_ipfs = __commonJS({
1915
2617
  return await uploadSimulated(payload, { warm, gateways });
1916
2618
  }
1917
2619
  } catch (error2) {
2620
+ if (error2.code === "CONTENT_BLOCKED" || error2.code === "PAYMENT_REQUIRED") {
2621
+ throw error2;
2622
+ }
1918
2623
  errors.push({ provider: candidate, error: error2 });
1919
2624
  }
1920
2625
  }
@@ -1923,7 +2628,7 @@ var require_ipfs = __commonJS({
1923
2628
  throw error;
1924
2629
  }
1925
2630
  async function uploadPrompt(options2 = {}) {
1926
- const { prompt, providers, provider, warm, gateways } = options2;
2631
+ const { prompt, providers, provider, warm, gateways, pin: pin2 } = options2;
1927
2632
  if (!prompt || typeof prompt !== "object") {
1928
2633
  throw new Error("prompt payload required");
1929
2634
  }
@@ -1949,6 +2654,7 @@ var require_ipfs = __commonJS({
1949
2654
  provider,
1950
2655
  warm,
1951
2656
  gateways,
2657
+ pin: pin2,
1952
2658
  filename: `${prompt.name || "prompt"}.json`,
1953
2659
  metadata
1954
2660
  });
@@ -2183,8 +2889,7 @@ var require_ipfs = __commonJS({
2183
2889
  "Content-Type": "application/json",
2184
2890
  "X-Wallet-Address": address,
2185
2891
  "X-Wallet-Signature": signature,
2186
- "X-Wallet-Nonce": nonce,
2187
- "X-Wallet-Message": message
2892
+ "X-Wallet-Nonce": nonce
2188
2893
  };
2189
2894
  let verified = false;
2190
2895
  try {
@@ -2428,6 +3133,15 @@ var require_validation = __commonJS({
2428
3133
  path2.join(__dirname, "..", "..", "docs", "schemas", "manifest.schema.json")
2429
3134
  ];
2430
3135
  }
3136
+ function normaliseV3SchemaPaths(v3SchemaPaths, { path: path2 }) {
3137
+ if (Array.isArray(v3SchemaPaths) && v3SchemaPaths.length) {
3138
+ return v3SchemaPaths;
3139
+ }
3140
+ return [
3141
+ path2.join(process.cwd(), "docs", "schemas", "manifest.v3.schema.json"),
3142
+ path2.join(__dirname, "..", "..", "docs", "schemas", "manifest.v3.schema.json")
3143
+ ];
3144
+ }
2431
3145
  function safeJsonParse(fs2, file) {
2432
3146
  try {
2433
3147
  const raw = fs2.readFileSync(file, "utf8");
@@ -2436,17 +3150,17 @@ var require_validation = __commonJS({
2436
3150
  return null;
2437
3151
  }
2438
3152
  }
2439
- function deriveHints(errors = []) {
3153
+ function deriveHints(errors = [], { version = "2.0.0" } = {}) {
2440
3154
  const hints = /* @__PURE__ */ new Set();
2441
3155
  for (const err of errors) {
2442
3156
  const keyword = (err.keyword || "").toLowerCase();
2443
3157
  const instancePath = err.instancePath || "/";
2444
3158
  const message = (err.message || "").toLowerCase();
2445
3159
  if (keyword === "required" && instancePath === "/") {
2446
- hints.add('Add a top-level "library" object and set "version": "2.0.0"');
3160
+ hints.add('Add a top-level "library" object and set "version": "3.0.0"');
2447
3161
  }
2448
3162
  if (message.includes("version") || instancePath === "/version") {
2449
- hints.add('Ensure "version" is exactly the semver string "2.0.0"');
3163
+ hints.add('Ensure "version" is exactly the semver string "3.0.0"');
2450
3164
  }
2451
3165
  if (keyword === "required" && instancePath.includes("/prompts")) {
2452
3166
  hints.add('Each prompt should define a unique "key"');
@@ -2460,17 +3174,23 @@ var require_validation = __commonJS({
2460
3174
  path: path2 = pathDefault,
2461
3175
  ajvFactory = defaultAjvFactory,
2462
3176
  addFormats = defaultAddFormats,
2463
- schemaPaths
3177
+ schemaPaths,
3178
+ v3SchemaPaths
2464
3179
  } = options;
2465
3180
  const searchPaths = normaliseSchemaPaths(schemaPaths, { path: path2 });
2466
- function loadSchema() {
2467
- for (const schemaPath of searchPaths) {
3181
+ const v3SearchPaths = normaliseV3SchemaPaths(v3SchemaPaths, { path: path2 });
3182
+ function loadSchema(version = "2.0.0") {
3183
+ const paths = version === "3.0.0" ? v3SearchPaths : searchPaths;
3184
+ for (const schemaPath of paths) {
2468
3185
  if (!fs2.existsSync(schemaPath)) continue;
2469
3186
  const schema = safeJsonParse(fs2, schemaPath);
2470
3187
  if (schema) return { schema, schemaPath };
2471
3188
  }
2472
3189
  return { schema: null, schemaPath: null };
2473
3190
  }
3191
+ function detectVersion(manifest) {
3192
+ return "3.0.0";
3193
+ }
2474
3194
  function lintManifest(manifest, { enforceVersion = true, manifestPath = null } = {}) {
2475
3195
  if (!manifest || typeof manifest !== "object") {
2476
3196
  return {
@@ -2483,16 +3203,18 @@ var require_validation = __commonJS({
2483
3203
  manifestPath
2484
3204
  };
2485
3205
  }
2486
- const { schema, schemaPath } = loadSchema();
3206
+ const detectedVersion = detectVersion(manifest);
3207
+ const { schema, schemaPath } = loadSchema(detectedVersion);
2487
3208
  if (!schema) {
3209
+ const schemaFile = detectedVersion === "3.0.0" ? "manifest.v3.schema.json" : "manifest.schema.json";
2488
3210
  return {
2489
3211
  ok: false,
2490
3212
  versionOk: false,
2491
3213
  missingSchema: true,
2492
3214
  schemaPath: null,
2493
- errors: [{ keyword: "schema", instancePath: "/", message: "manifest schema not found" }],
3215
+ errors: [{ keyword: "schema", instancePath: "/", message: `manifest schema not found for version ${detectedVersion}` }],
2494
3216
  hints: [
2495
- 'Ensure docs/schemas/manifest.schema.json exists (run "sage project scaffold" to regenerate)'
3217
+ `Ensure docs/schemas/${schemaFile} exists (run "sage project scaffold" to regenerate)`
2496
3218
  ],
2497
3219
  manifestPath
2498
3220
  };
@@ -2511,19 +3233,19 @@ var require_validation = __commonJS({
2511
3233
  let versionOk = true;
2512
3234
  const version = manifest?.version;
2513
3235
  if (valid && enforceVersion) {
2514
- const isV2Semver = typeof version === "string" && version.trim() === "2.0.0";
2515
- versionOk = isV2Semver;
3236
+ const isValidVersion = detectedVersion === "3.0.0" ? typeof version === "string" && version.trim() === "3.0.0" : typeof version === "string" && version.trim() === "2.0.0";
3237
+ versionOk = isValidVersion;
2516
3238
  if (!versionOk) {
2517
3239
  validationErrors.push({
2518
3240
  keyword: "const",
2519
3241
  instancePath: "/version",
2520
- message: 'version must be the semver string "2.0.0"',
3242
+ message: `version must be the semver string "${detectedVersion}"`,
2521
3243
  schemaPath: "#/properties/version",
2522
- params: { allowedValue: "2.0.0" }
3244
+ params: { allowedValue: detectedVersion }
2523
3245
  });
2524
3246
  }
2525
3247
  }
2526
- const hints = deriveHints(validationErrors);
3248
+ const hints = deriveHints(validationErrors, { version: detectedVersion });
2527
3249
  return {
2528
3250
  ok: valid && versionOk,
2529
3251
  versionOk,
@@ -2532,7 +3254,8 @@ var require_validation = __commonJS({
2532
3254
  errors: validationErrors,
2533
3255
  hints,
2534
3256
  manifestPath,
2535
- version
3257
+ version,
3258
+ detectedVersion
2536
3259
  };
2537
3260
  }
2538
3261
  function lintManifestFile(manifestPath, options2 = {}) {
@@ -2604,6 +3327,7 @@ var require_validation = __commonJS({
2604
3327
  }
2605
3328
  return {
2606
3329
  loadSchema,
3330
+ detectVersion,
2607
3331
  lintManifest,
2608
3332
  lintManifestFile,
2609
3333
  bestPracticeCheck,
@@ -2701,7 +3425,6 @@ var require_library = __commonJS({
2701
3425
  ]);
2702
3426
  return { to, data, value: 0n };
2703
3427
  }
2704
- var buildUpdateLibraryForSubDAOTx = buildUpdateLibraryTx;
2705
3428
  module2.exports = {
2706
3429
  listManifests,
2707
3430
  getManifestInfo,
@@ -2709,7 +3432,6 @@ var require_library = __commonJS({
2709
3432
  getLatestLibrary,
2710
3433
  hasScopedOwnership,
2711
3434
  buildUpdateLibraryTx,
2712
- buildUpdateLibraryForSubDAOTx,
2713
3435
  _computeLibraryKey,
2714
3436
  getBeforeAfterForUpdate,
2715
3437
  /** Build an authorizeTimelock(timelock, subdao) call for a LibraryRegistry. */
@@ -2829,12 +3551,35 @@ var require_governance = __commonJS({
2829
3551
  votes: { against, for: _for, abstain }
2830
3552
  };
2831
3553
  }
2832
- async function listProposals({ provider, governor, fromBlock = 0, toBlock = "latest" }) {
3554
+ async function listProposals({ provider, governor, fromBlock, toBlock = "latest", subgraphUrl }) {
2833
3555
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
2834
3556
  const addr = normaliseGovernor(governor);
3557
+ const sgUrl = subgraphUrl || process.env.SAGE_SUBGRAPH_URL || process.env.SUBGRAPH_URL || null;
3558
+ if (sgUrl) {
3559
+ try {
3560
+ const browserSubgraph = require_subgraph2();
3561
+ const sgProposals = await browserSubgraph.listProposals({ url: sgUrl, governor: addr, first: 100 });
3562
+ if (sgProposals && sgProposals.length > 0) {
3563
+ return sgProposals.map((p) => ({
3564
+ id: BigInt(p.id),
3565
+ proposer: p.proposer,
3566
+ targets: p.targets || [],
3567
+ values: (p.values || []).map((v) => BigInt(v)),
3568
+ calldatas: p.calldatas || [],
3569
+ signatures: [],
3570
+ description: p.description || "",
3571
+ descriptionHash: p.description ? hashDescription(p.description) : null,
3572
+ createdAt: p.createdAt
3573
+ }));
3574
+ }
3575
+ } catch (_) {
3576
+ }
3577
+ }
3578
+ const currentBlock = await provider.getBlockNumber();
3579
+ const effectiveFromBlock = fromBlock !== void 0 ? fromBlock : Math.max(0, currentBlock - 5e4);
2835
3580
  const iface = new Interface([ABI.Events.ProposalCreated]);
2836
3581
  const topic = iface.getEvent("ProposalCreated").topicHash;
2837
- const logs = await provider.getLogs({ address: addr, fromBlock, toBlock, topics: [topic] });
3582
+ const logs = await provider.getLogs({ address: addr, fromBlock: effectiveFromBlock, toBlock, topics: [topic] });
2838
3583
  const proposals = [];
2839
3584
  for (const log of logs) {
2840
3585
  try {
@@ -2847,7 +3592,8 @@ var require_governance = __commonJS({
2847
3592
  calldatas: parsed.args.calldatas.map((data) => hexlify(data)),
2848
3593
  signatures: parsed.args.signatures ? parsed.args.signatures.map(String) : [],
2849
3594
  description: parsed.args.description,
2850
- descriptionHash: hashDescription(parsed.args.description)
3595
+ descriptionHash: hashDescription(parsed.args.description),
3596
+ blockNumber: log.blockNumber
2851
3597
  });
2852
3598
  } catch (err) {
2853
3599
  continue;
@@ -2855,13 +3601,38 @@ var require_governance = __commonJS({
2855
3601
  }
2856
3602
  return proposals;
2857
3603
  }
2858
- async function getProposalMetadata({ provider, governor, id: id2, fromBlock = 0, toBlock = "latest" }) {
3604
+ async function getProposalMetadata({ provider, governor, id: id2, fromBlock, toBlock = "latest", subgraphUrl }) {
2859
3605
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
2860
3606
  const addr = normaliseGovernor(governor);
3607
+ const pid = typeof id2 === "bigint" ? id2 : String(id2).startsWith("0x") ? BigInt(id2) : BigInt(String(id2));
3608
+ const sgUrl = subgraphUrl || process.env.SAGE_SUBGRAPH_URL || process.env.SUBGRAPH_URL || null;
3609
+ if (sgUrl) {
3610
+ try {
3611
+ const browserSubgraph = require_subgraph2();
3612
+ const sgProposal = await browserSubgraph.getProposalById({ url: sgUrl, id: String(pid), governor: addr });
3613
+ if (sgProposal && sgProposal.targets) {
3614
+ return {
3615
+ governor: addr,
3616
+ id: pid,
3617
+ proposer: sgProposal.proposer,
3618
+ targets: sgProposal.targets || [],
3619
+ values: (sgProposal.values || []).map((v) => BigInt(v)),
3620
+ calldatas: sgProposal.calldatas || [],
3621
+ signatures: [],
3622
+ description: sgProposal.description || "",
3623
+ descriptionHash: sgProposal.description ? hashDescription(sgProposal.description) : null,
3624
+ blockNumber: sgProposal.createdAt || null,
3625
+ source: "subgraph"
3626
+ };
3627
+ }
3628
+ } catch (_) {
3629
+ }
3630
+ }
3631
+ const currentBlock = await provider.getBlockNumber();
3632
+ const effectiveFromBlock = fromBlock !== void 0 ? fromBlock : Math.max(0, currentBlock - 5e4);
2861
3633
  const iface = new Interface([ABI.Events.ProposalCreated]);
2862
3634
  const topic = iface.getEvent("ProposalCreated").topicHash;
2863
- const pid = typeof id2 === "bigint" ? id2 : String(id2).startsWith("0x") ? BigInt(id2) : BigInt(String(id2));
2864
- const logs = await provider.getLogs({ address: addr, fromBlock, toBlock, topics: [topic] });
3635
+ const logs = await provider.getLogs({ address: addr, fromBlock: effectiveFromBlock, toBlock, topics: [topic] });
2865
3636
  for (const log of logs) {
2866
3637
  try {
2867
3638
  const parsed = iface.parseLog(log);
@@ -2979,25 +3750,40 @@ var require_governance = __commonJS({
2979
3750
  if (!parsed) throw new Error("ProposalCreated event not found");
2980
3751
  const targets = parsed.args.targets.map(getAddress);
2981
3752
  const calldatas = parsed.args.calldatas.map((d) => typeof d === "string" ? d : "0x" + Buffer.from(d).toString("hex"));
2982
- const LibraryIface = new Interface(["function updateLibraryForSubDAO(address,string,string,uint256)", "function subdaoLibraryLatest(bytes32) view returns (string)"]);
3753
+ const LibraryIface = new Interface(["function updateLibrary(address,string,string)"]);
2983
3754
  const PromptIface = new Interface(["function updatePromptByGovernance(string,string)"]);
2984
- const coder = AbiCoder.defaultAbiCoder ? AbiCoder.defaultAbiCoder() : new AbiCoder();
2985
3755
  const effects = [];
2986
3756
  for (let i = 0; i < calldatas.length; i++) {
2987
3757
  const data = calldatas[i];
2988
3758
  const sel = data.slice(0, 10);
2989
3759
  try {
2990
- const decoded = LibraryIface.decodeFunctionData("updateLibraryForSubDAO", data);
2991
- const [subdao, libraryId, newCid, promptCount] = decoded;
3760
+ const decoded = LibraryIface.decodeFunctionData("updateLibrary", data);
3761
+ const [dao, newCid, version] = decoded;
2992
3762
  let previousCID = null;
3763
+ let previousVersion = null;
2993
3764
  try {
2994
- const reg = new Contract(targets[i], ["function subdaoLibraryLatest(bytes32) view returns (string)"], provider);
2995
- const key = keccak256(coder.encode(["address", "string"], [getAddress(subdao), String(libraryId)]));
2996
- const prev = await reg.subdaoLibraryLatest(key).catch(() => "");
2997
- previousCID = prev && prev.length ? String(prev) : null;
3765
+ const reg = new Contract(
3766
+ targets[i],
3767
+ ["function libraryByDAO(address) view returns (tuple(string manifestCID,address lastUpdater,uint256 lastUpdated,string version,address forkedFromDAO,uint256 sxxxForkFee))"],
3768
+ provider
3769
+ );
3770
+ const info = await reg.libraryByDAO(dao).catch(() => null);
3771
+ if (info && typeof info.manifestCID === "string") {
3772
+ previousCID = info.manifestCID || null;
3773
+ previousVersion = info.version || null;
3774
+ }
2998
3775
  } catch (_) {
2999
3776
  }
3000
- effects.push({ type: "libraryUpdate", index: i, target: targets[i], subdao: getAddress(subdao), libraryId: String(libraryId), previousCid: previousCID, newCid: String(newCid), promptCount: Number(promptCount) });
3777
+ effects.push({
3778
+ type: "libraryUpdateV4",
3779
+ index: i,
3780
+ target: targets[i],
3781
+ dao: getAddress(dao),
3782
+ previousCid: previousCID,
3783
+ previousVersion,
3784
+ newCid: String(newCid),
3785
+ newVersion: String(version)
3786
+ });
3001
3787
  continue;
3002
3788
  } catch (_) {
3003
3789
  }
@@ -3042,13 +3828,10 @@ var require_governance = __commonJS({
3042
3828
  } else {
3043
3829
  const govAddr = normaliseGovernor(governor);
3044
3830
  try {
3045
- const iface = new Interface(["function sxxxToken() view returns (address)"]);
3046
- const data = iface.encodeFunctionData("sxxxToken", []);
3047
- const ret = await provider.call({ to: govAddr, data });
3048
- const [tok] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3049
- addr = getAddress(tok);
3831
+ const chain = await resolveVotesTokenChain({ provider, governor: govAddr });
3832
+ addr = getAddress(chain.votingToken);
3050
3833
  } catch (err) {
3051
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve governance token from governor", { cause: err });
3834
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token from governor", { cause: err });
3052
3835
  }
3053
3836
  }
3054
3837
  const user = getAddress(account);
@@ -3129,6 +3912,210 @@ var require_governance = __commonJS({
3129
3912
  const token = await g.sxxxToken();
3130
3913
  return buildDelegateTx({ token, delegatee: account });
3131
3914
  }
3915
+ async function resolveVotesTokenChain({ provider, subdao, governor }) {
3916
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3917
+ if (!subdao && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3918
+ let votingToken = null;
3919
+ if (governor) {
3920
+ const govAddr = normaliseGovernor(governor);
3921
+ try {
3922
+ const iTok = new Interface(["function token() view returns (address)"]);
3923
+ const data = iTok.encodeFunctionData("token", []);
3924
+ const ret = await provider.call({ to: govAddr, data });
3925
+ if (ret && ret !== "0x") {
3926
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3927
+ votingToken = addr;
3928
+ }
3929
+ } catch (_) {
3930
+ }
3931
+ if (!votingToken) {
3932
+ try {
3933
+ const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3934
+ const d2 = iGov.encodeFunctionData("sxxxToken", []);
3935
+ const r2 = await provider.call({ to: govAddr, data: d2 });
3936
+ if (r2 && r2 !== "0x") {
3937
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3938
+ votingToken = addr;
3939
+ }
3940
+ } catch (_) {
3941
+ }
3942
+ }
3943
+ }
3944
+ if (!votingToken && subdao) {
3945
+ try {
3946
+ const subAddr = getAddress(subdao);
3947
+ const iSub = new Interface(["function stakeToken() view returns (address)"]);
3948
+ const d3 = iSub.encodeFunctionData("stakeToken", []);
3949
+ const r3 = await provider.call({ to: subAddr, data: d3 });
3950
+ if (r3 && r3 !== "0x") {
3951
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3952
+ votingToken = addr;
3953
+ }
3954
+ } catch (_) {
3955
+ }
3956
+ }
3957
+ if (!votingToken) {
3958
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3959
+ }
3960
+ const votingTokenNorm = getAddress(votingToken);
3961
+ let baseToken = votingTokenNorm;
3962
+ let isWrapper = false;
3963
+ try {
3964
+ const wrapperIface = new Interface([
3965
+ "function baseToken() view returns (address)",
3966
+ "function dao() view returns (address)"
3967
+ ]);
3968
+ const [rawBase, rawDao] = await Promise.all([
3969
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("baseToken", []) }),
3970
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("dao", []) })
3971
+ ]);
3972
+ if (rawBase && rawBase !== "0x" && rawDao && rawDao !== "0x") {
3973
+ const [decodedBase] = AbiCoder.defaultAbiCoder().decode(["address"], rawBase);
3974
+ const [decodedDao] = AbiCoder.defaultAbiCoder().decode(["address"], rawDao);
3975
+ const baseNorm = getAddress(decodedBase);
3976
+ const daoNorm = getAddress(decodedDao);
3977
+ if (!subdao || daoNorm === getAddress(subdao)) {
3978
+ baseToken = baseNorm;
3979
+ isWrapper = true;
3980
+ }
3981
+ }
3982
+ } catch (_) {
3983
+ }
3984
+ return { votingToken: votingTokenNorm, baseToken, isWrapper };
3985
+ }
3986
+ async function describeVotesToken({ provider, subdao, governor }) {
3987
+ const { votingToken, baseToken, isWrapper } = await resolveVotesTokenChain({ provider, subdao, governor });
3988
+ let multiplierNFT = null;
3989
+ let basis = null;
3990
+ if (isWrapper) {
3991
+ try {
3992
+ const wrapper = new Contract(votingToken, ABI.MultipliedVotes, provider);
3993
+ multiplierNFT = await wrapper.multiplierNFT().catch(() => null);
3994
+ basis = await wrapper.BASIS().catch(() => null);
3995
+ } catch (_) {
3996
+ }
3997
+ }
3998
+ const votingNorm = getAddress(votingToken);
3999
+ const baseNorm = getAddress(baseToken);
4000
+ const multiplierNorm = multiplierNFT && /^0x[0-9a-fA-F]{40}$/.test(String(multiplierNFT)) ? getAddress(multiplierNFT) : null;
4001
+ const basisBig = basis != null ? BigInt(String(basis)) : null;
4002
+ let description;
4003
+ if (!isWrapper) {
4004
+ description = `Voting token = ERC20Votes at ${votingNorm}`;
4005
+ } else {
4006
+ const basisStr = basisBig != null ? basisBig.toString() : "10000";
4007
+ description = `Voting token = MultipliedVotes(base=${baseNorm}, multiplierNFT=${multiplierNorm || "unknown"}, BASIS=${basisStr})`;
4008
+ if (subdao) {
4009
+ description += ` for DAO ${getAddress(subdao)}`;
4010
+ }
4011
+ }
4012
+ return {
4013
+ votingToken: votingNorm,
4014
+ baseToken: baseNorm,
4015
+ isWrapper,
4016
+ multiplierNFT: multiplierNorm,
4017
+ basis: basisBig,
4018
+ description
4019
+ };
4020
+ }
4021
+ async function getVotingStatus({ provider, subdao, governor, account }) {
4022
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
4023
+ if (!governor && !subdao) throw new SageSDKError(CODES.INVALID_ARGS, "governor or subdao required");
4024
+ if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
4025
+ const acct = getAddress(account);
4026
+ let govAddr = null;
4027
+ let subdaoAddr = null;
4028
+ if (governor) {
4029
+ govAddr = normaliseGovernor(governor);
4030
+ }
4031
+ if (subdao) {
4032
+ subdaoAddr = getAddress(subdao);
4033
+ if (!govAddr) {
4034
+ try {
4035
+ const sub = new Contract(subdaoAddr, ["function governor() view returns (address)"], provider);
4036
+ govAddr = getAddress(await sub.governor());
4037
+ } catch (_) {
4038
+ }
4039
+ }
4040
+ }
4041
+ if (!govAddr) throw new SageSDKError(CODES.INVALID_ARGS, "could not resolve governor address");
4042
+ let threshold = null;
4043
+ try {
4044
+ const g = new Contract(govAddr, ABI.Governor, provider);
4045
+ const t = await g.proposalThreshold();
4046
+ threshold = BigInt(t.toString());
4047
+ } catch (_) {
4048
+ }
4049
+ const desc = await describeVotesToken({ provider, subdao: subdaoAddr || void 0, governor: govAddr });
4050
+ let stakeToken = null;
4051
+ if (subdaoAddr) {
4052
+ try {
4053
+ const sub = new Contract(subdaoAddr, ["function stakeToken() view returns (address)"], provider);
4054
+ const st = await sub.stakeToken();
4055
+ if (st && /^0x[0-9a-fA-F]{40}$/.test(String(st))) {
4056
+ stakeToken = getAddress(st);
4057
+ }
4058
+ } catch (_) {
4059
+ }
4060
+ }
4061
+ const VotesABI = [
4062
+ "function getVotes(address) view returns (uint256)",
4063
+ "function delegates(address) view returns (address)",
4064
+ "function balanceOf(address) view returns (uint256)"
4065
+ ];
4066
+ let votingPower = null;
4067
+ let delegate = null;
4068
+ let tokenBalance = null;
4069
+ try {
4070
+ const votingC = new Contract(desc.votingToken, VotesABI, provider);
4071
+ const vp = await votingC.getVotes(acct).catch(() => null);
4072
+ if (vp != null) votingPower = BigInt(vp.toString());
4073
+ const del = await votingC.delegates(acct).catch(() => null);
4074
+ if (del && /^0x[0-9a-fA-F]{40}$/.test(String(del))) delegate = getAddress(del);
4075
+ const bal = await votingC.balanceOf(acct).catch(() => null);
4076
+ if (bal != null) tokenBalance = BigInt(bal.toString());
4077
+ } catch (_) {
4078
+ }
4079
+ const canPropose = threshold != null && votingPower != null ? votingPower >= threshold : null;
4080
+ let stakeTokenVotes = null;
4081
+ let stakeTokenDelegate = null;
4082
+ let stakeTokenBalance = null;
4083
+ const tokenMismatch = !!stakeToken && stakeToken.toLowerCase() !== desc.votingToken.toLowerCase();
4084
+ if (stakeToken && tokenMismatch) {
4085
+ try {
4086
+ const stakeC = new Contract(stakeToken, VotesABI, provider);
4087
+ const sv = await stakeC.getVotes(acct).catch(() => null);
4088
+ if (sv != null) stakeTokenVotes = BigInt(sv.toString());
4089
+ const sd = await stakeC.delegates(acct).catch(() => null);
4090
+ if (sd && /^0x[0-9a-fA-F]{40}$/.test(String(sd))) {
4091
+ stakeTokenDelegate = getAddress(sd);
4092
+ }
4093
+ const sb = await stakeC.balanceOf(acct).catch(() => null);
4094
+ if (sb != null) stakeTokenBalance = BigInt(sb.toString());
4095
+ } catch (_) {
4096
+ }
4097
+ }
4098
+ return {
4099
+ subdao: subdaoAddr,
4100
+ governor: govAddr,
4101
+ stakeToken,
4102
+ votingToken: desc.votingToken,
4103
+ baseToken: desc.baseToken,
4104
+ isWrapper: desc.isWrapper,
4105
+ multiplierNFT: desc.multiplierNFT,
4106
+ basis: desc.basis,
4107
+ threshold,
4108
+ votingPower,
4109
+ tokenBalance,
4110
+ delegate,
4111
+ canPropose,
4112
+ tokenMismatch,
4113
+ stakeTokenVotes,
4114
+ stakeTokenDelegate,
4115
+ stakeTokenBalance,
4116
+ description: desc.description
4117
+ };
4118
+ }
3132
4119
  module2.exports = {
3133
4120
  getGovernorInfo,
3134
4121
  getProposal,
@@ -3160,52 +4147,28 @@ var require_governance = __commonJS({
3160
4147
  * - SubDAO.stakeToken() (when subdao provided)
3161
4148
  */
3162
4149
  resolveVotesToken: async function resolveVotesToken({ provider, subdao, governor }) {
3163
- if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3164
- if (!subdao && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3165
- if (governor) {
3166
- const govAddr = normaliseGovernor(governor);
3167
- try {
3168
- const iTok = new Interface(["function token() view returns (address)"]);
3169
- const data = iTok.encodeFunctionData("token", []);
3170
- const ret = await provider.call({ to: govAddr, data });
3171
- if (ret && ret !== "0x") {
3172
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3173
- return getAddress(addr);
3174
- }
3175
- } catch (_) {
3176
- }
3177
- try {
3178
- const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3179
- const d2 = iGov.encodeFunctionData("sxxxToken", []);
3180
- const r2 = await provider.call({ to: govAddr, data: d2 });
3181
- if (r2 && r2 !== "0x") {
3182
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3183
- return getAddress(addr);
3184
- }
3185
- } catch (_) {
3186
- }
3187
- }
3188
- if (subdao) {
3189
- try {
3190
- const subAddr = getAddress(subdao);
3191
- const iSub = new Interface(["function stakeToken() view returns (address)"]);
3192
- const d3 = iSub.encodeFunctionData("stakeToken", []);
3193
- const r3 = await provider.call({ to: subAddr, data: d3 });
3194
- if (r3 && r3 !== "0x") {
3195
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3196
- return getAddress(addr);
3197
- }
3198
- } catch (_) {
3199
- }
3200
- }
3201
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
4150
+ const { votingToken } = await resolveVotesTokenChain({ provider, subdao, governor });
4151
+ return votingToken;
3202
4152
  },
4153
+ /**
4154
+ * Resolve the IVotes token chain used for voting (wrapper + base token).
4155
+ * See resolveVotesTokenChain() for details.
4156
+ */
4157
+ resolveVotesTokenChain,
4158
+ /**
4159
+ * Human-friendly description of the voting token wiring for a Governor/SubDAO.
4160
+ */
4161
+ describeVotesToken,
4162
+ /**
4163
+ * Get voting status for an account relative to a Governor/SubDAO.
4164
+ */
4165
+ getVotingStatus,
3203
4166
  /** Build a delegate(self) tx using the preferred votes token resolution path. */
3204
4167
  buildDelegateSelfPreferred: async function buildDelegateSelfPreferred({ provider, subdao, governor, account }) {
3205
4168
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3206
4169
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3207
- const token = await this.resolveVotesToken({ provider, subdao, governor });
3208
- return buildDelegateTx({ token, delegatee: account });
4170
+ const { baseToken } = await resolveVotesTokenChain({ provider, subdao, governor });
4171
+ return buildDelegateTx({ token: baseToken, delegatee: account });
3209
4172
  },
3210
4173
  /**
3211
4174
  * Send a delegate(self) and verify votes at latest-1.
@@ -3214,15 +4177,15 @@ var require_governance = __commonJS({
3214
4177
  delegateSelfAndVerify: async function delegateSelfAndVerify({ provider, subdao, governor, account, signer = null, minVotes = null }) {
3215
4178
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3216
4179
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3217
- const token = await this.resolveVotesToken({ provider, subdao, governor });
3218
- const payload = buildDelegateTx({ token, delegatee: account });
4180
+ const { votingToken, baseToken } = await resolveVotesTokenChain({ provider, subdao, governor });
4181
+ const payload = buildDelegateTx({ token: baseToken, delegatee: account });
3219
4182
  let txHash = null;
3220
4183
  if (signer && typeof signer.sendTransaction === "function") {
3221
4184
  const tx = await signer.sendTransaction({ to: payload.to, data: payload.data, value: payload.value });
3222
4185
  txHash = tx?.hash || null;
3223
4186
  if (tx?.wait) await tx.wait();
3224
4187
  }
3225
- const votes = await getVotesLatestMinusOne({ provider, token, account });
4188
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account });
3226
4189
  const ok = minVotes != null ? votes >= BigInt(minVotes) : votes > 0n;
3227
4190
  return { txHash, ok, votes, payload };
3228
4191
  },
@@ -3276,8 +4239,8 @@ var require_governance = __commonJS({
3276
4239
  }
3277
4240
  let votesOk = null;
3278
4241
  try {
3279
- const token = sxxx || await this.resolveVotesToken({ provider, governor });
3280
- const votes = await getVotesLatestMinusOne({ provider, token, account: user });
4242
+ const { votingToken } = await resolveVotesTokenChain({ provider, governor });
4243
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account: user });
3281
4244
  const th = threshold != null ? BigInt(threshold) : 0n;
3282
4245
  votesOk = votes >= th;
3283
4246
  } catch (_) {
@@ -3294,7 +4257,7 @@ var require_governance = __commonJS({
3294
4257
  },
3295
4258
  /**
3296
4259
  * Compose propose readiness with optional execution readiness checks.
3297
- * execution?: { provider, registry, timelock, subdao, libraryId, manifestCID, promptCount }
4260
+ * execution?: { provider, registry, timelock, subdao, manifestCID, version }
3298
4261
  */
3299
4262
  readinessToPropose: async function readinessToPropose({ provider, governor, proposer, execution = null }) {
3300
4263
  const gates = await this.ensureProposeGates({ provider, governor, proposer });
@@ -3303,12 +4266,11 @@ var require_governance = __commonJS({
3303
4266
  if (execution && execution.registry && execution.timelock && execution.subdao) {
3304
4267
  try {
3305
4268
  const library = require_library();
3306
- const { to, data } = library.buildUpdateLibraryForSubDAOTx({
4269
+ const { to, data } = library.buildUpdateLibraryTx({
3307
4270
  registry: execution.registry,
3308
4271
  subdao: execution.subdao,
3309
4272
  manifestCID: execution.manifestCID || "",
3310
- promptCount: execution.promptCount || 0,
3311
- libraryId: execution.libraryId || "main"
4273
+ version: execution.version || "1.0.0"
3312
4274
  });
3313
4275
  const sim = await library.simulateAsTimelock({ provider, registry: execution.registry, to, data, timelock: execution.timelock });
3314
4276
  executionReady = !!sim.ok;
@@ -3842,13 +4804,13 @@ var require_openzeppelin = __commonJS({
3842
4804
  return null;
3843
4805
  }
3844
4806
  }
3845
- async function getProposals({ provider, governor, fromBlock = 0, toBlock = "latest", pageSize = 5e3, abiResolver = null, selectorResolver = null, chainId = null }) {
4807
+ async function getProposals({ provider, governor, fromBlock, toBlock = "latest", pageSize = 5e3, abiResolver = null, selectorResolver = null, chainId = null }) {
3846
4808
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3847
4809
  const addr = normaliseGovernor(governor);
3848
4810
  const iface = new Interface([Events.ProposalCreated]);
3849
4811
  const topic = iface.getEvent("ProposalCreated").topicHash;
3850
4812
  const latest = toBlock === "latest" ? await provider.getBlockNumber() : Number(toBlock);
3851
- const start = Number(fromBlock);
4813
+ const start = fromBlock !== void 0 ? Number(fromBlock) : Math.max(0, latest - 5e4);
3852
4814
  const end = latest;
3853
4815
  const items = [];
3854
4816
  const resolvedChainId = await resolveChainId(provider, chainId);
@@ -3877,7 +4839,7 @@ var require_openzeppelin = __commonJS({
3877
4839
  }
3878
4840
  return { items, nextCursor: null };
3879
4841
  }
3880
- async function getTimelineOnchain({ provider, governor, id: id2, fromBlock = 0, toBlock = "latest" }) {
4842
+ async function getTimelineOnchain({ provider, governor, id: id2, fromBlock, toBlock = "latest" }) {
3881
4843
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3882
4844
  const addr = normaliseGovernor(governor);
3883
4845
  const pid = typeof id2 === "bigint" ? id2 : String(id2).startsWith("0x") ? BigInt(id2) : BigInt(String(id2));
@@ -3888,7 +4850,8 @@ var require_openzeppelin = __commonJS({
3888
4850
  iface.getEvent("ProposalCanceled").topicHash
3889
4851
  ];
3890
4852
  const latest = toBlock === "latest" ? await provider.getBlockNumber() : Number(toBlock);
3891
- const logs = await provider.getLogs({ address: addr, fromBlock: Number(fromBlock), toBlock: latest, topics: [topics] });
4853
+ const start = fromBlock !== void 0 ? Number(fromBlock) : Math.max(0, latest - 5e4);
4854
+ const logs = await provider.getLogs({ address: addr, fromBlock: start, toBlock: latest, topics: [topics] });
3892
4855
  const out = [];
3893
4856
  for (const log of logs) {
3894
4857
  try {
@@ -4165,6 +5128,7 @@ var require_operations = __commonJS({
4165
5128
  cache = null,
4166
5129
  fromBlock = 0,
4167
5130
  helperAddress = null,
5131
+ subgraphUrl = null,
4168
5132
  hints = {},
4169
5133
  chunkSizeBlocks = 1e4,
4170
5134
  lookBackBlocks = 2e3,
@@ -4178,6 +5142,27 @@ var require_operations = __commonJS({
4178
5142
  const cached = await cacheAdapter.load(govAddr, id2);
4179
5143
  if (cached) return cached;
4180
5144
  }
5145
+ if (subgraphUrl) {
5146
+ try {
5147
+ const subgraph = require_subgraph2();
5148
+ const sgProposal = await subgraph.getProposalById({ url: subgraphUrl, id: String(id2), governor: govAddr });
5149
+ if (sgProposal && sgProposal.targets && sgProposal.targets.length > 0) {
5150
+ const tuple2 = {
5151
+ id: id2,
5152
+ governor: govAddr,
5153
+ targets: sgProposal.targets,
5154
+ values: sgProposal.values || [],
5155
+ calldatas: sgProposal.calldatas || [],
5156
+ description: sgProposal.description || "",
5157
+ descriptionHash: sgProposal.description ? keccak256(toUtf8Bytes(sgProposal.description)) : null,
5158
+ createdBlock: sgProposal.createdAt || null
5159
+ };
5160
+ if (cacheAdapter) await cacheAdapter.save(govAddr, id2, tuple2);
5161
+ return tuple2;
5162
+ }
5163
+ } catch (_) {
5164
+ }
5165
+ }
4181
5166
  if (helperAddress) {
4182
5167
  try {
4183
5168
  const helperAbi = [
@@ -4391,8 +5376,14 @@ var require_operations = __commonJS({
4391
5376
  ]);
4392
5377
  let resolvedSubDAO = subdao;
4393
5378
  if (!resolvedSubDAO) {
4394
- resolvedSubDAO = await governorContract.subDAO().catch(() => null);
4395
- if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5379
+ try {
5380
+ const subDAOInterface = new Interface(["function subDAO() view returns (address)"]);
5381
+ const subdaoContract = new Contract(govAddr, subDAOInterface, provider);
5382
+ resolvedSubDAO = await subdaoContract.subDAO().catch(() => null);
5383
+ if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5384
+ } catch {
5385
+ resolvedSubDAO = null;
5386
+ }
4396
5387
  }
4397
5388
  let mode = null;
4398
5389
  let eligible = null;
@@ -4467,10 +5458,11 @@ var require_operations = __commonJS({
4467
5458
  refresh = false,
4468
5459
  cache = null,
4469
5460
  includeTimeline = false,
4470
- helperAddress = null
5461
+ helperAddress = null,
5462
+ subgraphUrl = null
4471
5463
  }) {
4472
5464
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
4473
- const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress });
5465
+ const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress, subgraphUrl });
4474
5466
  let proposal = null;
4475
5467
  try {
4476
5468
  proposal = await governance.getProposal({ provider, governor: tuple.governor, id: tuple.id });
@@ -4808,8 +5800,6 @@ var require_factory = __commonJS({
4808
5800
  stableCreationFee,
4809
5801
  feeReceiver,
4810
5802
  allowStableFee,
4811
- stablePromptForkFee,
4812
- allowStablePromptForkFee,
4813
5803
  stableForkFee,
4814
5804
  allowStableForkFee,
4815
5805
  timelockMinDelay,
@@ -4833,8 +5823,6 @@ var require_factory = __commonJS({
4833
5823
  }
4834
5824
  })(),
4835
5825
  contract.allowStableFee().catch(() => null),
4836
- contract.stablePromptForkFee().catch(() => null),
4837
- contract.allowStablePromptForkFee().catch(() => null),
4838
5826
  contract.stableForkFee().catch(() => null),
4839
5827
  contract.allowStableForkFee().catch(() => null),
4840
5828
  contract.timelockMinDelay().catch(() => null),
@@ -4850,8 +5838,6 @@ var require_factory = __commonJS({
4850
5838
  stableCreationFee,
4851
5839
  feeReceiver: feeReceiver && feeReceiver !== "0x0000000000000000000000000000000000000000" ? getAddress(feeReceiver) : null,
4852
5840
  allowStableFee,
4853
- stablePromptForkFee,
4854
- allowStablePromptForkFee,
4855
5841
  stableForkFee,
4856
5842
  allowStableForkFee,
4857
5843
  timelockMinDelay,
@@ -5165,20 +6151,127 @@ var require_factory = __commonJS({
5165
6151
  }
5166
6152
  }
5167
6153
  module2.exports = {
5168
- getFactoryConfig,
5169
- getFactoryStats,
5170
- listSubDAOs,
5171
- listSubDAOsIndexed,
5172
- getSubDAORegistry,
5173
- listTemplates,
5174
- getTemplateDetails,
5175
- buildCreateSubDAOTx,
5176
- buildCreateSubDAOWithStableTx,
5177
- buildCreateSubDAOWithParamsTx,
5178
- buildCreateOperatorSubDAOWithStableTx,
5179
- buildCreateOperatorSubDAOWithStableAdvancedTx,
5180
- buildCreateForkedSubDAOTx,
5181
- buildCreateForkedSubDAOWithStableTx
6154
+ getFactoryConfig,
6155
+ getFactoryStats,
6156
+ listSubDAOs,
6157
+ listSubDAOsIndexed,
6158
+ getSubDAORegistry,
6159
+ listTemplates,
6160
+ getTemplateDetails,
6161
+ buildCreateSubDAOTx,
6162
+ buildCreateSubDAOWithStableTx,
6163
+ buildCreateSubDAOWithParamsTx,
6164
+ buildCreateOperatorSubDAOWithStableTx,
6165
+ buildCreateOperatorSubDAOWithStableAdvancedTx,
6166
+ buildCreateForkedSubDAOTx,
6167
+ buildCreateForkedSubDAOWithStableTx
6168
+ };
6169
+ }
6170
+ });
6171
+
6172
+ // src/lineage/index.js
6173
+ var require_lineage = __commonJS({
6174
+ "src/lineage/index.js"(exports2, module2) {
6175
+ var { Contract, getAddress } = __require("ethers");
6176
+ var { SageSDKError, CODES } = require_errors();
6177
+ var LINEAGE_ABI = [
6178
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
6179
+ "function getLibraryForkFee(address) view returns (uint256)"
6180
+ ];
6181
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
6182
+ function normalise(address, label) {
6183
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
6184
+ try {
6185
+ return getAddress(address);
6186
+ } catch (err) {
6187
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
6188
+ }
6189
+ }
6190
+ async function getParentLibrary({ provider, registry, subdao }) {
6191
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6192
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6193
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6194
+ try {
6195
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6196
+ const info = await contract.libraryByDAO(normalise(subdao, "subdao"));
6197
+ const parent = info.forkedFromDAO;
6198
+ if (!parent || parent === ZERO_ADDRESS) {
6199
+ return null;
6200
+ }
6201
+ return getAddress(parent).toLowerCase();
6202
+ } catch (err) {
6203
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch parent library", { cause: err });
6204
+ }
6205
+ }
6206
+ async function getLineageChain({ provider, registry, subdao }) {
6207
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6208
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6209
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6210
+ try {
6211
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6212
+ const chain = [];
6213
+ let current = normalise(subdao, "subdao");
6214
+ const MAX_DEPTH = 100;
6215
+ let iterations = 0;
6216
+ while (current && iterations < MAX_DEPTH) {
6217
+ chain.unshift(getAddress(current).toLowerCase());
6218
+ const info = await contract.libraryByDAO(current);
6219
+ const parent = info.forkedFromDAO;
6220
+ if (!parent || parent === ZERO_ADDRESS) {
6221
+ break;
6222
+ }
6223
+ current = parent;
6224
+ iterations++;
6225
+ }
6226
+ return {
6227
+ chain,
6228
+ depth: chain.length - 1,
6229
+ root: chain[0]
6230
+ };
6231
+ } catch (err) {
6232
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch lineage chain", { cause: err });
6233
+ }
6234
+ }
6235
+ async function isFork({ provider, registry, subdao }) {
6236
+ const parent = await getParentLibrary({ provider, registry, subdao });
6237
+ return parent !== null;
6238
+ }
6239
+ async function getLibraryForkFee({ provider, registry, subdao }) {
6240
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6241
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6242
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6243
+ try {
6244
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6245
+ const fee = await contract.getLibraryForkFee(normalise(subdao, "subdao"));
6246
+ return BigInt(fee.toString());
6247
+ } catch (err) {
6248
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library fork fee", { cause: err });
6249
+ }
6250
+ }
6251
+ async function getLibraryInfo({ provider, registry, subdao }) {
6252
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6253
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6254
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6255
+ try {
6256
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6257
+ const info = await contract.libraryByDAO(normalise(subdao, "subdao"));
6258
+ const parent = info.forkedFromDAO;
6259
+ return {
6260
+ parentDAO: !parent || parent === ZERO_ADDRESS ? null : getAddress(parent).toLowerCase(),
6261
+ forkFee: BigInt(info.sxxxForkFee.toString()),
6262
+ manifestCID: info.manifestCID,
6263
+ version: info.version
6264
+ };
6265
+ } catch (err) {
6266
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library info", { cause: err });
6267
+ }
6268
+ }
6269
+ module2.exports = {
6270
+ getParentLibrary,
6271
+ getLineageChain,
6272
+ isFork,
6273
+ getLibraryForkFee,
6274
+ getLibraryInfo
5182
6275
  };
5183
6276
  }
5184
6277
  });
@@ -5855,7 +6948,6 @@ var require_ipns = __commonJS({
5855
6948
  headers["X-Wallet-Address"] = auth.address;
5856
6949
  headers["X-Wallet-Signature"] = auth.signature;
5857
6950
  headers["X-Wallet-Nonce"] = auth.nonce;
5858
- headers["X-Wallet-Message"] = auth.message;
5859
6951
  }
5860
6952
  return { headers, auth };
5861
6953
  }
@@ -5877,8 +6969,7 @@ var require_ipns = __commonJS({
5877
6969
  ...extraHeaders,
5878
6970
  "X-Wallet-Address": auth.address,
5879
6971
  "X-Wallet-Signature": auth.signature,
5880
- "X-Wallet-Nonce": auth.nonce,
5881
- "X-Wallet-Message": auth.message
6972
+ "X-Wallet-Nonce": auth.nonce
5882
6973
  };
5883
6974
  return { headers, auth };
5884
6975
  }
@@ -6515,8 +7606,34 @@ var require_time = __commonJS({
6515
7606
  var require_treasury = __commonJS({
6516
7607
  "src/treasury/index.js"(exports2, module2) {
6517
7608
  var { Contract, Interface, getAddress } = __require("ethers");
6518
- var ABI = require_abi();
6519
7609
  var { SageSDKError, CODES } = require_errors();
7610
+ var SAGE_TREASURY_ABI = [
7611
+ // Aggregated views
7612
+ "function totalReserves() view returns (uint256)",
7613
+ "function totalPOL() view returns (uint256)",
7614
+ "function totalDebt() view returns (uint256)",
7615
+ // Canonical liquidity config
7616
+ "function canonicalPool() view returns (address)",
7617
+ "function routerOrVault() view returns (address)",
7618
+ // Withdrawal rate limits
7619
+ "function maxWithdrawalRate() view returns (uint256)",
7620
+ "function emergencyWithdrawalLimit() view returns (uint256)",
7621
+ // Reserve tokens
7622
+ "function getReserveTokens() view returns (address[])",
7623
+ "function getReserve(address token) view returns (tuple(uint256 amount, uint256 value, bool isLP, bool isActive))",
7624
+ // Withdrawal queue
7625
+ "function nextWithdrawalId() view returns (uint256)",
7626
+ "function pendingWithdrawals(uint256 id) view returns (tuple(bool exists, address token, address recipient, uint256 amount, uint256 value, address requester, uint256 balanceBefore, uint256 recipientBalanceBefore, uint256 depositSnapshot, bool isLP, bool isEmergency))",
7627
+ "function withdraw(address token, uint256 amount, address recipient)",
7628
+ "function confirmWithdrawal(uint256 id)",
7629
+ "function cancelWithdrawal(uint256 id)",
7630
+ // Manual price overrides
7631
+ "function manualPrices(address token) view returns (tuple(uint256 price, uint256 expiresAt, bool active))",
7632
+ "function setPriceOverride(address token, uint256 price, uint256 ttlSeconds)",
7633
+ "function clearPriceOverride(address token)",
7634
+ // Events
7635
+ "event WithdrawalScheduled(uint256 indexed id, address indexed token, address indexed recipient, uint256 amount)"
7636
+ ];
6520
7637
  var LiquidityEvents = new Interface([
6521
7638
  "event CanonicalLiquidityUpdated(address indexed pool, address indexed routerOrVault)",
6522
7639
  "event LiquidityAddPlanned(address indexed subdao, address indexed pool, address sxxxToken, address stableToken, uint256 sxxxAmount, uint256 stableAmount, address lpRecipient)",
@@ -6561,7 +7678,7 @@ var require_treasury = __commonJS({
6561
7678
  async function getTreasuryInfo({ provider, treasury }) {
6562
7679
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6563
7680
  const addr = normalise(treasury, "treasury");
6564
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7681
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6565
7682
  const [totalReserves, totalPOL, totalDebt, canonicalPool, routerOrVault, maxWithdrawalRate, emergencyWithdrawalLimit] = await Promise.all([
6566
7683
  contract.totalReserves().catch(() => 0n),
6567
7684
  contract.totalPOL().catch(() => 0n),
@@ -6585,7 +7702,7 @@ var require_treasury = __commonJS({
6585
7702
  async function getPendingWithdrawals({ provider, treasury, ids, limit = 50 }) {
6586
7703
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6587
7704
  const addr = normalise(treasury, "treasury");
6588
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7705
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6589
7706
  let idList = ids;
6590
7707
  if (!Array.isArray(idList)) {
6591
7708
  const nextId = await contract.nextWithdrawalId().catch(() => 0n);
@@ -6617,14 +7734,14 @@ var require_treasury = __commonJS({
6617
7734
  async function getReserveTokens({ provider, treasury }) {
6618
7735
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6619
7736
  const addr = normalise(treasury, "treasury");
6620
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7737
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6621
7738
  const tokens = await contract.getReserveTokens().catch(() => []);
6622
7739
  return tokens.map((token) => getAddress(token));
6623
7740
  }
6624
7741
  async function getReserves({ provider, treasury, tokens, fetchMetadata = true }) {
6625
7742
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6626
7743
  const addr = normalise(treasury, "treasury");
6627
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7744
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6628
7745
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token) => getAddress(token)) : await contract.getReserveTokens().catch(() => []);
6629
7746
  const reserves = [];
6630
7747
  for (const token of tokenList) {
@@ -6654,7 +7771,7 @@ var require_treasury = __commonJS({
6654
7771
  async function getManualPriceOverrides({ provider, treasury, tokens }) {
6655
7772
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6656
7773
  const addr = normalise(treasury, "treasury");
6657
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7774
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6658
7775
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token) => getAddress(token)) : await contract.getReserveTokens().catch(() => []);
6659
7776
  const overrides = [];
6660
7777
  for (const token of tokenList) {
@@ -6759,7 +7876,7 @@ var require_treasury = __commonJS({
6759
7876
  async function getLPContribution({ provider, treasury, subdao, token }) {
6760
7877
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6761
7878
  const addr = normalise(treasury, "treasury");
6762
- const c = new Contract(addr, ABI.SageTreasury, provider);
7879
+ const c = new Contract(addr, SAGE_TREASURY_ABI, provider);
6763
7880
  const amount = await c.lpContributions(normalise(subdao, "subdao"), normalise(token, "token")).catch(() => 0n);
6764
7881
  return amount;
6765
7882
  }
@@ -6801,7 +7918,7 @@ var require_treasury = __commonJS({
6801
7918
  function createWriteContract({ signer, treasury }) {
6802
7919
  if (!signer) throw new SageSDKError(CODES.INVALID_ARGS, "signer required");
6803
7920
  const addr = normalise(treasury, "treasury");
6804
- return new Contract(addr, ABI.SageTreasury, signer);
7921
+ return new Contract(addr, SAGE_TREASURY_ABI, signer);
6805
7922
  }
6806
7923
  async function waitForReceipt({ signer, tx, waitMs }) {
6807
7924
  const provider = signer.provider;
@@ -7097,10 +8214,787 @@ var require_bounty = __commonJS({
7097
8214
  return { governor, proposalCall };
7098
8215
  }
7099
8216
  module2.exports = {
7100
- configureWinnerMode,
7101
- fundFromTreasury,
7102
- approveWinner,
7103
- proposeApproveWinner
8217
+ configureWinnerMode,
8218
+ fundFromTreasury,
8219
+ approveWinner,
8220
+ proposeApproveWinner
8221
+ };
8222
+ }
8223
+ });
8224
+
8225
+ // src/contributions/index.js
8226
+ var require_contributions = __commonJS({
8227
+ "src/contributions/index.js"(exports2, module2) {
8228
+ var { getAddress, isAddress } = __require("ethers");
8229
+ var subgraph = require_subgraph();
8230
+ var GovernanceModel = {
8231
+ TOKEN_VOTING: "TOKEN_VOTING",
8232
+ COUNCIL: "COUNCIL",
8233
+ OPERATOR: "OPERATOR",
8234
+ DIRECT: "DIRECT"
8235
+ };
8236
+ function safeGetAddress(value) {
8237
+ try {
8238
+ return getAddress(value);
8239
+ } catch {
8240
+ return null;
8241
+ }
8242
+ }
8243
+ function mapSafe(list, mapper) {
8244
+ const out = [];
8245
+ for (const item of list || []) {
8246
+ try {
8247
+ const v = mapper(item);
8248
+ if (v != null) out.push(v);
8249
+ } catch {
8250
+ }
8251
+ }
8252
+ return out;
8253
+ }
8254
+ function detectGovernanceModel(subdaoInfo) {
8255
+ if (!subdaoInfo) return GovernanceModel.DIRECT;
8256
+ const playbook = subdaoInfo.playbook;
8257
+ if (playbook) {
8258
+ if (playbook === "council-closed" || playbook === "council-drafts") {
8259
+ return GovernanceModel.COUNCIL;
8260
+ }
8261
+ if (playbook === "community") {
8262
+ return GovernanceModel.TOKEN_VOTING;
8263
+ }
8264
+ }
8265
+ const governanceKind = subdaoInfo.governanceKind;
8266
+ if (governanceKind === 0) {
8267
+ return GovernanceModel.OPERATOR;
8268
+ }
8269
+ if (governanceKind === 1) {
8270
+ const proposalAccess = subdaoInfo.proposalAccess;
8271
+ if (proposalAccess === 0) {
8272
+ return GovernanceModel.COUNCIL;
8273
+ }
8274
+ return GovernanceModel.TOKEN_VOTING;
8275
+ }
8276
+ return GovernanceModel.TOKEN_VOTING;
8277
+ }
8278
+ async function listContributions({
8279
+ url,
8280
+ subdao,
8281
+ promptKey,
8282
+ contributor,
8283
+ fromBounty,
8284
+ first = 50,
8285
+ skip = 0,
8286
+ orderBy = "updatedAt",
8287
+ orderDirection = "desc"
8288
+ }) {
8289
+ if (!url) throw new Error("subgraph url required");
8290
+ const filters = [];
8291
+ if (subdao) {
8292
+ const addr = safeGetAddress(subdao);
8293
+ if (!addr) throw new Error("invalid subdao address");
8294
+ filters.push(`dao: "${addr.toLowerCase()}"`);
8295
+ }
8296
+ if (promptKey) {
8297
+ filters.push(`promptKey: "${String(promptKey)}"`);
8298
+ }
8299
+ if (contributor) {
8300
+ const addr = safeGetAddress(contributor);
8301
+ if (!addr) throw new Error("invalid contributor address");
8302
+ filters.push(`contributor: "${addr.toLowerCase()}"`);
8303
+ }
8304
+ if (fromBounty !== void 0) {
8305
+ filters.push(`fromBounty: ${Boolean(fromBounty)}`);
8306
+ }
8307
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
8308
+ const safeOrderBy = ["updatedAt", "createdAt"].includes(orderBy) ? orderBy : "updatedAt";
8309
+ const safeOrderDirection = orderDirection === "asc" ? "asc" : "desc";
8310
+ const doc = `
8311
+ query($first: Int!, $skip: Int!) {
8312
+ promptContributions(
8313
+ ${where}
8314
+ first: $first
8315
+ skip: $skip
8316
+ orderBy: ${safeOrderBy}
8317
+ orderDirection: ${safeOrderDirection}
8318
+ ) {
8319
+ id
8320
+ dao
8321
+ promptKey
8322
+ contributor
8323
+ cid
8324
+ proposalId
8325
+ forVotes
8326
+ againstVotes
8327
+ abstainVotes
8328
+ uniqueVoters
8329
+ quorum
8330
+ fromBounty
8331
+ bountyId
8332
+ badgeId
8333
+ badgeEvidenceURI
8334
+ createdAt
8335
+ updatedAt
8336
+ transactionHash
8337
+ }
8338
+ }
8339
+ `;
8340
+ const data = await subgraph.query(url, doc, {
8341
+ first: Math.min(Math.max(1, Number(first || 50)), 100),
8342
+ skip: Number(skip || 0)
8343
+ });
8344
+ return mapSafe(data?.promptContributions, mapContribution);
8345
+ }
8346
+ async function getByPrompt({ url, subdao, promptKey }) {
8347
+ if (!url) throw new Error("subgraph url required");
8348
+ if (!subdao) throw new Error("subdao required");
8349
+ if (!promptKey) throw new Error("promptKey required");
8350
+ const contributions = await listContributions({
8351
+ url,
8352
+ subdao,
8353
+ promptKey,
8354
+ first: 100
8355
+ });
8356
+ const aggregates = computeAggregates(contributions);
8357
+ return { contributions, aggregates };
8358
+ }
8359
+ async function getById({ url, id: id2 }) {
8360
+ if (!url) throw new Error("subgraph url required");
8361
+ if (!id2) throw new Error("id required");
8362
+ const doc = `
8363
+ query($id: ID!) {
8364
+ promptContribution(id: $id) {
8365
+ id
8366
+ dao
8367
+ promptKey
8368
+ contributor
8369
+ cid
8370
+ proposalId
8371
+ forVotes
8372
+ againstVotes
8373
+ abstainVotes
8374
+ uniqueVoters
8375
+ quorum
8376
+ fromBounty
8377
+ bountyId
8378
+ badgeId
8379
+ badgeEvidenceURI
8380
+ createdAt
8381
+ updatedAt
8382
+ transactionHash
8383
+ }
8384
+ }
8385
+ `;
8386
+ const data = await subgraph.query(url, doc, { id: String(id2) });
8387
+ const row = data?.promptContribution;
8388
+ if (!row) return null;
8389
+ return mapContribution(row);
8390
+ }
8391
+ function mapContribution(row) {
8392
+ const dao = safeGetAddress(row.dao);
8393
+ const contributor = safeGetAddress(row.contributor);
8394
+ if (!dao) return null;
8395
+ let governanceModel = GovernanceModel.DIRECT;
8396
+ if (row.proposalId != null) {
8397
+ governanceModel = GovernanceModel.TOKEN_VOTING;
8398
+ } else if (row.fromBounty) {
8399
+ governanceModel = GovernanceModel.DIRECT;
8400
+ }
8401
+ return {
8402
+ id: String(row.id),
8403
+ dao,
8404
+ daoName: null,
8405
+ // Enriched separately if needed
8406
+ promptKey: String(row.promptKey),
8407
+ contributor: contributor || "0x0000000000000000000000000000000000000000",
8408
+ cid: String(row.cid),
8409
+ timestamp: Number(row.updatedAt || 0),
8410
+ createdAt: Number(row.createdAt || 0),
8411
+ updatedAt: Number(row.updatedAt || 0),
8412
+ transactionHash: row.transactionHash || null,
8413
+ // Governance context
8414
+ governanceModel,
8415
+ proposalId: row.proposalId != null ? BigInt(String(row.proposalId)) : null,
8416
+ forVotes: row.forVotes != null ? BigInt(String(row.forVotes)) : null,
8417
+ againstVotes: row.againstVotes != null ? BigInt(String(row.againstVotes)) : null,
8418
+ abstainVotes: row.abstainVotes != null ? BigInt(String(row.abstainVotes)) : null,
8419
+ uniqueVoters: row.uniqueVoters != null ? Number(row.uniqueVoters) : null,
8420
+ quorum: row.quorum != null ? BigInt(String(row.quorum)) : null,
8421
+ // Bounty context
8422
+ fromBounty: Boolean(row.fromBounty),
8423
+ bountyId: row.bountyId != null ? BigInt(String(row.bountyId)) : null,
8424
+ // Badge context
8425
+ badgeId: row.badgeId != null ? BigInt(String(row.badgeId)) : null,
8426
+ badgeEvidenceURI: row.badgeEvidenceURI || null
8427
+ };
8428
+ }
8429
+ function computeAggregates(contributions) {
8430
+ if (!contributions || contributions.length === 0) {
8431
+ return {
8432
+ totalContributions: 0,
8433
+ uniqueContributors: 0,
8434
+ bountyOriginated: 0,
8435
+ governanceOriginated: 0,
8436
+ totalForVotes: 0n,
8437
+ totalAgainstVotes: 0n,
8438
+ averageVoterCount: 0,
8439
+ badgeCount: 0
8440
+ };
8441
+ }
8442
+ const contributorSet = /* @__PURE__ */ new Set();
8443
+ let bountyOriginated = 0;
8444
+ let governanceOriginated = 0;
8445
+ let totalForVotes = 0n;
8446
+ let totalAgainstVotes = 0n;
8447
+ let voterCountSum = 0;
8448
+ let voterCountN = 0;
8449
+ let badgeCount = 0;
8450
+ for (const c of contributions) {
8451
+ if (c.contributor) contributorSet.add(c.contributor.toLowerCase());
8452
+ if (c.fromBounty) {
8453
+ bountyOriginated++;
8454
+ } else {
8455
+ governanceOriginated++;
8456
+ }
8457
+ if (c.forVotes != null) totalForVotes += c.forVotes;
8458
+ if (c.againstVotes != null) totalAgainstVotes += c.againstVotes;
8459
+ if (c.uniqueVoters != null) {
8460
+ voterCountSum += c.uniqueVoters;
8461
+ voterCountN++;
8462
+ }
8463
+ if (c.badgeId != null) badgeCount++;
8464
+ }
8465
+ return {
8466
+ totalContributions: contributions.length,
8467
+ uniqueContributors: contributorSet.size,
8468
+ bountyOriginated,
8469
+ governanceOriginated,
8470
+ totalForVotes,
8471
+ totalAgainstVotes,
8472
+ averageVoterCount: voterCountN > 0 ? Math.round(voterCountSum / voterCountN) : 0,
8473
+ badgeCount
8474
+ };
8475
+ }
8476
+ function getGovernanceQuality(contribution, context = {}) {
8477
+ if (!contribution) {
8478
+ return {
8479
+ model: GovernanceModel.DIRECT,
8480
+ decentralization: 0,
8481
+ consensus: 0,
8482
+ raw: {}
8483
+ };
8484
+ }
8485
+ const model = contribution.governanceModel || GovernanceModel.DIRECT;
8486
+ switch (model) {
8487
+ case GovernanceModel.TOKEN_VOTING:
8488
+ return computeTokenVotingQuality(contribution, context);
8489
+ case GovernanceModel.COUNCIL:
8490
+ return computeCouncilQuality(contribution, context);
8491
+ case GovernanceModel.OPERATOR:
8492
+ return computeOperatorQuality(contribution, context);
8493
+ case GovernanceModel.DIRECT:
8494
+ default:
8495
+ return {
8496
+ model: GovernanceModel.DIRECT,
8497
+ decentralization: 0,
8498
+ consensus: 1,
8499
+ // Direct = full consensus (single decision maker)
8500
+ raw: {
8501
+ contributor: contribution.contributor
8502
+ }
8503
+ };
8504
+ }
8505
+ }
8506
+ function computeTokenVotingQuality(contribution, context) {
8507
+ const forVotes = contribution.forVotes || 0n;
8508
+ const againstVotes = contribution.againstVotes || 0n;
8509
+ const abstainVotes = contribution.abstainVotes || 0n;
8510
+ const totalVotes = forVotes + againstVotes + abstainVotes;
8511
+ const uniqueVoters = contribution.uniqueVoters || 0;
8512
+ const quorum = contribution.quorum || null;
8513
+ const totalHolders = context.totalHolders || null;
8514
+ let decentralization = 0;
8515
+ if (totalHolders && totalHolders > 0 && uniqueVoters > 0) {
8516
+ decentralization = Math.min(1, uniqueVoters / totalHolders);
8517
+ } else if (uniqueVoters > 0) {
8518
+ decentralization = Math.min(1, Math.log10(uniqueVoters + 1) / 3);
8519
+ }
8520
+ let consensus = 0;
8521
+ if (totalVotes > 0n) {
8522
+ consensus = Number(forVotes * 10000n / totalVotes) / 1e4;
8523
+ }
8524
+ let quorumMet = null;
8525
+ if (quorum != null && quorum > 0n) {
8526
+ quorumMet = totalVotes >= quorum;
8527
+ }
8528
+ return {
8529
+ model: GovernanceModel.TOKEN_VOTING,
8530
+ decentralization,
8531
+ consensus,
8532
+ raw: {
8533
+ forVotes,
8534
+ againstVotes,
8535
+ abstainVotes,
8536
+ totalVotes,
8537
+ uniqueVoters,
8538
+ quorum,
8539
+ quorumMet,
8540
+ proposalId: contribution.proposalId
8541
+ }
8542
+ };
8543
+ }
8544
+ function computeCouncilQuality(contribution, context) {
8545
+ const signerCount = contribution.signerCount || context.signerCount || 0;
8546
+ const threshold = contribution.threshold || context.threshold || 0;
8547
+ const totalCouncilMembers = context.totalCouncilMembers || threshold;
8548
+ let decentralization = 0;
8549
+ if (totalCouncilMembers > 0 && signerCount > 0) {
8550
+ decentralization = Math.min(1, signerCount / totalCouncilMembers);
8551
+ }
8552
+ let consensus = 0;
8553
+ if (threshold > 0) {
8554
+ consensus = Math.min(1, signerCount / threshold);
8555
+ }
8556
+ return {
8557
+ model: GovernanceModel.COUNCIL,
8558
+ decentralization,
8559
+ consensus,
8560
+ raw: {
8561
+ signerCount,
8562
+ threshold,
8563
+ totalCouncilMembers,
8564
+ signers: contribution.signers || []
8565
+ }
8566
+ };
8567
+ }
8568
+ function computeOperatorQuality(contribution, context) {
8569
+ return {
8570
+ model: GovernanceModel.OPERATOR,
8571
+ decentralization: 0,
8572
+ // Single operator = not decentralized
8573
+ consensus: 1,
8574
+ // Operator decision = full "consensus"
8575
+ raw: {
8576
+ operator: contribution.operator || contribution.contributor,
8577
+ operatorRole: contribution.operatorRole || context.operatorRole || null
8578
+ }
8579
+ };
8580
+ }
8581
+ function enrichWithGovernanceModel(contribution, subdaoInfo) {
8582
+ if (!contribution) return contribution;
8583
+ const model = detectGovernanceModel(subdaoInfo);
8584
+ return {
8585
+ ...contribution,
8586
+ governanceModel: model,
8587
+ daoName: subdaoInfo?.name || null
8588
+ };
8589
+ }
8590
+ async function getByContributor({ url, contributor, first = 50, skip = 0 }) {
8591
+ if (!url) throw new Error("subgraph url required");
8592
+ if (!contributor) throw new Error("contributor required");
8593
+ return listContributions({ url, contributor, first, skip });
8594
+ }
8595
+ async function getBadgesByRecipient({ url, recipient, first = 50 }) {
8596
+ if (!url) throw new Error("subgraph url required");
8597
+ if (!recipient) throw new Error("recipient required");
8598
+ const addr = safeGetAddress(recipient);
8599
+ if (!addr) throw new Error("invalid recipient address");
8600
+ const doc = `
8601
+ query($recipient: Bytes!, $first: Int!) {
8602
+ soulboundBadges(
8603
+ where: { recipient: $recipient }
8604
+ first: $first
8605
+ orderBy: blockTimestamp
8606
+ orderDirection: desc
8607
+ ) {
8608
+ id
8609
+ contract
8610
+ badgeId
8611
+ recipient
8612
+ evidenceURI
8613
+ blockNumber
8614
+ blockTimestamp
8615
+ transactionHash
8616
+ }
8617
+ }
8618
+ `;
8619
+ const data = await subgraph.query(url, doc, {
8620
+ recipient: addr.toLowerCase(),
8621
+ first: Math.min(Math.max(1, Number(first || 50)), 100)
8622
+ });
8623
+ return mapSafe(data?.soulboundBadges, (row) => {
8624
+ const contract = safeGetAddress(row.contract);
8625
+ const recipient2 = safeGetAddress(row.recipient);
8626
+ if (!contract || !recipient2) return null;
8627
+ return {
8628
+ id: String(row.id),
8629
+ contract,
8630
+ badgeId: BigInt(String(row.badgeId || "0")),
8631
+ recipient: recipient2,
8632
+ evidenceURI: row.evidenceURI || null,
8633
+ blockNumber: Number(row.blockNumber || 0),
8634
+ blockTimestamp: Number(row.blockTimestamp || 0),
8635
+ transactionHash: row.transactionHash || null
8636
+ };
8637
+ });
8638
+ }
8639
+ module2.exports = {
8640
+ // Constants
8641
+ GovernanceModel,
8642
+ // Main queries
8643
+ listContributions,
8644
+ getByPrompt,
8645
+ getById,
8646
+ getByContributor,
8647
+ getBadgesByRecipient,
8648
+ // Governance quality helpers
8649
+ getGovernanceQuality,
8650
+ enrichWithGovernanceModel,
8651
+ detectGovernanceModel,
8652
+ // Aggregation helpers
8653
+ computeAggregates
8654
+ };
8655
+ }
8656
+ });
8657
+
8658
+ // src/votingMultiplier/index.js
8659
+ var require_votingMultiplier = __commonJS({
8660
+ "src/votingMultiplier/index.js"(exports2, module2) {
8661
+ var { Contract, Interface, getAddress } = __require("ethers");
8662
+ var ABI = require_abi();
8663
+ var { SageSDKError, CODES } = require_errors();
8664
+ function normaliseAddress(address, label) {
8665
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8666
+ try {
8667
+ return getAddress(address);
8668
+ } catch (err) {
8669
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8670
+ }
8671
+ }
8672
+ function toBigInt(value, label) {
8673
+ if (value === void 0 || value === null) {
8674
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8675
+ }
8676
+ try {
8677
+ return BigInt(value.toString());
8678
+ } catch (err) {
8679
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8680
+ }
8681
+ }
8682
+ function getNftContract(provider, nft) {
8683
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8684
+ const addr = normaliseAddress(nft, "nft");
8685
+ return new Contract(addr, ABI.VotingMultiplierNFT, provider);
8686
+ }
8687
+ function getWrapperContract(provider, wrapper) {
8688
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8689
+ const addr = normaliseAddress(wrapper, "wrapper");
8690
+ return new Contract(addr, ABI.MultipliedVotes, provider);
8691
+ }
8692
+ async function getTier({ provider, nft, tierId }) {
8693
+ const c = getNftContract(provider, nft);
8694
+ const id2 = toBigInt(tierId, "tierId");
8695
+ let tier;
8696
+ if (typeof c.getTier === "function") {
8697
+ tier = await c.getTier(id2);
8698
+ } else {
8699
+ tier = await c.tiers(id2);
8700
+ }
8701
+ const name = String(tier.name ?? tier[0]);
8702
+ const multiplier = BigInt((tier.multiplier ?? tier[1]).toString());
8703
+ const maxSupply = BigInt((tier.maxSupply ?? tier[2]).toString());
8704
+ const minted = BigInt((tier.minted ?? tier[3]).toString());
8705
+ const price = BigInt((tier.price ?? tier[4]).toString());
8706
+ const dao = getAddress(tier.dao ?? tier[5]);
8707
+ return { name, multiplier, maxSupply, minted, price, dao };
8708
+ }
8709
+ async function getTierCount({ provider, nft }) {
8710
+ const c = getNftContract(provider, nft);
8711
+ const count = await c.tierCount();
8712
+ return BigInt(count.toString());
8713
+ }
8714
+ function buildCreateTierTx({ nft, dao, name, multiplier, maxSupply, price }) {
8715
+ const addr = normaliseAddress(nft, "nft");
8716
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8717
+ const data = iface.encodeFunctionData("createTier", [
8718
+ normaliseAddress(dao, "dao"),
8719
+ String(name ?? ""),
8720
+ toBigInt(multiplier, "multiplier"),
8721
+ toBigInt(maxSupply, "maxSupply"),
8722
+ toBigInt(price, "price")
8723
+ ]);
8724
+ return { to: addr, data, value: 0n };
8725
+ }
8726
+ function buildMintTx({ nft, to, tierId, uri }) {
8727
+ const addr = normaliseAddress(nft, "nft");
8728
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8729
+ const data = iface.encodeFunctionData("mint", [
8730
+ normaliseAddress(to, "to"),
8731
+ toBigInt(tierId, "tierId"),
8732
+ String(uri ?? "")
8733
+ ]);
8734
+ return { to: addr, data, value: 0n };
8735
+ }
8736
+ function buildPublicMintTx({ nft, tierId, uri, value }) {
8737
+ const addr = normaliseAddress(nft, "nft");
8738
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8739
+ const data = iface.encodeFunctionData("publicMint", [
8740
+ toBigInt(tierId, "tierId"),
8741
+ String(uri ?? "")
8742
+ ]);
8743
+ return { to: addr, data, value: toBigInt(value ?? 0n, "value") };
8744
+ }
8745
+ async function getMultiplier({ provider, nft, account, dao }) {
8746
+ const c = getNftContract(provider, nft);
8747
+ const res = await c.getMultiplier(normaliseAddress(account, "account"), normaliseAddress(dao, "dao"));
8748
+ return BigInt(res.toString());
8749
+ }
8750
+ async function getPastMultiplier({ provider, nft, account, dao, timepoint }) {
8751
+ const c = getNftContract(provider, nft);
8752
+ const res = await c.getPastMultiplier(
8753
+ normaliseAddress(account, "account"),
8754
+ normaliseAddress(dao, "dao"),
8755
+ toBigInt(timepoint, "timepoint")
8756
+ );
8757
+ return BigInt(res.toString());
8758
+ }
8759
+ async function getTokenMultiplier({ provider, nft, tokenId }) {
8760
+ const c = getNftContract(provider, nft);
8761
+ const res = await c.getTokenMultiplier(toBigInt(tokenId, "tokenId"));
8762
+ return BigInt(res.toString());
8763
+ }
8764
+ async function getTokenDAO({ provider, nft, tokenId }) {
8765
+ const c = getNftContract(provider, nft);
8766
+ const res = await c.getTokenDAO(toBigInt(tokenId, "tokenId"));
8767
+ return getAddress(res);
8768
+ }
8769
+ async function getTokenInfo({ provider, nft, tokenId }) {
8770
+ const c = getNftContract(provider, nft);
8771
+ const id2 = toBigInt(tokenId, "tokenId");
8772
+ const info = await c.getTokenInfo(id2);
8773
+ const owner = getAddress(info.owner ?? info[0]);
8774
+ const tierId = BigInt((info.tierId ?? info[1]).toString());
8775
+ const multiplier = BigInt((info.multiplier ?? info[2]).toString());
8776
+ const uri = String(info.uri ?? info[3]);
8777
+ return { owner, tierId, multiplier, uri };
8778
+ }
8779
+ async function getVotes({ provider, wrapper, account }) {
8780
+ const c = getWrapperContract(provider, wrapper);
8781
+ const res = await c.getVotes(normaliseAddress(account, "account"));
8782
+ return BigInt(res.toString());
8783
+ }
8784
+ async function getPastVotes({ provider, wrapper, account, timepoint }) {
8785
+ const c = getWrapperContract(provider, wrapper);
8786
+ const res = await c.getPastVotes(
8787
+ normaliseAddress(account, "account"),
8788
+ toBigInt(timepoint, "timepoint")
8789
+ );
8790
+ return BigInt(res.toString());
8791
+ }
8792
+ async function getVotingBreakdown({ provider, wrapper, account }) {
8793
+ const c = getWrapperContract(provider, wrapper);
8794
+ const [baseVotes, multiplier, effectiveVotes] = await c.getVotingBreakdown(normaliseAddress(account, "account"));
8795
+ return {
8796
+ baseVotes: BigInt(baseVotes.toString()),
8797
+ multiplier: BigInt(multiplier.toString()),
8798
+ effectiveVotes: BigInt(effectiveVotes.toString())
8799
+ };
8800
+ }
8801
+ async function getPastVotingBreakdown({ provider, wrapper, account, timepoint }) {
8802
+ const c = getWrapperContract(provider, wrapper);
8803
+ const [baseVotes, multiplier, effectiveVotes] = await c.getPastVotingBreakdown(
8804
+ normaliseAddress(account, "account"),
8805
+ toBigInt(timepoint, "timepoint")
8806
+ );
8807
+ return {
8808
+ baseVotes: BigInt(baseVotes.toString()),
8809
+ multiplier: BigInt(multiplier.toString()),
8810
+ effectiveVotes: BigInt(effectiveVotes.toString())
8811
+ };
8812
+ }
8813
+ async function hasMultiplierBonus({ provider, wrapper, account }) {
8814
+ const c = getWrapperContract(provider, wrapper);
8815
+ const res = await c.hasMultiplierBonus(normaliseAddress(account, "account"));
8816
+ return !!res;
8817
+ }
8818
+ module2.exports = {
8819
+ // Tier management
8820
+ getTier,
8821
+ getTierCount,
8822
+ buildCreateTierTx,
8823
+ // Minting
8824
+ buildMintTx,
8825
+ buildPublicMintTx,
8826
+ // Multiplier queries
8827
+ getMultiplier,
8828
+ getPastMultiplier,
8829
+ getTokenMultiplier,
8830
+ getTokenDAO,
8831
+ getTokenInfo,
8832
+ // Wrapper queries
8833
+ getVotes,
8834
+ getPastVotes,
8835
+ getVotingBreakdown,
8836
+ getPastVotingBreakdown,
8837
+ hasMultiplierBonus
8838
+ };
8839
+ }
8840
+ });
8841
+
8842
+ // src/auction/index.js
8843
+ var require_auction = __commonJS({
8844
+ "src/auction/index.js"(exports2, module2) {
8845
+ var { Contract, Interface, getAddress } = __require("ethers");
8846
+ var ABI = require_abi();
8847
+ var { SageSDKError, CODES } = require_errors();
8848
+ function normaliseAddress(address, label) {
8849
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8850
+ try {
8851
+ return getAddress(address);
8852
+ } catch (err) {
8853
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8854
+ }
8855
+ }
8856
+ function toBigInt(value, label) {
8857
+ if (value === void 0 || value === null) {
8858
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8859
+ }
8860
+ try {
8861
+ return BigInt(value.toString());
8862
+ } catch (err) {
8863
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8864
+ }
8865
+ }
8866
+ function getAuctionContract(provider, auctionHouse) {
8867
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8868
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8869
+ return new Contract(addr, ABI.SageAuctionHouse, provider);
8870
+ }
8871
+ async function getAuction({ provider, auctionHouse }) {
8872
+ const c = getAuctionContract(provider, auctionHouse);
8873
+ const res = await c.auction();
8874
+ const nftId = BigInt(res.nftId.toString());
8875
+ const amount = BigInt(res.amount.toString());
8876
+ const startTime = BigInt(res.startTime.toString());
8877
+ const endTime = BigInt(res.endTime.toString());
8878
+ const bidder = getAddress(res.bidder);
8879
+ const settled = !!res.settled;
8880
+ return { nftId, amount, startTime, endTime, bidder, settled };
8881
+ }
8882
+ async function getConfig({ provider, auctionHouse }) {
8883
+ const c = getAuctionContract(provider, auctionHouse);
8884
+ const [nft, treasury, weth, timeBuffer, reservePrice, minBidIncrementPercentage, duration, mintTierId, defaultTokenURI, paused, owner] = await Promise.all([
8885
+ c.nft(),
8886
+ c.treasury(),
8887
+ c.weth(),
8888
+ c.timeBuffer(),
8889
+ c.reservePrice(),
8890
+ c.minBidIncrementPercentage(),
8891
+ c.duration(),
8892
+ c.mintTierId(),
8893
+ c.defaultTokenURI(),
8894
+ c.paused(),
8895
+ c.owner()
8896
+ ]);
8897
+ return {
8898
+ nft: getAddress(nft),
8899
+ treasury: getAddress(treasury),
8900
+ weth: getAddress(weth),
8901
+ timeBuffer: BigInt(timeBuffer.toString()),
8902
+ reservePrice: BigInt(reservePrice.toString()),
8903
+ minBidIncrementPercentage: BigInt(minBidIncrementPercentage.toString()),
8904
+ duration: BigInt(duration.toString()),
8905
+ mintTierId: BigInt(mintTierId.toString()),
8906
+ defaultTokenURI: String(defaultTokenURI),
8907
+ paused: !!paused,
8908
+ owner: getAddress(owner)
8909
+ };
8910
+ }
8911
+ function buildCreateBidTx({ auctionHouse, nftId, value }) {
8912
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8913
+ const iface = new Interface(ABI.SageAuctionHouse);
8914
+ const data = iface.encodeFunctionData("createBid", [toBigInt(nftId, "nftId")]);
8915
+ return { to: addr, data, value: toBigInt(value, "value") };
8916
+ }
8917
+ function buildSettleAndCreateTx({ auctionHouse }) {
8918
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8919
+ const iface = new Interface(ABI.SageAuctionHouse);
8920
+ const data = iface.encodeFunctionData("settleCurrentAndCreateNewAuction", []);
8921
+ return { to: addr, data, value: 0n };
8922
+ }
8923
+ function buildSettleTx({ auctionHouse }) {
8924
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8925
+ const iface = new Interface(ABI.SageAuctionHouse);
8926
+ const data = iface.encodeFunctionData("settleAuction", []);
8927
+ return { to: addr, data, value: 0n };
8928
+ }
8929
+ function buildCreateAuctionTx({ auctionHouse }) {
8930
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8931
+ const iface = new Interface(ABI.SageAuctionHouse);
8932
+ const data = iface.encodeFunctionData("createAuction", []);
8933
+ return { to: addr, data, value: 0n };
8934
+ }
8935
+ function buildPauseTx({ auctionHouse }) {
8936
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8937
+ const iface = new Interface(ABI.SageAuctionHouse);
8938
+ const data = iface.encodeFunctionData("pause", []);
8939
+ return { to: addr, data, value: 0n };
8940
+ }
8941
+ function buildUnpauseTx({ auctionHouse }) {
8942
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8943
+ const iface = new Interface(ABI.SageAuctionHouse);
8944
+ const data = iface.encodeFunctionData("unpause", []);
8945
+ return { to: addr, data, value: 0n };
8946
+ }
8947
+ function buildSetTimeBufferTx({ auctionHouse, timeBuffer }) {
8948
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8949
+ const iface = new Interface(ABI.SageAuctionHouse);
8950
+ const data = iface.encodeFunctionData("setTimeBuffer", [toBigInt(timeBuffer, "timeBuffer")]);
8951
+ return { to: addr, data, value: 0n };
8952
+ }
8953
+ function buildSetReservePriceTx({ auctionHouse, reservePrice }) {
8954
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8955
+ const iface = new Interface(ABI.SageAuctionHouse);
8956
+ const data = iface.encodeFunctionData("setReservePrice", [toBigInt(reservePrice, "reservePrice")]);
8957
+ return { to: addr, data, value: 0n };
8958
+ }
8959
+ function buildSetMinBidIncrementTx({ auctionHouse, percentage }) {
8960
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8961
+ const iface = new Interface(ABI.SageAuctionHouse);
8962
+ const data = iface.encodeFunctionData("setMinBidIncrementPercentage", [toBigInt(percentage, "percentage")]);
8963
+ return { to: addr, data, value: 0n };
8964
+ }
8965
+ function buildSetDurationTx({ auctionHouse, duration }) {
8966
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8967
+ const iface = new Interface(ABI.SageAuctionHouse);
8968
+ const data = iface.encodeFunctionData("setDuration", [toBigInt(duration, "duration")]);
8969
+ return { to: addr, data, value: 0n };
8970
+ }
8971
+ function buildSetMintTierIdTx({ auctionHouse, tierId }) {
8972
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8973
+ const iface = new Interface(ABI.SageAuctionHouse);
8974
+ const data = iface.encodeFunctionData("setMintTierId", [toBigInt(tierId, "tierId")]);
8975
+ return { to: addr, data, value: 0n };
8976
+ }
8977
+ function buildSetDefaultTokenURITx({ auctionHouse, uri }) {
8978
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8979
+ const iface = new Interface(ABI.SageAuctionHouse);
8980
+ const data = iface.encodeFunctionData("setDefaultTokenURI", [String(uri ?? "")]);
8981
+ return { to: addr, data, value: 0n };
8982
+ }
8983
+ module2.exports = {
8984
+ getAuction,
8985
+ getConfig,
8986
+ buildCreateBidTx,
8987
+ buildSettleAndCreateTx,
8988
+ buildSettleTx,
8989
+ buildCreateAuctionTx,
8990
+ buildPauseTx,
8991
+ buildUnpauseTx,
8992
+ buildSetTimeBufferTx,
8993
+ buildSetReservePriceTx,
8994
+ buildSetMinBidIncrementTx,
8995
+ buildSetDurationTx,
8996
+ buildSetMintTierIdTx,
8997
+ buildSetDefaultTokenURITx
7104
8998
  };
7105
8999
  }
7106
9000
  });
@@ -9910,6 +11804,885 @@ var require_client2 = __commonJS({
9910
11804
  }
9911
11805
  });
9912
11806
 
11807
+ // src/clients/discovery-client.js
11808
+ var require_discovery_client = __commonJS({
11809
+ "src/clients/discovery-client.js"(exports2, module2) {
11810
+ var DiscoveryClient = class {
11811
+ /**
11812
+ * @param {string} baseUrl - Base URL of the discovery API
11813
+ * @param {object} [options] - Client options
11814
+ * @param {number} [options.timeout=10000] - Request timeout in milliseconds
11815
+ * @param {Record<string, string>} [options.headers] - Custom headers
11816
+ */
11817
+ constructor(baseUrl, options = {}) {
11818
+ this.baseUrl = baseUrl.replace(/\/$/, "");
11819
+ this.timeout = options.timeout || 1e4;
11820
+ this.headers = options.headers || {};
11821
+ }
11822
+ /**
11823
+ * Search prompts with keyword matching and trend ranking
11824
+ * @param {string} query - Search query
11825
+ * @param {object} [options] - Search options
11826
+ * @param {string} [options.category] - Filter by category
11827
+ * @param {string[]} [options.tags] - Filter by tags
11828
+ * @param {string} [options.author] - Filter by author
11829
+ * @param {number} [options.limit] - Max results to return
11830
+ * @param {number} [options.offset] - Number of results to skip
11831
+ * @param {boolean} [options.useVector] - Use vector search
11832
+ * @returns {Promise<{results: Array, total: number}>}
11833
+ */
11834
+ async search(query, options = {}) {
11835
+ const params = new URLSearchParams();
11836
+ if (query) params.set("q", query);
11837
+ if (options.category) params.set("category", options.category);
11838
+ if (options.author) params.set("author", options.author);
11839
+ if (options.tags) {
11840
+ options.tags.forEach((tag) => params.append("tags", tag));
11841
+ }
11842
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11843
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11844
+ if (options.useVector !== void 0) params.set("useVector", String(options.useVector));
11845
+ return this._get(`/discover/search?${params}`);
11846
+ }
11847
+ /**
11848
+ * Get trending prompts by time window
11849
+ * @param {object} [options] - Trending options
11850
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11851
+ * @param {string} [options.category] - Filter by category
11852
+ * @param {number} [options.limit] - Max results to return
11853
+ * @param {number} [options.offset] - Number of results to skip
11854
+ * @returns {Promise<{results: Array}>}
11855
+ */
11856
+ async trending(options = {}) {
11857
+ const params = new URLSearchParams();
11858
+ if (options.window) params.set("window", options.window);
11859
+ if (options.category) params.set("category", options.category);
11860
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11861
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11862
+ return this._get(`/discover/trending?${params}`);
11863
+ }
11864
+ /**
11865
+ * Get trending prompts (alias for /trends/top endpoint)
11866
+ * @param {object} [options] - Trending options
11867
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11868
+ * @param {number} [options.limit] - Max results to return
11869
+ * @param {number} [options.offset] - Number of results to skip
11870
+ * @returns {Promise<{results: Array}>}
11871
+ */
11872
+ async trendingTop(options = {}) {
11873
+ const params = new URLSearchParams();
11874
+ if (options.window) params.set("window", options.window);
11875
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11876
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11877
+ return this._get(`/trends/top?${params}`);
11878
+ }
11879
+ /**
11880
+ * Find prompts matching user preferences
11881
+ *
11882
+ * Note: This endpoint is not yet implemented in the backend.
11883
+ * This is a placeholder for future implementation.
11884
+ * @param {object} preferences - User preferences
11885
+ * @param {string[]} [preferences.recentPrompts] - Recent prompt CIDs
11886
+ * @param {string[]} [preferences.preferredTags] - Preferred tags
11887
+ * @param {string[]} [preferences.preferredCategories] - Preferred categories
11888
+ * @param {string[]} [preferences.excludeAuthors] - Authors to exclude
11889
+ * @param {number} [preferences.limit] - Max results
11890
+ * @param {boolean} [preferences.diversify] - Diversify results
11891
+ * @returns {Promise<{results: Array, total: number}>}
11892
+ */
11893
+ async match(preferences) {
11894
+ return this._post("/discover/match", preferences);
11895
+ }
11896
+ /**
11897
+ * Find prompts similar to a given prompt
11898
+ * @param {string} cid - Prompt CID to find similar prompts for
11899
+ * @param {object} [options] - Similar options
11900
+ * @param {number} [options.limit] - Max results to return
11901
+ * @param {'vector'|'keyword'|'hybrid'} [options.method] - Similarity method
11902
+ * @returns {Promise<{similar: Array}>}
11903
+ */
11904
+ async similar(cid, options = {}) {
11905
+ const params = new URLSearchParams();
11906
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11907
+ if (options.method) params.set("method", options.method);
11908
+ return this._get(`/discover/similar/${cid}?${params}`);
11909
+ }
11910
+ /**
11911
+ * Get popular tags with optional clustering
11912
+ * @param {object} [options] - Tags options
11913
+ * @param {number} [options.limit] - Max tags to return
11914
+ * @param {string} [options.category] - Filter by category
11915
+ * @param {boolean} [options.clusters] - Enable tag clustering
11916
+ * @returns {Promise<{tags: Array}>}
11917
+ */
11918
+ async tags(options = {}) {
11919
+ const params = new URLSearchParams();
11920
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11921
+ if (options.category) params.set("category", options.category);
11922
+ if (options.clusters !== void 0) params.set("clusters", String(options.clusters));
11923
+ return this._get(`/discover/tags?${params}`);
11924
+ }
11925
+ /**
11926
+ * Get category statistics
11927
+ *
11928
+ * Note: This endpoint is not yet implemented in the backend.
11929
+ * This is a placeholder for future implementation.
11930
+ * @returns {Promise<{categories: Array}>}
11931
+ */
11932
+ async categories() {
11933
+ return this._get("/discover/categories");
11934
+ }
11935
+ /**
11936
+ * Get prompts by tag
11937
+ * @param {string} tag - Tag to search for
11938
+ * @param {number} [limit] - Max results to return
11939
+ * @returns {Promise<{results: Array}>}
11940
+ */
11941
+ async promptsByTag(tag, limit) {
11942
+ const params = new URLSearchParams();
11943
+ if (limit !== void 0) params.set("limit", String(limit));
11944
+ const encodedTag = encodeURIComponent(tag);
11945
+ return this._get(`/discover/by-tag/${encodedTag}?${params}`);
11946
+ }
11947
+ /**
11948
+ * Get index statistics
11949
+ * @returns {Promise<{totalPrompts: number, totalTags: number, avgTrendScore: number}>}
11950
+ */
11951
+ async stats() {
11952
+ return this._get("/discover/stats");
11953
+ }
11954
+ /**
11955
+ * Get trend signals for a specific CID
11956
+ * @param {string} cid - Prompt CID
11957
+ * @returns {Promise<{usageCount: number, forkCount: number, purchaseCount: number, uniqueBuyers: number, governanceVotes: number, lastActivityAt: number}>}
11958
+ */
11959
+ async trendSignals(cid) {
11960
+ return this._get(`/trends/signals/${cid}`);
11961
+ }
11962
+ /**
11963
+ * Get trend history for a specific CID
11964
+ * @param {string} cid - Prompt CID
11965
+ * @param {object} [options] - History options
11966
+ * @param {number} [options.limit] - Max history entries
11967
+ * @param {number} [options.since] - Timestamp to start from
11968
+ * @returns {Promise<{history: Array}>}
11969
+ */
11970
+ async trendHistory(cid, options = {}) {
11971
+ const params = new URLSearchParams();
11972
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11973
+ if (options.since !== void 0) params.set("since", String(options.since));
11974
+ return this._get(`/trends/history/${cid}?${params}`);
11975
+ }
11976
+ /**
11977
+ * Get trend statistics
11978
+ * @returns {Promise<{totalTracked: number, avgScore: number, maxScore: number, recentlyActive: number}>}
11979
+ */
11980
+ async trendStats() {
11981
+ return this._get("/trends/stats");
11982
+ }
11983
+ /**
11984
+ * Record a usage event for a prompt (requires authentication)
11985
+ * @param {string} cid - Prompt CID
11986
+ * @returns {Promise<{ok: boolean}>}
11987
+ */
11988
+ async recordUsage(cid) {
11989
+ return this._post("/trends/usage", { cid });
11990
+ }
11991
+ // Private fetch helpers
11992
+ /**
11993
+ * Perform a GET request
11994
+ * @private
11995
+ * @param {string} path - API path
11996
+ * @returns {Promise<any>}
11997
+ */
11998
+ async _get(path2) {
11999
+ const controller = new AbortController();
12000
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12001
+ try {
12002
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12003
+ method: "GET",
12004
+ headers: {
12005
+ "Accept": "application/json",
12006
+ ...this.headers
12007
+ },
12008
+ signal: controller.signal
12009
+ });
12010
+ clearTimeout(timeoutId);
12011
+ if (!response.ok) {
12012
+ const errorBody = await response.text().catch(() => "Unknown error");
12013
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12014
+ }
12015
+ return await response.json();
12016
+ } catch (error) {
12017
+ clearTimeout(timeoutId);
12018
+ if (error.name === "AbortError") {
12019
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12020
+ }
12021
+ throw error;
12022
+ }
12023
+ }
12024
+ /**
12025
+ * Perform a POST request
12026
+ * @private
12027
+ * @param {string} path - API path
12028
+ * @param {any} body - Request body
12029
+ * @returns {Promise<any>}
12030
+ */
12031
+ async _post(path2, body) {
12032
+ const controller = new AbortController();
12033
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12034
+ try {
12035
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12036
+ method: "POST",
12037
+ headers: {
12038
+ "Accept": "application/json",
12039
+ "Content-Type": "application/json",
12040
+ ...this.headers
12041
+ },
12042
+ body: JSON.stringify(body),
12043
+ signal: controller.signal
12044
+ });
12045
+ clearTimeout(timeoutId);
12046
+ if (!response.ok) {
12047
+ const errorBody = await response.text().catch(() => "Unknown error");
12048
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12049
+ }
12050
+ return await response.json();
12051
+ } catch (error) {
12052
+ clearTimeout(timeoutId);
12053
+ if (error.name === "AbortError") {
12054
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12055
+ }
12056
+ throw error;
12057
+ }
12058
+ }
12059
+ };
12060
+ module2.exports = { DiscoveryClient };
12061
+ }
12062
+ });
12063
+
12064
+ // src/clients/git-storage-client.js
12065
+ var require_git_storage_client = __commonJS({
12066
+ "src/clients/git-storage-client.js"(exports2, module2) {
12067
+ var GitStorageClient = class {
12068
+ /**
12069
+ * @param {string} baseUrl - Base URL of the API (e.g., 'https://api.sageprotocol.io')
12070
+ * @param {Object} [options] - Client options
12071
+ * @param {number} [options.timeout=30000] - Request timeout in milliseconds
12072
+ * @param {Record<string, string>} [options.headers] - Custom headers
12073
+ * @param {AuthProvider} [options.signer] - Ethers signer for authenticated requests
12074
+ * @param {() => Promise<{address: string, signature: string, nonce: string}>} [options.getAuth] - Custom auth provider
12075
+ * @param {string} [options.token] - Bearer token for authentication
12076
+ */
12077
+ constructor(baseUrl, options = {}) {
12078
+ this.baseUrl = baseUrl.replace(/\/$/, "");
12079
+ this.timeout = options.timeout || 3e4;
12080
+ this.headers = options.headers || {};
12081
+ this.signer = options.signer || null;
12082
+ this.getAuth = options.getAuth || null;
12083
+ this.token = options.token || null;
12084
+ this._authCache = null;
12085
+ this._authCacheExpiry = 0;
12086
+ }
12087
+ // =========================================================================
12088
+ // Library Management
12089
+ // =========================================================================
12090
+ /**
12091
+ * Create a new library
12092
+ * @param {string} subdao - SubDAO address
12093
+ * @param {string} name - Library name
12094
+ * @param {Object} [options] - Creation options
12095
+ * @param {string} [options.description] - Library description
12096
+ * @param {'public'|'private'} [options.visibility='public'] - Library visibility
12097
+ * @returns {Promise<LibraryMetadata>}
12098
+ */
12099
+ async createLibrary(subdao, name, options = {}) {
12100
+ return this._post("/git/libraries", {
12101
+ subdao,
12102
+ name,
12103
+ description: options.description,
12104
+ visibility: options.visibility || "public"
12105
+ }, { auth: true });
12106
+ }
12107
+ /**
12108
+ * Get library metadata
12109
+ * @param {string} subdao - SubDAO address
12110
+ * @returns {Promise<LibraryMetadata>}
12111
+ */
12112
+ async getLibrary(subdao) {
12113
+ return this._get(`/git/libraries/${encodeURIComponent(subdao)}`);
12114
+ }
12115
+ /**
12116
+ * List all libraries
12117
+ * @param {Object} [options] - List options
12118
+ * @param {number} [options.limit=50] - Max results to return
12119
+ * @param {string} [options.cursor] - Pagination cursor
12120
+ * @returns {Promise<{libraries: LibraryMetadata[], cursor?: string}>}
12121
+ */
12122
+ async listLibraries(options = {}) {
12123
+ const params = new URLSearchParams();
12124
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
12125
+ if (options.cursor) params.set("cursor", options.cursor);
12126
+ const queryString = params.toString();
12127
+ return this._get(`/git/libraries${queryString ? "?" + queryString : ""}`);
12128
+ }
12129
+ /**
12130
+ * Delete a library (admin only)
12131
+ * @param {string} subdao - SubDAO address
12132
+ * @returns {Promise<{ok: boolean}>}
12133
+ */
12134
+ async deleteLibrary(subdao) {
12135
+ return this._delete(`/git/libraries/${encodeURIComponent(subdao)}`, { auth: true });
12136
+ }
12137
+ // =========================================================================
12138
+ // Git Object Operations
12139
+ // =========================================================================
12140
+ /**
12141
+ * Store git objects (batch)
12142
+ * @param {string} subdao - SubDAO address
12143
+ * @param {GitObject[]} objects - Objects to store
12144
+ * @returns {Promise<{stored: number}>}
12145
+ */
12146
+ async putObjects(subdao, objects) {
12147
+ return this._post(`/git/${encodeURIComponent(subdao)}/objects`, { objects }, { auth: true });
12148
+ }
12149
+ /**
12150
+ * Get a single git object
12151
+ * @param {string} subdao - SubDAO address
12152
+ * @param {string} oid - Object ID
12153
+ * @returns {Promise<GitObject>}
12154
+ */
12155
+ async getObject(subdao, oid) {
12156
+ return this._get(`/git/${encodeURIComponent(subdao)}/objects/${oid}`);
12157
+ }
12158
+ /**
12159
+ * Get multiple git objects
12160
+ * @param {string} subdao - SubDAO address
12161
+ * @param {string[]} oids - Object IDs
12162
+ * @returns {Promise<{objects: GitObject[]}>}
12163
+ */
12164
+ async getObjects(subdao, oids) {
12165
+ return this._get(`/git/${encodeURIComponent(subdao)}/objects?oids=${oids.join(",")}`);
12166
+ }
12167
+ // =========================================================================
12168
+ // Reference Operations
12169
+ // =========================================================================
12170
+ /**
12171
+ * List all refs
12172
+ * @param {string} subdao - SubDAO address
12173
+ * @returns {Promise<{refs: GitRef[]}>}
12174
+ */
12175
+ async listRefs(subdao) {
12176
+ return this._get(`/git/${encodeURIComponent(subdao)}/refs`);
12177
+ }
12178
+ /**
12179
+ * Get a specific ref
12180
+ * @param {string} subdao - SubDAO address
12181
+ * @param {string} refName - Reference name (e.g., 'refs/heads/main')
12182
+ * @returns {Promise<GitRef>}
12183
+ */
12184
+ async getRef(subdao, refName) {
12185
+ return this._get(`/git/${encodeURIComponent(subdao)}/refs/${encodeURIComponent(refName)}`);
12186
+ }
12187
+ /**
12188
+ * Update a ref
12189
+ * @param {string} subdao - SubDAO address
12190
+ * @param {string} refName - Reference name
12191
+ * @param {string} oid - New object ID
12192
+ * @param {Object} [options] - Update options
12193
+ * @param {string} [options.oldOid] - Expected current OID (for optimistic concurrency)
12194
+ * @returns {Promise<{ok: boolean}>}
12195
+ */
12196
+ async updateRef(subdao, refName, oid, options = {}) {
12197
+ return this._post(
12198
+ `/git/${encodeURIComponent(subdao)}/refs/${encodeURIComponent(refName)}`,
12199
+ { oid, oldOid: options.oldOid },
12200
+ { auth: true }
12201
+ );
12202
+ }
12203
+ // =========================================================================
12204
+ // Sync Operations
12205
+ // =========================================================================
12206
+ /**
12207
+ * Push changes to library
12208
+ * @param {string} subdao - SubDAO address
12209
+ * @param {Object} payload - Push payload
12210
+ * @param {GitObject[]} payload.objects - Objects to push
12211
+ * @param {Record<string, string>} payload.refs - Ref updates (name -> oid)
12212
+ * @param {string} payload.message - Commit message
12213
+ * @returns {Promise<PushResult>}
12214
+ */
12215
+ async push(subdao, payload) {
12216
+ return this._post(`/git/${encodeURIComponent(subdao)}/push`, payload, { auth: true });
12217
+ }
12218
+ /**
12219
+ * Clone a library (get all objects and refs)
12220
+ * @param {string} subdao - SubDAO address
12221
+ * @returns {Promise<{objects: GitObject[], refs: Record<string, string>, metadata: LibraryMetadata}>}
12222
+ */
12223
+ async clone(subdao) {
12224
+ return this._get(`/git/${encodeURIComponent(subdao)}/clone`);
12225
+ }
12226
+ /**
12227
+ * Fetch changes since a commit
12228
+ * @param {string} subdao - SubDAO address
12229
+ * @param {string} [since] - Commit OID to fetch since
12230
+ * @returns {Promise<{objects: GitObject[], refs: Record<string, string>}>}
12231
+ */
12232
+ async fetch(subdao, since) {
12233
+ const params = since ? `?since=${since}` : "";
12234
+ return this._get(`/git/${encodeURIComponent(subdao)}/fetch${params}`);
12235
+ }
12236
+ // =========================================================================
12237
+ // File Access
12238
+ // =========================================================================
12239
+ /**
12240
+ * Get commit history
12241
+ * @param {string} subdao - SubDAO address
12242
+ * @param {Object} [options] - History options
12243
+ * @param {string} [options.ref='refs/heads/main'] - Reference to get history from
12244
+ * @param {number} [options.limit=50] - Max commits to return
12245
+ * @returns {Promise<{commits: GitCommit[]}>}
12246
+ */
12247
+ async getHistory(subdao, options = {}) {
12248
+ const params = new URLSearchParams();
12249
+ if (options.ref) params.set("ref", options.ref);
12250
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
12251
+ return this._get(`/git/${encodeURIComponent(subdao)}/log?${params}`);
12252
+ }
12253
+ /**
12254
+ * Get directory listing
12255
+ * @param {string} subdao - SubDAO address
12256
+ * @param {string} ref - Reference (e.g., 'main')
12257
+ * @param {string} path - Directory path
12258
+ * @returns {Promise<{entries: Array}>}
12259
+ */
12260
+ async getTree(subdao, ref, path2) {
12261
+ return this._get(
12262
+ `/git/${encodeURIComponent(subdao)}/tree/${encodeURIComponent(ref)}/${encodeURIComponent(path2)}`
12263
+ );
12264
+ }
12265
+ /**
12266
+ * Get file contents
12267
+ * @param {string} subdao - SubDAO address
12268
+ * @param {string} ref - Reference (e.g., 'main')
12269
+ * @param {string} path - File path
12270
+ * @returns {Promise<{content: string}>}
12271
+ */
12272
+ async getBlob(subdao, ref, path2) {
12273
+ return this._get(
12274
+ `/git/${encodeURIComponent(subdao)}/blob/${encodeURIComponent(ref)}/${encodeURIComponent(path2)}`
12275
+ );
12276
+ }
12277
+ /**
12278
+ * Get file contents as string (convenience method)
12279
+ * @param {string} subdao - SubDAO address
12280
+ * @param {string} ref - Reference (e.g., 'main')
12281
+ * @param {string} path - File path
12282
+ * @returns {Promise<string>}
12283
+ */
12284
+ async getFile(subdao, ref, path2) {
12285
+ const result = await this.getBlob(subdao, ref, path2);
12286
+ return result.content;
12287
+ }
12288
+ // =========================================================================
12289
+ // Fork Operations
12290
+ // =========================================================================
12291
+ /**
12292
+ * Fork a library to a new SubDAO
12293
+ * @param {string} sourceSubdao - Source SubDAO address to fork from
12294
+ * @param {string} targetSubdao - Target SubDAO address for the fork
12295
+ * @param {Object} [options] - Fork options
12296
+ * @param {string} [options.targetName] - Name for the forked library
12297
+ * @param {string} [options.targetDescription] - Description for the forked library
12298
+ * @returns {Promise<{ok: boolean, forkedLibrary: string, sourceLibrary: string, commitsCopied: number}>}
12299
+ */
12300
+ async fork(sourceSubdao, targetSubdao, options = {}) {
12301
+ return this._post(`/git/libraries/${encodeURIComponent(sourceSubdao)}/fork`, {
12302
+ targetSubdao,
12303
+ targetName: options.targetName,
12304
+ targetDescription: options.targetDescription
12305
+ }, { auth: true });
12306
+ }
12307
+ /**
12308
+ * List forks of a library
12309
+ * @param {string} subdao - SubDAO address
12310
+ * @returns {Promise<{forks: Array, count: number}>}
12311
+ */
12312
+ async getForks(subdao) {
12313
+ return this._get(`/git/libraries/${encodeURIComponent(subdao)}/forks`);
12314
+ }
12315
+ /**
12316
+ * Get upstream fork info (for forked libraries)
12317
+ * @param {string} subdao - SubDAO address
12318
+ * @returns {Promise<{upstreamSubdao: string, upstreamCommit: string, forkedAt: number}>}
12319
+ */
12320
+ async getUpstream(subdao) {
12321
+ return this._get(`/git/${encodeURIComponent(subdao)}/upstream`);
12322
+ }
12323
+ /**
12324
+ * Check if a library is a fork
12325
+ * @param {string} subdao - SubDAO address
12326
+ * @returns {Promise<boolean>}
12327
+ */
12328
+ async isFork(subdao) {
12329
+ try {
12330
+ await this.getUpstream(subdao);
12331
+ return true;
12332
+ } catch (e) {
12333
+ if (e.message && e.message.includes("404")) {
12334
+ return false;
12335
+ }
12336
+ throw e;
12337
+ }
12338
+ }
12339
+ // =========================================================================
12340
+ // Collaborator Operations
12341
+ // =========================================================================
12342
+ /**
12343
+ * List collaborators
12344
+ * @param {string} subdao - SubDAO address
12345
+ * @returns {Promise<{collaborators: Collaborator[]}>}
12346
+ */
12347
+ async listCollaborators(subdao) {
12348
+ return this._get(`/git/${encodeURIComponent(subdao)}/collaborators`);
12349
+ }
12350
+ /**
12351
+ * Add a collaborator
12352
+ * @param {string} subdao - SubDAO address
12353
+ * @param {string} address - Collaborator wallet address
12354
+ * @param {'read'|'write'|'admin'} permission - Permission level
12355
+ * @returns {Promise<{ok: boolean}>}
12356
+ */
12357
+ async addCollaborator(subdao, address, permission) {
12358
+ return this._post(`/git/${encodeURIComponent(subdao)}/collaborators`, {
12359
+ address,
12360
+ permission
12361
+ }, { auth: true });
12362
+ }
12363
+ /**
12364
+ * Remove a collaborator
12365
+ * @param {string} subdao - SubDAO address
12366
+ * @param {string} address - Collaborator wallet address
12367
+ * @returns {Promise<{ok: boolean}>}
12368
+ */
12369
+ async removeCollaborator(subdao, address) {
12370
+ return this._delete(
12371
+ `/git/${encodeURIComponent(subdao)}/collaborators/${encodeURIComponent(address)}`,
12372
+ { auth: true }
12373
+ );
12374
+ }
12375
+ /**
12376
+ * Check permissions for an address
12377
+ * @param {string} subdao - SubDAO address
12378
+ * @param {string} address - Wallet address to check
12379
+ * @returns {Promise<{canRead: boolean, canWrite: boolean, isAdmin: boolean, permission?: string}>}
12380
+ */
12381
+ async getPermissions(subdao, address) {
12382
+ return this._get(
12383
+ `/git/${encodeURIComponent(subdao)}/collaborators/${encodeURIComponent(address)}/permissions`
12384
+ );
12385
+ }
12386
+ // =========================================================================
12387
+ // High-Level Convenience Methods
12388
+ // =========================================================================
12389
+ /**
12390
+ * Push a manifest file (convenience method)
12391
+ * @param {string} subdao - SubDAO address
12392
+ * @param {Object} manifest - Manifest object to push
12393
+ * @param {string} message - Commit message
12394
+ * @returns {Promise<PushResult>}
12395
+ */
12396
+ async pushManifest(subdao, manifest, message) {
12397
+ const content = JSON.stringify(manifest, null, 2);
12398
+ const oid = await this._computeOid(content);
12399
+ const objects = [{
12400
+ oid,
12401
+ type: "blob",
12402
+ size: content.length,
12403
+ data: this._toBase64(content)
12404
+ }];
12405
+ const treeContent = JSON.stringify({ "manifest.json": oid });
12406
+ const treeOid = await this._computeOid(treeContent);
12407
+ objects.push({
12408
+ oid: treeOid,
12409
+ type: "tree",
12410
+ size: treeContent.length,
12411
+ data: this._toBase64(treeContent)
12412
+ });
12413
+ let parentOid = null;
12414
+ try {
12415
+ const currentRef = await this.getRef(subdao, "refs/heads/main");
12416
+ parentOid = currentRef.oid;
12417
+ } catch (e) {
12418
+ }
12419
+ const author = await this._getAuthAddress();
12420
+ const commitContent = JSON.stringify({
12421
+ tree: treeOid,
12422
+ parent: parentOid,
12423
+ message,
12424
+ author: { address: author },
12425
+ timestamp: Date.now()
12426
+ });
12427
+ const commitOid = await this._computeOid(commitContent);
12428
+ objects.push({
12429
+ oid: commitOid,
12430
+ type: "commit",
12431
+ size: commitContent.length,
12432
+ data: this._toBase64(commitContent)
12433
+ });
12434
+ return this.push(subdao, {
12435
+ objects,
12436
+ refs: { "refs/heads/main": commitOid },
12437
+ message
12438
+ });
12439
+ }
12440
+ /**
12441
+ * Get manifest from library (convenience method)
12442
+ * @param {string} subdao - SubDAO address
12443
+ * @param {string} [ref='main'] - Reference to get manifest from
12444
+ * @returns {Promise<Object>}
12445
+ */
12446
+ async getManifest(subdao, ref = "main") {
12447
+ const content = await this.getFile(subdao, ref, "manifest.json");
12448
+ return JSON.parse(content);
12449
+ }
12450
+ // =========================================================================
12451
+ // Private HTTP Methods
12452
+ // =========================================================================
12453
+ /**
12454
+ * Get authentication headers
12455
+ * @private
12456
+ * @returns {Promise<Record<string, string>>}
12457
+ */
12458
+ async _getAuthHeaders() {
12459
+ if (this._authCache && Date.now() < this._authCacheExpiry) {
12460
+ return this._authCache;
12461
+ }
12462
+ if (this.token) {
12463
+ const headers = { Authorization: `Bearer ${this.token}` };
12464
+ this._authCache = headers;
12465
+ this._authCacheExpiry = Date.now() + 36e5;
12466
+ return headers;
12467
+ }
12468
+ if (typeof this.getAuth === "function") {
12469
+ const auth = await this.getAuth();
12470
+ const headers = {
12471
+ "X-Wallet-Address": auth.address,
12472
+ "X-Wallet-Signature": auth.signature,
12473
+ "X-Wallet-Nonce": auth.nonce
12474
+ };
12475
+ this._authCache = headers;
12476
+ this._authCacheExpiry = Date.now() + 3e5;
12477
+ return headers;
12478
+ }
12479
+ if (this.signer) {
12480
+ const signer = typeof this.signer === "function" ? await this.signer() : this.signer;
12481
+ if (!signer) throw new Error("signer_unavailable");
12482
+ const address = await signer.getAddress();
12483
+ const challengeResponse = await this._post("/ipfs/auth/challenge", { address }, { auth: false });
12484
+ const { message, nonce } = challengeResponse;
12485
+ if (!message || !nonce) throw new Error("challenge_response_invalid");
12486
+ const signature = await signer.signMessage(message);
12487
+ const headers = {
12488
+ "X-Wallet-Address": address,
12489
+ "X-Wallet-Signature": signature,
12490
+ "X-Wallet-Nonce": nonce
12491
+ };
12492
+ this._authCache = headers;
12493
+ this._authCacheExpiry = Date.now() + 3e5;
12494
+ return headers;
12495
+ }
12496
+ return {};
12497
+ }
12498
+ /**
12499
+ * Get authenticated address
12500
+ * @private
12501
+ * @returns {Promise<string>}
12502
+ */
12503
+ async _getAuthAddress() {
12504
+ if (this.signer) {
12505
+ const signer = typeof this.signer === "function" ? await this.signer() : this.signer;
12506
+ return signer.getAddress();
12507
+ }
12508
+ if (typeof this.getAuth === "function") {
12509
+ const auth = await this.getAuth();
12510
+ return auth.address;
12511
+ }
12512
+ return "0x0000000000000000000000000000000000000000";
12513
+ }
12514
+ /**
12515
+ * Perform a GET request
12516
+ * @private
12517
+ * @param {string} path - API path
12518
+ * @param {Object} [options] - Request options
12519
+ * @param {boolean} [options.auth=false] - Whether to include auth headers
12520
+ * @returns {Promise<any>}
12521
+ */
12522
+ async _get(path2, options = {}) {
12523
+ const controller = new AbortController();
12524
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12525
+ try {
12526
+ const authHeaders = options.auth ? await this._getAuthHeaders() : {};
12527
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12528
+ method: "GET",
12529
+ headers: {
12530
+ Accept: "application/json",
12531
+ ...this.headers,
12532
+ ...authHeaders
12533
+ },
12534
+ signal: controller.signal
12535
+ });
12536
+ clearTimeout(timeoutId);
12537
+ if (!response.ok) {
12538
+ const errorBody = await response.text().catch(() => "Unknown error");
12539
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12540
+ }
12541
+ return await response.json();
12542
+ } catch (error) {
12543
+ clearTimeout(timeoutId);
12544
+ if (error.name === "AbortError") {
12545
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12546
+ }
12547
+ throw error;
12548
+ }
12549
+ }
12550
+ /**
12551
+ * Perform a POST request
12552
+ * @private
12553
+ * @param {string} path - API path
12554
+ * @param {any} body - Request body
12555
+ * @param {Object} [options] - Request options
12556
+ * @param {boolean} [options.auth=false] - Whether to include auth headers
12557
+ * @returns {Promise<any>}
12558
+ */
12559
+ async _post(path2, body, options = {}) {
12560
+ const controller = new AbortController();
12561
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12562
+ try {
12563
+ const authHeaders = options.auth ? await this._getAuthHeaders() : {};
12564
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12565
+ method: "POST",
12566
+ headers: {
12567
+ Accept: "application/json",
12568
+ "Content-Type": "application/json",
12569
+ ...this.headers,
12570
+ ...authHeaders
12571
+ },
12572
+ body: JSON.stringify(body),
12573
+ signal: controller.signal
12574
+ });
12575
+ clearTimeout(timeoutId);
12576
+ if (!response.ok) {
12577
+ const errorBody = await response.text().catch(() => "Unknown error");
12578
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12579
+ }
12580
+ return await response.json();
12581
+ } catch (error) {
12582
+ clearTimeout(timeoutId);
12583
+ if (error.name === "AbortError") {
12584
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12585
+ }
12586
+ throw error;
12587
+ }
12588
+ }
12589
+ /**
12590
+ * Perform a DELETE request
12591
+ * @private
12592
+ * @param {string} path - API path
12593
+ * @param {Object} [options] - Request options
12594
+ * @param {boolean} [options.auth=false] - Whether to include auth headers
12595
+ * @returns {Promise<any>}
12596
+ */
12597
+ async _delete(path2, options = {}) {
12598
+ const controller = new AbortController();
12599
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12600
+ try {
12601
+ const authHeaders = options.auth ? await this._getAuthHeaders() : {};
12602
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12603
+ method: "DELETE",
12604
+ headers: {
12605
+ Accept: "application/json",
12606
+ ...this.headers,
12607
+ ...authHeaders
12608
+ },
12609
+ signal: controller.signal
12610
+ });
12611
+ clearTimeout(timeoutId);
12612
+ if (!response.ok) {
12613
+ const errorBody = await response.text().catch(() => "Unknown error");
12614
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12615
+ }
12616
+ return await response.json();
12617
+ } catch (error) {
12618
+ clearTimeout(timeoutId);
12619
+ if (error.name === "AbortError") {
12620
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12621
+ }
12622
+ throw error;
12623
+ }
12624
+ }
12625
+ // =========================================================================
12626
+ // Private Utility Methods
12627
+ // =========================================================================
12628
+ /**
12629
+ * Compute a simple hash for object IDs
12630
+ * @private
12631
+ * @param {string} content - Content to hash
12632
+ * @returns {Promise<string>}
12633
+ */
12634
+ async _computeOid(content) {
12635
+ if (typeof crypto !== "undefined" && crypto.subtle) {
12636
+ const encoder = new TextEncoder();
12637
+ const data = encoder.encode(content);
12638
+ const hashBuffer = await crypto.subtle.digest("SHA-1", data);
12639
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
12640
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
12641
+ }
12642
+ let hash = 0;
12643
+ for (let i = 0; i < content.length; i++) {
12644
+ const char = content.charCodeAt(i);
12645
+ hash = (hash << 5) - hash + char;
12646
+ hash = hash & hash;
12647
+ }
12648
+ return Math.abs(hash).toString(16).padStart(40, "0");
12649
+ }
12650
+ /**
12651
+ * Convert string to base64
12652
+ * @private
12653
+ * @param {string} str - String to encode
12654
+ * @returns {string}
12655
+ */
12656
+ _toBase64(str) {
12657
+ if (typeof btoa !== "undefined") {
12658
+ return btoa(str);
12659
+ }
12660
+ return Buffer.from(str).toString("base64");
12661
+ }
12662
+ /**
12663
+ * Clear auth cache (useful after logout)
12664
+ */
12665
+ clearAuthCache() {
12666
+ this._authCache = null;
12667
+ this._authCacheExpiry = 0;
12668
+ }
12669
+ };
12670
+ module2.exports = { GitStorageClient };
12671
+ }
12672
+ });
12673
+
12674
+ // src/clients/index.js
12675
+ var require_clients = __commonJS({
12676
+ "src/clients/index.js"(exports2, module2) {
12677
+ var { DiscoveryClient } = require_discovery_client();
12678
+ var { GitStorageClient } = require_git_storage_client();
12679
+ module2.exports = {
12680
+ DiscoveryClient,
12681
+ GitStorageClient
12682
+ };
12683
+ }
12684
+ });
12685
+
9913
12686
  // src/hooks/useSubDAOs.js
9914
12687
  var require_useSubDAOs = __commonJS({
9915
12688
  "src/hooks/useSubDAOs.js"(exports2, module2) {
@@ -10120,6 +12893,7 @@ var require_src = __commonJS({
10120
12893
  var timelock = require_timelock();
10121
12894
  var factory = require_factory();
10122
12895
  var library = require_library();
12896
+ var lineage = require_lineage();
10123
12897
  var prompt = require_prompt();
10124
12898
  var { SageEchoExecutor } = require_execute();
10125
12899
  var ipfs = require_ipfs();
@@ -10133,6 +12907,9 @@ var require_src = __commonJS({
10133
12907
  var treasury = require_treasury();
10134
12908
  var boost = require_boost();
10135
12909
  var bounty = require_bounty();
12910
+ var contributions = require_contributions();
12911
+ var votingMultiplier = require_votingMultiplier();
12912
+ var auction = require_auction();
10136
12913
  var wallet = require_wallet();
10137
12914
  wallet.session = require_session();
10138
12915
  var walletCastManager = require_cast_manager();
@@ -10153,6 +12930,7 @@ var require_src = __commonJS({
10153
12930
  var serviceErrors = require_errors2();
10154
12931
  var { SimpleCache } = require_cache();
10155
12932
  var { retryWithBackoff } = require_retry();
12933
+ var { DiscoveryClient, GitStorageClient } = require_clients();
10156
12934
  var hooks = null;
10157
12935
  try {
10158
12936
  hooks = require_hooks();
@@ -10168,6 +12946,7 @@ var require_src = __commonJS({
10168
12946
  timelock,
10169
12947
  factory,
10170
12948
  library,
12949
+ lineage,
10171
12950
  prompt,
10172
12951
  ipfs,
10173
12952
  ipns,
@@ -10180,6 +12959,9 @@ var require_src = __commonJS({
10180
12959
  subgraph,
10181
12960
  utils: { ...utils, privateTx, safe, time },
10182
12961
  bounty,
12962
+ contributions,
12963
+ votingMultiplier,
12964
+ auction,
10183
12965
  wallet: Object.assign(wallet, {
10184
12966
  cast: walletCastManager,
10185
12967
  cdp: walletCdpManager
@@ -10200,6 +12982,13 @@ var require_src = __commonJS({
10200
12982
  SimpleCache,
10201
12983
  retryWithBackoff
10202
12984
  },
12985
+ // Client exports
12986
+ clients: {
12987
+ DiscoveryClient,
12988
+ GitStorageClient
12989
+ },
12990
+ DiscoveryClient,
12991
+ GitStorageClient,
10203
12992
  // React hooks (optional - requires react + swr peer dependencies)
10204
12993
  hooks,
10205
12994
  // Legacy exports (deprecated): maintain compatibility while consumers migrate