@sage-protocol/sdk 0.0.8 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -14,7 +14,7 @@ var require_package = __commonJS({
14
14
  "package.json"(exports2, module2) {
15
15
  module2.exports = {
16
16
  name: "@sage-protocol/sdk",
17
- version: "0.0.8",
17
+ version: "0.1.2",
18
18
  description: "Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).",
19
19
  main: "dist/index.cjs",
20
20
  module: "dist/index.mjs",
@@ -24,9 +24,21 @@ var require_package = __commonJS({
24
24
  exports: {
25
25
  ".": {
26
26
  types: "./types/index.d.ts",
27
- require: "./dist/index.cjs",
27
+ browser: "./dist/browser/index.mjs",
28
28
  import: "./dist/index.mjs",
29
- default: "./dist/index.cjs"
29
+ require: "./dist/index.cjs",
30
+ default: "./dist/index.mjs"
31
+ },
32
+ "./browser": {
33
+ types: "./types/index.d.ts",
34
+ import: "./dist/browser/index.mjs",
35
+ default: "./dist/browser/index.mjs"
36
+ },
37
+ "./node": {
38
+ types: "./types/index.d.ts",
39
+ import: "./dist/node/index.mjs",
40
+ require: "./dist/node/index.cjs",
41
+ default: "./dist/node/index.mjs"
30
42
  },
31
43
  "./package.json": "./package.json",
32
44
  "./types/*": "./types/*"
@@ -37,6 +49,12 @@ var require_package = __commonJS({
37
49
  "README.md"
38
50
  ],
39
51
  sideEffects: false,
52
+ browser: {
53
+ fs: false,
54
+ path: false,
55
+ os: false,
56
+ child_process: false
57
+ },
40
58
  repository: {
41
59
  type: "git",
42
60
  url: "git+https://github.com/sage-protocol/sdk.git"
@@ -848,7 +866,17 @@ var require_ipfs = __commonJS({
848
866
  pinUrl: removeTrailingSlash(options.workerPinUrl || env.SAGE_IPFS_WORKER_PIN_URL || ""),
849
867
  warmUrl: removeTrailingSlash(options.workerWarmUrl || env.SAGE_IPFS_WORKER_WARM_URL || ""),
850
868
  signer: options.workerSigner || options.signer || null,
851
- getAuth: options.workerGetAuth || null
869
+ getAuth: options.workerGetAuth || null,
870
+ address: options.workerAddress || env.SAGE_SANDBOX_ADDRESS || "",
871
+ discoveryEventsPath: options.workerDiscoveryEventsPath || env.SAGE_IPFS_WORKER_DISCOVERY_EVENTS_PATH || "/discover/events",
872
+ discoveryMcpPath: options.workerDiscoveryMcpPath || env.SAGE_IPFS_WORKER_DISCOVERY_MCP_PATH || "/discover/mcp",
873
+ discoveryLaunchPath: options.workerDiscoveryLaunchPath || env.SAGE_IPFS_WORKER_DISCOVERY_LAUNCH_PATH || "/discover/launch",
874
+ discoveryFeedPath: options.workerDiscoveryFeedPath || env.SAGE_IPFS_WORKER_DISCOVERY_FEED_PATH || "/discover",
875
+ discoveryMetricsPath: options.workerDiscoveryMetricsPath || env.SAGE_IPFS_WORKER_DISCOVERY_METRICS_PATH || "/discover/metrics",
876
+ governanceReportPath: options.workerGovernanceReportPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REPORT_PATH || "/governance/report",
877
+ governanceReportsPath: options.workerGovernanceReportsPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REPORTS_PATH || "/governance/reports",
878
+ governanceReviewPath: options.workerGovernanceReviewPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REVIEW_PATH || "/governance/report/review",
879
+ governanceBatchPath: options.workerGovernanceBatchPath || env.SAGE_IPFS_WORKER_GOVERNANCE_BATCH_PATH || "/governance/report/batch"
852
880
  },
853
881
  web3: {
854
882
  token: options.web3Token || env.W3S_TOKEN || env.WEB3_STORAGE_TOKEN || ""
@@ -892,6 +920,28 @@ var require_ipfs = __commonJS({
892
920
  if (kind === "delete" && config.worker.pinUrl) return `${ensureEndsWith(config.worker.pinUrl, "/pin")}/${cid}`;
893
921
  throw new Error(`Worker endpoint for ${kind} not configured`);
894
922
  }
923
+ function workerPath(key, fallback) {
924
+ return ensureLeadingSlash(config.worker[key] || fallback);
925
+ }
926
+ function workerEndpoint(key, fallback) {
927
+ const base = workerBaseUrl();
928
+ if (!base) throw new Error("worker_base_url_required");
929
+ return `${base}${workerPath(key, fallback)}`;
930
+ }
931
+ async function postWorkerJson(pathKey, fallback, payload = {}, extraHeaders = {}) {
932
+ const url = workerEndpoint(pathKey, fallback);
933
+ const { headers, auth } = await buildWorkerAuthHeaders({ ...extraHeaders, "Content-Type": "application/json" });
934
+ const body = { ...payload };
935
+ if (auth && body.auth == null) body.auth = auth;
936
+ const response = await axiosInstance.post(url, body, { headers, timeout: config.timeoutMs });
937
+ return response?.data;
938
+ }
939
+ async function getWorkerJson(pathKey, fallback, params = {}, extraHeaders = {}) {
940
+ const url = workerEndpoint(pathKey, fallback);
941
+ const { headers } = await buildWorkerAuthHeaders({ "Accept": "application/json", ...extraHeaders });
942
+ const response = await axiosInstance.get(url, { headers, params, timeout: config.timeoutMs });
943
+ return response?.data;
944
+ }
895
945
  async function buildWorkerAuthHeaders(extraHeaders = {}) {
896
946
  if (config.worker.token) {
897
947
  return { headers: { ...extraHeaders, Authorization: `Bearer ${config.worker.token}` }, auth: null };
@@ -1168,6 +1218,83 @@ var require_ipfs = __commonJS({
1168
1218
  }
1169
1219
  return { provider: null, ok: true };
1170
1220
  }
1221
+ async function recordDiscoveryEvent(event = {}) {
1222
+ if (!event || typeof event !== "object") throw new Error("event required");
1223
+ const promptId = typeof event.promptId === "string" ? event.promptId.trim() : "";
1224
+ if (!promptId) throw new Error("promptId required");
1225
+ const payload = { ...event, promptId };
1226
+ return postWorkerJson("discoveryEventsPath", "/discover/events", payload);
1227
+ }
1228
+ async function recordMcpUsageEvent({ promptId, metadata, address } = {}) {
1229
+ const id = typeof promptId === "string" ? promptId.trim() : "";
1230
+ if (!id) throw new Error("promptId required");
1231
+ const payload = { promptId: id };
1232
+ if (metadata && typeof metadata === "object") payload.metadata = metadata;
1233
+ const actor = address || config.worker.address;
1234
+ if (actor) payload.address = actor;
1235
+ return postWorkerJson("discoveryMcpPath", "/discover/mcp", payload);
1236
+ }
1237
+ async function recordLaunchEvent({ promptId, metadata, address } = {}) {
1238
+ const id = typeof promptId === "string" ? promptId.trim() : "";
1239
+ if (!id) throw new Error("promptId required");
1240
+ const payload = { promptId: id };
1241
+ if (metadata && typeof metadata === "object") payload.metadata = metadata;
1242
+ const actor = address || config.worker.address;
1243
+ if (actor) payload.address = actor;
1244
+ return postWorkerJson("discoveryLaunchPath", "/discover/launch", payload);
1245
+ }
1246
+ async function submitGovernanceReport(payload = {}) {
1247
+ if (!payload || typeof payload !== "object") throw new Error("payload required");
1248
+ const promptId = typeof payload.promptId === "string" ? payload.promptId.trim() : "";
1249
+ if (!promptId) throw new Error("promptId required");
1250
+ const body = { promptId };
1251
+ const reporter = payload.address || config.worker.address;
1252
+ if (reporter) body.address = reporter;
1253
+ if (typeof payload.reason === "string") body.reason = payload.reason;
1254
+ if (typeof payload.note === "string") body.note = payload.note;
1255
+ if (payload.weight !== void 0) {
1256
+ const weight = Number(payload.weight);
1257
+ if (Number.isFinite(weight) && weight > 0) body.weight = weight;
1258
+ }
1259
+ return postWorkerJson("governanceReportPath", "/governance/report", body);
1260
+ }
1261
+ async function listGovernanceReports(params = {}) {
1262
+ const query = {};
1263
+ if (params.status) query.status = params.status;
1264
+ if (params.limit !== void 0) query.limit = params.limit;
1265
+ if (params.cursor !== void 0) query.cursor = params.cursor;
1266
+ return getWorkerJson("governanceReportsPath", "/governance/reports", query);
1267
+ }
1268
+ async function reviewGovernanceReport(payload = {}) {
1269
+ if (!payload || typeof payload !== "object") throw new Error("payload required");
1270
+ const id = typeof payload.id === "string" ? payload.id.trim() : "";
1271
+ if (!id) throw new Error("report id required");
1272
+ const status = typeof payload.status === "string" ? payload.status.trim() : "";
1273
+ if (!status) throw new Error("status required");
1274
+ const body = { id, status };
1275
+ if (typeof payload.note === "string") body.note = payload.note;
1276
+ if (typeof payload.action === "string") body.action = payload.action;
1277
+ return postWorkerJson("governanceReviewPath", "/governance/report/review", body);
1278
+ }
1279
+ async function batchGovernanceReports(payload = {}) {
1280
+ if (!payload || typeof payload !== "object") throw new Error("payload required");
1281
+ const ids = Array.isArray(payload.ids) ? payload.ids.map(String).filter(Boolean) : [];
1282
+ if (!ids.length) throw new Error("ids required");
1283
+ const action = typeof payload.action === "string" ? payload.action.trim() : "";
1284
+ if (!action) throw new Error("action required");
1285
+ const body = { ids, action };
1286
+ if (typeof payload.note === "string") body.note = payload.note;
1287
+ return postWorkerJson("governanceBatchPath", "/governance/report/batch", body);
1288
+ }
1289
+ async function fetchDiscovery(params = {}) {
1290
+ const query = {};
1291
+ if (params.filter) query.filter = params.filter;
1292
+ if (params.limit !== void 0) query.limit = params.limit;
1293
+ return getWorkerJson("discoveryFeedPath", "/discover", query);
1294
+ }
1295
+ async function fetchDiscoveryMetrics(params = {}) {
1296
+ return getWorkerJson("discoveryMetricsPath", "/discover/metrics", params);
1297
+ }
1171
1298
  return {
1172
1299
  config,
1173
1300
  hasPinataCreds,
@@ -1180,6 +1307,15 @@ var require_ipfs = __commonJS({
1180
1307
  warmGateways,
1181
1308
  buildGatewayUrls: (cid, extra) => buildGatewayUrls(cid, config.gateway, extra),
1182
1309
  pin,
1310
+ recordDiscoveryEvent,
1311
+ recordMcpUsage: recordMcpUsageEvent,
1312
+ recordLaunchEvent,
1313
+ submitGovernanceReport,
1314
+ listGovernanceReports,
1315
+ reviewGovernanceReport,
1316
+ batchGovernanceReports,
1317
+ fetchDiscovery,
1318
+ fetchDiscoveryMetrics,
1183
1319
  generateCid
1184
1320
  };
1185
1321
  }
@@ -3120,7 +3256,12 @@ var require_operations = __commonJS({
3120
3256
  proposalId,
3121
3257
  refresh = false,
3122
3258
  cache = null,
3123
- fromBlock = 0
3259
+ fromBlock = 0,
3260
+ helperAddress = null,
3261
+ hints = {},
3262
+ chunkSizeBlocks = 1e4,
3263
+ lookBackBlocks = 2e3,
3264
+ lookAheadBlocks = 2e3
3124
3265
  }) {
3125
3266
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3126
3267
  const govAddr = normaliseGovernor(governor);
@@ -3130,6 +3271,30 @@ var require_operations = __commonJS({
3130
3271
  const cached = await cacheAdapter.load(govAddr, id);
3131
3272
  if (cached) return cached;
3132
3273
  }
3274
+ if (helperAddress) {
3275
+ try {
3276
+ const helperAbi = [
3277
+ "function getProposalTuple(uint256) view returns (address[] targets,uint256[] values,bytes[] calldatas,bytes32 descriptionHash,bool exists)"
3278
+ ];
3279
+ const helper = new Contract(helperAddress, helperAbi, provider);
3280
+ const res = await helper.getProposalTuple(id);
3281
+ if (res && res.exists) {
3282
+ const tuple2 = {
3283
+ id,
3284
+ governor: normaliseGovernor(governor),
3285
+ targets: res.targets || [],
3286
+ values: (res.values || []).map((v) => BigInt(v)),
3287
+ calldatas: (res.calldatas || []).map(String),
3288
+ description: "",
3289
+ descriptionHash: res.descriptionHash || null,
3290
+ createdBlock: null
3291
+ };
3292
+ if (cacheAdapter) await cacheAdapter.save(governor, id, tuple2);
3293
+ return tuple2;
3294
+ }
3295
+ } catch (_) {
3296
+ }
3297
+ }
3133
3298
  let metadata = null;
3134
3299
  try {
3135
3300
  metadata = await governance2.getProposalMetadata({ provider, governor: govAddr, id });
@@ -3137,14 +3302,66 @@ var require_operations = __commonJS({
3137
3302
  metadata = null;
3138
3303
  }
3139
3304
  if (!metadata) {
3140
- const page = await governance2.listProposals({ provider, governor: govAddr, fromBlock, toBlock: "latest" });
3141
- metadata = page.find((entry) => {
3142
- try {
3143
- return normaliseProposalId(entry.id || entry.proposalId) === id;
3144
- } catch (_) {
3145
- return false;
3305
+ let lower = fromBlock || 0;
3306
+ try {
3307
+ const govAbi = new Interface(ABI.Governor);
3308
+ const govC = new Contract(govAddr, govAbi, provider);
3309
+ const snapshot = hints.snapshot ?? await govC.proposalSnapshot(id).catch(() => null);
3310
+ const votingDelay = hints.votingDelay ?? await govC.votingDelay().catch(() => null);
3311
+ if (snapshot !== null && votingDelay !== null) {
3312
+ const approxCreation = Number(snapshot) - Number(votingDelay);
3313
+ lower = approxCreation > 0 ? approxCreation : 0;
3314
+ const upper = lower + Number(lookAheadBlocks);
3315
+ const from = lower > lookBackBlocks ? lower - Number(lookBackBlocks) : 0;
3316
+ const toBlock = await provider.getBlockNumber();
3317
+ const max = Math.min(upper + Number(lookBackBlocks), Number(toBlock));
3318
+ const topic = govC.interface.getEvent("ProposalCreated").topicHash;
3319
+ for (let start = from; start <= max; start += Number(chunkSizeBlocks)) {
3320
+ const end = Math.min(max, start + Number(chunkSizeBlocks));
3321
+ try {
3322
+ const logs = await provider.getLogs({
3323
+ address: govAddr,
3324
+ topics: [topic],
3325
+ fromBlock: start,
3326
+ toBlock: end
3327
+ });
3328
+ for (const log of logs) {
3329
+ try {
3330
+ const parsed = govC.interface.parseLog(log);
3331
+ const pid = normaliseProposalId(parsed.args.proposalId);
3332
+ if (pid === id) {
3333
+ metadata = {
3334
+ id,
3335
+ governor: govAddr,
3336
+ targets: Array.from(parsed.args.targets || [], String),
3337
+ values: Array.from(parsed.args.values || [], (v) => BigInt(v.toString())),
3338
+ calldatas: Array.from(parsed.args.calldatas || [], (b) => String(b)),
3339
+ description: String(parsed.args.description || ""),
3340
+ descriptionHash: governance2.hashDescription ? governance2.hashDescription(String(parsed.args.description || "")) : keccak256(toUtf8Bytes(String(parsed.args.description || ""))),
3341
+ createdBlock: log.blockNumber
3342
+ };
3343
+ break;
3344
+ }
3345
+ } catch (_) {
3346
+ }
3347
+ }
3348
+ if (metadata) break;
3349
+ } catch (_) {
3350
+ }
3351
+ }
3146
3352
  }
3147
- }) || null;
3353
+ } catch (_) {
3354
+ }
3355
+ if (!metadata) {
3356
+ const page = await governance2.listProposals({ provider, governor: govAddr, fromBlock, toBlock: "latest" });
3357
+ metadata = page.find((entry) => {
3358
+ try {
3359
+ return normaliseProposalId(entry.id || entry.proposalId) === id;
3360
+ } catch (_) {
3361
+ return false;
3362
+ }
3363
+ }) || null;
3364
+ }
3148
3365
  }
3149
3366
  if (!metadata) {
3150
3367
  throw new SageSDKError(CODES.NOT_FOUND, "proposal tuple not found");
@@ -3342,10 +3559,11 @@ var require_operations = __commonJS({
3342
3559
  proposalId,
3343
3560
  refresh = false,
3344
3561
  cache = null,
3345
- includeTimeline = false
3562
+ includeTimeline = false,
3563
+ helperAddress = null
3346
3564
  }) {
3347
3565
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3348
- const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache });
3566
+ const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress });
3349
3567
  let proposal = null;
3350
3568
  try {
3351
3569
  proposal = await governance2.getProposal({ provider, governor: tuple.governor, id: tuple.id });
package/dist/index.mjs CHANGED
@@ -20,7 +20,7 @@ var require_package = __commonJS({
20
20
  "package.json"(exports, module) {
21
21
  module.exports = {
22
22
  name: "@sage-protocol/sdk",
23
- version: "0.0.8",
23
+ version: "0.1.2",
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",
@@ -30,9 +30,21 @@ var require_package = __commonJS({
30
30
  exports: {
31
31
  ".": {
32
32
  types: "./types/index.d.ts",
33
- require: "./dist/index.cjs",
33
+ browser: "./dist/browser/index.mjs",
34
34
  import: "./dist/index.mjs",
35
- default: "./dist/index.cjs"
35
+ require: "./dist/index.cjs",
36
+ default: "./dist/index.mjs"
37
+ },
38
+ "./browser": {
39
+ types: "./types/index.d.ts",
40
+ import: "./dist/browser/index.mjs",
41
+ default: "./dist/browser/index.mjs"
42
+ },
43
+ "./node": {
44
+ types: "./types/index.d.ts",
45
+ import: "./dist/node/index.mjs",
46
+ require: "./dist/node/index.cjs",
47
+ default: "./dist/node/index.mjs"
36
48
  },
37
49
  "./package.json": "./package.json",
38
50
  "./types/*": "./types/*"
@@ -43,6 +55,12 @@ var require_package = __commonJS({
43
55
  "README.md"
44
56
  ],
45
57
  sideEffects: false,
58
+ browser: {
59
+ fs: false,
60
+ path: false,
61
+ os: false,
62
+ child_process: false
63
+ },
46
64
  repository: {
47
65
  type: "git",
48
66
  url: "git+https://github.com/sage-protocol/sdk.git"
@@ -854,7 +872,17 @@ var require_ipfs = __commonJS({
854
872
  pinUrl: removeTrailingSlash(options.workerPinUrl || env.SAGE_IPFS_WORKER_PIN_URL || ""),
855
873
  warmUrl: removeTrailingSlash(options.workerWarmUrl || env.SAGE_IPFS_WORKER_WARM_URL || ""),
856
874
  signer: options.workerSigner || options.signer || null,
857
- getAuth: options.workerGetAuth || null
875
+ getAuth: options.workerGetAuth || null,
876
+ address: options.workerAddress || env.SAGE_SANDBOX_ADDRESS || "",
877
+ discoveryEventsPath: options.workerDiscoveryEventsPath || env.SAGE_IPFS_WORKER_DISCOVERY_EVENTS_PATH || "/discover/events",
878
+ discoveryMcpPath: options.workerDiscoveryMcpPath || env.SAGE_IPFS_WORKER_DISCOVERY_MCP_PATH || "/discover/mcp",
879
+ discoveryLaunchPath: options.workerDiscoveryLaunchPath || env.SAGE_IPFS_WORKER_DISCOVERY_LAUNCH_PATH || "/discover/launch",
880
+ discoveryFeedPath: options.workerDiscoveryFeedPath || env.SAGE_IPFS_WORKER_DISCOVERY_FEED_PATH || "/discover",
881
+ discoveryMetricsPath: options.workerDiscoveryMetricsPath || env.SAGE_IPFS_WORKER_DISCOVERY_METRICS_PATH || "/discover/metrics",
882
+ governanceReportPath: options.workerGovernanceReportPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REPORT_PATH || "/governance/report",
883
+ governanceReportsPath: options.workerGovernanceReportsPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REPORTS_PATH || "/governance/reports",
884
+ governanceReviewPath: options.workerGovernanceReviewPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REVIEW_PATH || "/governance/report/review",
885
+ governanceBatchPath: options.workerGovernanceBatchPath || env.SAGE_IPFS_WORKER_GOVERNANCE_BATCH_PATH || "/governance/report/batch"
858
886
  },
859
887
  web3: {
860
888
  token: options.web3Token || env.W3S_TOKEN || env.WEB3_STORAGE_TOKEN || ""
@@ -898,6 +926,28 @@ var require_ipfs = __commonJS({
898
926
  if (kind === "delete" && config.worker.pinUrl) return `${ensureEndsWith(config.worker.pinUrl, "/pin")}/${cid}`;
899
927
  throw new Error(`Worker endpoint for ${kind} not configured`);
900
928
  }
929
+ function workerPath(key, fallback) {
930
+ return ensureLeadingSlash(config.worker[key] || fallback);
931
+ }
932
+ function workerEndpoint(key, fallback) {
933
+ const base = workerBaseUrl();
934
+ if (!base) throw new Error("worker_base_url_required");
935
+ return `${base}${workerPath(key, fallback)}`;
936
+ }
937
+ async function postWorkerJson(pathKey, fallback, payload = {}, extraHeaders = {}) {
938
+ const url = workerEndpoint(pathKey, fallback);
939
+ const { headers, auth } = await buildWorkerAuthHeaders({ ...extraHeaders, "Content-Type": "application/json" });
940
+ const body = { ...payload };
941
+ if (auth && body.auth == null) body.auth = auth;
942
+ const response = await axiosInstance.post(url, body, { headers, timeout: config.timeoutMs });
943
+ return response?.data;
944
+ }
945
+ async function getWorkerJson(pathKey, fallback, params = {}, extraHeaders = {}) {
946
+ const url = workerEndpoint(pathKey, fallback);
947
+ const { headers } = await buildWorkerAuthHeaders({ "Accept": "application/json", ...extraHeaders });
948
+ const response = await axiosInstance.get(url, { headers, params, timeout: config.timeoutMs });
949
+ return response?.data;
950
+ }
901
951
  async function buildWorkerAuthHeaders(extraHeaders = {}) {
902
952
  if (config.worker.token) {
903
953
  return { headers: { ...extraHeaders, Authorization: `Bearer ${config.worker.token}` }, auth: null };
@@ -1174,6 +1224,83 @@ var require_ipfs = __commonJS({
1174
1224
  }
1175
1225
  return { provider: null, ok: true };
1176
1226
  }
1227
+ async function recordDiscoveryEvent(event = {}) {
1228
+ if (!event || typeof event !== "object") throw new Error("event required");
1229
+ const promptId = typeof event.promptId === "string" ? event.promptId.trim() : "";
1230
+ if (!promptId) throw new Error("promptId required");
1231
+ const payload = { ...event, promptId };
1232
+ return postWorkerJson("discoveryEventsPath", "/discover/events", payload);
1233
+ }
1234
+ async function recordMcpUsageEvent({ promptId, metadata, address } = {}) {
1235
+ const id = typeof promptId === "string" ? promptId.trim() : "";
1236
+ if (!id) throw new Error("promptId required");
1237
+ const payload = { promptId: id };
1238
+ if (metadata && typeof metadata === "object") payload.metadata = metadata;
1239
+ const actor = address || config.worker.address;
1240
+ if (actor) payload.address = actor;
1241
+ return postWorkerJson("discoveryMcpPath", "/discover/mcp", payload);
1242
+ }
1243
+ async function recordLaunchEvent({ promptId, metadata, address } = {}) {
1244
+ const id = typeof promptId === "string" ? promptId.trim() : "";
1245
+ if (!id) throw new Error("promptId required");
1246
+ const payload = { promptId: id };
1247
+ if (metadata && typeof metadata === "object") payload.metadata = metadata;
1248
+ const actor = address || config.worker.address;
1249
+ if (actor) payload.address = actor;
1250
+ return postWorkerJson("discoveryLaunchPath", "/discover/launch", payload);
1251
+ }
1252
+ async function submitGovernanceReport(payload = {}) {
1253
+ if (!payload || typeof payload !== "object") throw new Error("payload required");
1254
+ const promptId = typeof payload.promptId === "string" ? payload.promptId.trim() : "";
1255
+ if (!promptId) throw new Error("promptId required");
1256
+ const body = { promptId };
1257
+ const reporter = payload.address || config.worker.address;
1258
+ if (reporter) body.address = reporter;
1259
+ if (typeof payload.reason === "string") body.reason = payload.reason;
1260
+ if (typeof payload.note === "string") body.note = payload.note;
1261
+ if (payload.weight !== void 0) {
1262
+ const weight = Number(payload.weight);
1263
+ if (Number.isFinite(weight) && weight > 0) body.weight = weight;
1264
+ }
1265
+ return postWorkerJson("governanceReportPath", "/governance/report", body);
1266
+ }
1267
+ async function listGovernanceReports(params = {}) {
1268
+ const query = {};
1269
+ if (params.status) query.status = params.status;
1270
+ if (params.limit !== void 0) query.limit = params.limit;
1271
+ if (params.cursor !== void 0) query.cursor = params.cursor;
1272
+ return getWorkerJson("governanceReportsPath", "/governance/reports", query);
1273
+ }
1274
+ async function reviewGovernanceReport(payload = {}) {
1275
+ if (!payload || typeof payload !== "object") throw new Error("payload required");
1276
+ const id = typeof payload.id === "string" ? payload.id.trim() : "";
1277
+ if (!id) throw new Error("report id required");
1278
+ const status = typeof payload.status === "string" ? payload.status.trim() : "";
1279
+ if (!status) throw new Error("status required");
1280
+ const body = { id, status };
1281
+ if (typeof payload.note === "string") body.note = payload.note;
1282
+ if (typeof payload.action === "string") body.action = payload.action;
1283
+ return postWorkerJson("governanceReviewPath", "/governance/report/review", body);
1284
+ }
1285
+ async function batchGovernanceReports(payload = {}) {
1286
+ if (!payload || typeof payload !== "object") throw new Error("payload required");
1287
+ const ids = Array.isArray(payload.ids) ? payload.ids.map(String).filter(Boolean) : [];
1288
+ if (!ids.length) throw new Error("ids required");
1289
+ const action = typeof payload.action === "string" ? payload.action.trim() : "";
1290
+ if (!action) throw new Error("action required");
1291
+ const body = { ids, action };
1292
+ if (typeof payload.note === "string") body.note = payload.note;
1293
+ return postWorkerJson("governanceBatchPath", "/governance/report/batch", body);
1294
+ }
1295
+ async function fetchDiscovery(params = {}) {
1296
+ const query = {};
1297
+ if (params.filter) query.filter = params.filter;
1298
+ if (params.limit !== void 0) query.limit = params.limit;
1299
+ return getWorkerJson("discoveryFeedPath", "/discover", query);
1300
+ }
1301
+ async function fetchDiscoveryMetrics(params = {}) {
1302
+ return getWorkerJson("discoveryMetricsPath", "/discover/metrics", params);
1303
+ }
1177
1304
  return {
1178
1305
  config,
1179
1306
  hasPinataCreds,
@@ -1186,6 +1313,15 @@ var require_ipfs = __commonJS({
1186
1313
  warmGateways,
1187
1314
  buildGatewayUrls: (cid, extra) => buildGatewayUrls(cid, config.gateway, extra),
1188
1315
  pin,
1316
+ recordDiscoveryEvent,
1317
+ recordMcpUsage: recordMcpUsageEvent,
1318
+ recordLaunchEvent,
1319
+ submitGovernanceReport,
1320
+ listGovernanceReports,
1321
+ reviewGovernanceReport,
1322
+ batchGovernanceReports,
1323
+ fetchDiscovery,
1324
+ fetchDiscoveryMetrics,
1189
1325
  generateCid
1190
1326
  };
1191
1327
  }
@@ -3126,7 +3262,12 @@ var require_operations = __commonJS({
3126
3262
  proposalId,
3127
3263
  refresh = false,
3128
3264
  cache = null,
3129
- fromBlock = 0
3265
+ fromBlock = 0,
3266
+ helperAddress = null,
3267
+ hints = {},
3268
+ chunkSizeBlocks = 1e4,
3269
+ lookBackBlocks = 2e3,
3270
+ lookAheadBlocks = 2e3
3130
3271
  }) {
3131
3272
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3132
3273
  const govAddr = normaliseGovernor(governor);
@@ -3136,6 +3277,30 @@ var require_operations = __commonJS({
3136
3277
  const cached = await cacheAdapter.load(govAddr, id);
3137
3278
  if (cached) return cached;
3138
3279
  }
3280
+ if (helperAddress) {
3281
+ try {
3282
+ const helperAbi = [
3283
+ "function getProposalTuple(uint256) view returns (address[] targets,uint256[] values,bytes[] calldatas,bytes32 descriptionHash,bool exists)"
3284
+ ];
3285
+ const helper = new Contract(helperAddress, helperAbi, provider);
3286
+ const res = await helper.getProposalTuple(id);
3287
+ if (res && res.exists) {
3288
+ const tuple2 = {
3289
+ id,
3290
+ governor: normaliseGovernor(governor),
3291
+ targets: res.targets || [],
3292
+ values: (res.values || []).map((v) => BigInt(v)),
3293
+ calldatas: (res.calldatas || []).map(String),
3294
+ description: "",
3295
+ descriptionHash: res.descriptionHash || null,
3296
+ createdBlock: null
3297
+ };
3298
+ if (cacheAdapter) await cacheAdapter.save(governor, id, tuple2);
3299
+ return tuple2;
3300
+ }
3301
+ } catch (_) {
3302
+ }
3303
+ }
3139
3304
  let metadata = null;
3140
3305
  try {
3141
3306
  metadata = await governance.getProposalMetadata({ provider, governor: govAddr, id });
@@ -3143,14 +3308,66 @@ var require_operations = __commonJS({
3143
3308
  metadata = null;
3144
3309
  }
3145
3310
  if (!metadata) {
3146
- const page = await governance.listProposals({ provider, governor: govAddr, fromBlock, toBlock: "latest" });
3147
- metadata = page.find((entry) => {
3148
- try {
3149
- return normaliseProposalId(entry.id || entry.proposalId) === id;
3150
- } catch (_) {
3151
- return false;
3311
+ let lower = fromBlock || 0;
3312
+ try {
3313
+ const govAbi = new Interface(ABI.Governor);
3314
+ const govC = new Contract(govAddr, govAbi, provider);
3315
+ const snapshot = hints.snapshot ?? await govC.proposalSnapshot(id).catch(() => null);
3316
+ const votingDelay = hints.votingDelay ?? await govC.votingDelay().catch(() => null);
3317
+ if (snapshot !== null && votingDelay !== null) {
3318
+ const approxCreation = Number(snapshot) - Number(votingDelay);
3319
+ lower = approxCreation > 0 ? approxCreation : 0;
3320
+ const upper = lower + Number(lookAheadBlocks);
3321
+ const from = lower > lookBackBlocks ? lower - Number(lookBackBlocks) : 0;
3322
+ const toBlock = await provider.getBlockNumber();
3323
+ const max = Math.min(upper + Number(lookBackBlocks), Number(toBlock));
3324
+ const topic = govC.interface.getEvent("ProposalCreated").topicHash;
3325
+ for (let start = from; start <= max; start += Number(chunkSizeBlocks)) {
3326
+ const end = Math.min(max, start + Number(chunkSizeBlocks));
3327
+ try {
3328
+ const logs = await provider.getLogs({
3329
+ address: govAddr,
3330
+ topics: [topic],
3331
+ fromBlock: start,
3332
+ toBlock: end
3333
+ });
3334
+ for (const log of logs) {
3335
+ try {
3336
+ const parsed = govC.interface.parseLog(log);
3337
+ const pid = normaliseProposalId(parsed.args.proposalId);
3338
+ if (pid === id) {
3339
+ metadata = {
3340
+ id,
3341
+ governor: govAddr,
3342
+ targets: Array.from(parsed.args.targets || [], String),
3343
+ values: Array.from(parsed.args.values || [], (v) => BigInt(v.toString())),
3344
+ calldatas: Array.from(parsed.args.calldatas || [], (b) => String(b)),
3345
+ description: String(parsed.args.description || ""),
3346
+ descriptionHash: governance.hashDescription ? governance.hashDescription(String(parsed.args.description || "")) : keccak256(toUtf8Bytes(String(parsed.args.description || ""))),
3347
+ createdBlock: log.blockNumber
3348
+ };
3349
+ break;
3350
+ }
3351
+ } catch (_) {
3352
+ }
3353
+ }
3354
+ if (metadata) break;
3355
+ } catch (_) {
3356
+ }
3357
+ }
3152
3358
  }
3153
- }) || null;
3359
+ } catch (_) {
3360
+ }
3361
+ if (!metadata) {
3362
+ const page = await governance.listProposals({ provider, governor: govAddr, fromBlock, toBlock: "latest" });
3363
+ metadata = page.find((entry) => {
3364
+ try {
3365
+ return normaliseProposalId(entry.id || entry.proposalId) === id;
3366
+ } catch (_) {
3367
+ return false;
3368
+ }
3369
+ }) || null;
3370
+ }
3154
3371
  }
3155
3372
  if (!metadata) {
3156
3373
  throw new SageSDKError(CODES.NOT_FOUND, "proposal tuple not found");
@@ -3348,10 +3565,11 @@ var require_operations = __commonJS({
3348
3565
  proposalId,
3349
3566
  refresh = false,
3350
3567
  cache = null,
3351
- includeTimeline = false
3568
+ includeTimeline = false,
3569
+ helperAddress = null
3352
3570
  }) {
3353
3571
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3354
- const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache });
3572
+ const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress });
3355
3573
  let proposal = null;
3356
3574
  try {
3357
3575
  proposal = await governance.getProposal({ provider, governor: tuple.governor, id: tuple.id });
@@ -7923,7 +8141,7 @@ var require_doppler = __commonJS({
7923
8141
  });
7924
8142
 
7925
8143
  // src/index.js
7926
- var require_index = __commonJS({
8144
+ var require_src = __commonJS({
7927
8145
  "src/index.js"(exports, module) {
7928
8146
  var pkg = require_package();
7929
8147
  var abi = require_abi();
@@ -8023,4 +8241,4 @@ var require_index = __commonJS({
8023
8241
  };
8024
8242
  }
8025
8243
  });
8026
- export default require_index();
8244
+ export default require_src();