bsv-mcp 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -25873,7 +25873,7 @@ var init_package = __esm(() => {
25873
25873
  name: "bsv-mcp",
25874
25874
  module: "dist/index.js",
25875
25875
  type: "module",
25876
- version: "0.5.1",
25876
+ version: "0.6.0",
25877
25877
  license: "MIT",
25878
25878
  author: "satchmo",
25879
25879
  description: "A collection of Bitcoin SV (BSV) tools for the Model Context Protocol (MCP) framework",
@@ -25949,7 +25949,6 @@ var init_package = __esm(() => {
25949
25949
  "@opl.dev/vault": "0.0.1",
25950
25950
  "better-auth": "1.7.3",
25951
25951
  "bitcoin-backup": "^0.1.0",
25952
- "bmap-api-types": "0.0.9",
25953
25952
  "bsv-bap": "^0.3.7",
25954
25953
  jose: "^6.2.12",
25955
25954
  "js-1sat-ord": "^0.1.91",
@@ -84144,17 +84143,6 @@ function createSuccessResponse(data) {
84144
84143
  isError: false
84145
84144
  };
84146
84145
  }
84147
- function createResponse(result) {
84148
- return {
84149
- content: [
84150
- {
84151
- type: "text",
84152
- text: JSON.stringify(result, null, 2)
84153
- }
84154
- ],
84155
- isError: !result.success
84156
- };
84157
- }
84158
84146
 
84159
84147
  // tools/utils/logger.ts
84160
84148
  var init_logger2 = () => {};
@@ -84168,32 +84156,6 @@ function numArrayToBuffer(numArray) {
84168
84156
  }
84169
84157
 
84170
84158
  // utils/broadcaster.ts
84171
- class BsocialBroadcaster {
84172
- async broadcast(transaction) {
84173
- const response = await fetch(`${BSOCIAL_API_URL}/submit`, {
84174
- method: "POST",
84175
- headers: {
84176
- "Content-Type": "application/octet-stream",
84177
- "X-BSV-TOPIC": "tm_bsocial,tm_bap"
84178
- },
84179
- body: numArrayToBuffer(transaction.toBEEF())
84180
- });
84181
- if (!response.ok) {
84182
- return {
84183
- status: "error",
84184
- code: response.statusText,
84185
- txid: transaction.id("hex"),
84186
- description: response.statusText
84187
- };
84188
- }
84189
- return {
84190
- status: "success",
84191
- txid: transaction.id("hex"),
84192
- message: "Transaction broadcasted successfully"
84193
- };
84194
- }
84195
- }
84196
-
84197
84159
  class V5Broadcaster {
84198
84160
  async broadcast(transaction) {
84199
84161
  const response = await fetch(`${V5_API_URL}/submit`, {
@@ -84263,33 +84225,33 @@ async function buildAndSendTransaction(config, broadcast = true) {
84263
84225
  }
84264
84226
  const totalOutputSatoshis = outputs.reduce((sum, out) => sum + out.satoshis, 0);
84265
84227
  let totalInputSatoshis = 0;
84266
- const selectedUtxos = [];
84267
- const sortedUtxos = [...utxos].sort((a, b) => a.satoshis - b.satoshis);
84228
+ const feeModel = new SatoshisPerKilobyte(feePerByte * 1000);
84229
+ tx.addOutput({ lockingScript: p2pkh.lock(changeAddress), satoshis: 0 });
84230
+ let estimatedFee = 0;
84231
+ const sortedUtxos = [...utxos].sort((a, b) => b.satoshis - a.satoshis);
84268
84232
  for (const utxo of sortedUtxos) {
84269
- selectedUtxos.push(utxo);
84270
84233
  totalInputSatoshis += utxo.satoshis;
84271
84234
  tx.addInput(fromUtxo(utxo, p2pkh.unlock(paymentKey, "all", false, utxo.satoshis, Script.fromHex(utxo.script))));
84272
- const estimatedSize = tx.toHex().length / 2 + 150;
84273
- const estimatedFee = Math.ceil(estimatedSize * feePerByte);
84274
- if (totalInputSatoshis >= totalOutputSatoshis + estimatedFee + DUST_LIMIT) {
84235
+ estimatedFee = await feeModel.computeFee(tx);
84236
+ if (totalInputSatoshis >= totalOutputSatoshis + estimatedFee) {
84275
84237
  break;
84276
84238
  }
84277
84239
  }
84278
- const estimatedSize = tx.toHex().length / 2 + 35;
84279
- const fee = Math.ceil(estimatedSize * feePerByte);
84280
- if (totalInputSatoshis < totalOutputSatoshis + fee) {
84240
+ let change = totalInputSatoshis - totalOutputSatoshis - estimatedFee;
84241
+ if (change < DUST_LIMIT) {
84242
+ tx.outputs.pop();
84243
+ estimatedFee = await feeModel.computeFee(tx);
84244
+ change = totalInputSatoshis - totalOutputSatoshis - estimatedFee;
84245
+ } else {
84246
+ tx.outputs[tx.outputs.length - 1].satoshis = change;
84247
+ }
84248
+ if (change < 0) {
84281
84249
  return {
84282
84250
  success: false,
84283
- error: `Insufficient funds. Have ${totalInputSatoshis} sats, need ${totalOutputSatoshis + fee} sats`
84251
+ error: `Insufficient funds. Have ${totalInputSatoshis} sats, need ${totalOutputSatoshis + estimatedFee} sats`
84284
84252
  };
84285
84253
  }
84286
- const change = totalInputSatoshis - totalOutputSatoshis - fee;
84287
- if (change >= DUST_LIMIT) {
84288
- tx.addOutput({
84289
- lockingScript: p2pkh.lock(changeAddress),
84290
- satoshis: change
84291
- });
84292
- }
84254
+ const fee = totalInputSatoshis - tx.outputs.reduce((sum, output) => sum + (output.satoshis ?? 0), 0);
84293
84255
  await tx.sign();
84294
84256
  const rawTx = tx.toHex();
84295
84257
  const txid = tx.id("hex");
@@ -84314,7 +84276,7 @@ async function buildAndSendTransaction(config, broadcast = true) {
84314
84276
  }
84315
84277
  if (isBroadcastFailure(broadcastResult)) {
84316
84278
  return {
84317
- success: true,
84279
+ success: false,
84318
84280
  txid,
84319
84281
  rawTx,
84320
84282
  fee,
@@ -84322,7 +84284,7 @@ async function buildAndSendTransaction(config, broadcast = true) {
84322
84284
  };
84323
84285
  }
84324
84286
  return {
84325
- success: true,
84287
+ success: false,
84326
84288
  txid,
84327
84289
  rawTx,
84328
84290
  fee,
@@ -84330,7 +84292,7 @@ async function buildAndSendTransaction(config, broadcast = true) {
84330
84292
  };
84331
84293
  } catch (error) {
84332
84294
  return {
84333
- success: true,
84295
+ success: false,
84334
84296
  txid,
84335
84297
  rawTx,
84336
84298
  fee,
@@ -113044,298 +113006,6 @@ var init_compactCatalog = __esm(() => {
113044
113006
  ORDINALS_READS = COMPACT_OPERATION_LEGACY_NAMES.ordinals_read;
113045
113007
  });
113046
113008
 
113047
- // utils/keys.ts
113048
- var friendPrivateKeyFromMemberIdKey = (memberIdKey, targetBapId) => {
113049
- return memberIdKey.deriveChild(memberIdKey.toPublicKey(), targetBapId);
113050
- };
113051
- var init_keys2 = () => {};
113052
-
113053
- // tools/wallet/utxo.ts
113054
- async function getBeefTransactionById(txid) {
113055
- const url = `${junglebusUrl()}/transaction/beef/${txid}`;
113056
- try {
113057
- const response = await fetch(url);
113058
- if (!response.ok) {
113059
- console.warn(`Failed to fetch transaction ${txid} from Junglebus: ${response.status} ${response.statusText}`);
113060
- return null;
113061
- }
113062
- const rawTxBuffer = await response.arrayBuffer();
113063
- if (!rawTxBuffer) {
113064
- console.warn(`Empty raw transaction buffer for ${txid} from Junglebus`);
113065
- return null;
113066
- }
113067
- const uint8Array = arrayBufferToUint8Array(rawTxBuffer);
113068
- const tx = Transaction.fromBEEF(uint8Array, txid);
113069
- return tx;
113070
- } catch (error) {
113071
- console.warn(`Error fetching or parsing transaction ${txid}: ${error instanceof Error ? error.message : String(error)}`);
113072
- return null;
113073
- }
113074
- }
113075
- var init_utxo = __esm(() => {
113076
- init_mod();
113077
- init_backends();
113078
- });
113079
-
113080
- // tools/wallet/fetchPaymentUtxos.ts
113081
- async function fetchPaymentUtxos(address) {
113082
- if (!address) {
113083
- console.error("fetchPaymentUtxos: No address provided");
113084
- return;
113085
- }
113086
- try {
113087
- const response = await explorerFetch(`${explorerUrl()}/address/${address}/unspent`);
113088
- if (!response.ok) {
113089
- console.error(`explorer API error: ${response.status} ${response.statusText}`);
113090
- return;
113091
- }
113092
- const data = await response.json();
113093
- if (!Array.isArray(data)) {
113094
- console.error("Invalid response format from explorer API");
113095
- return;
113096
- }
113097
- const utxos = await Promise.all(data.map(async (utxo) => {
113098
- const tx = await getBeefTransactionById(utxo.tx_hash);
113099
- const script = tx?.outputs[utxo.tx_pos]?.lockingScript.toHex();
113100
- if (!script) {
113101
- console.error(`Could not get script for UTXO: ${utxo.tx_hash}:${utxo.tx_pos}`);
113102
- return null;
113103
- }
113104
- return {
113105
- txid: utxo.tx_hash,
113106
- vout: utxo.tx_pos,
113107
- satoshis: utxo.value,
113108
- script
113109
- };
113110
- }));
113111
- const validUtxos = utxos.filter((utxo) => utxo !== null);
113112
- return validUtxos;
113113
- } catch (error) {
113114
- console.error("Error fetching payment UTXOs:", error);
113115
- return;
113116
- }
113117
- }
113118
- async function fetchPaymentUtxosFromV5(address) {
113119
- try {
113120
- const url = `${V5_API_URL}/own/${address}/utxos?refresh=true&txo=true&script=true&limit=250&tags=p2pkh`;
113121
- console.error(`Fetching UTXOs from V5: ${url}`);
113122
- const response = await fetch(url);
113123
- if (!response.ok) {
113124
- console.error(`V5 UTXO fetch failed: ${response.status} ${response.statusText}`);
113125
- return;
113126
- }
113127
- const data = await response.json();
113128
- if (!Array.isArray(data)) {
113129
- console.error(`V5 UTXO response was not an array: ${typeof data}`);
113130
- return;
113131
- }
113132
- const utxos = [];
113133
- for (const utxo of data) {
113134
- if (!utxo.data.p2pkh) {
113135
- continue;
113136
- }
113137
- const [txid, vout] = utxo.outpoint.split("_");
113138
- if (!txid || !vout) {
113139
- console.error(`Invalid outpoint: ${utxo.outpoint}`);
113140
- continue;
113141
- }
113142
- utxos.push({
113143
- txid,
113144
- vout: Number.parseInt(vout, 10),
113145
- satoshis: utxo.satoshis,
113146
- script: toHex6(toArray9(utxo.script, "base64"))
113147
- });
113148
- }
113149
- return utxos;
113150
- } catch (error) {
113151
- console.error("Error fetching payment UTXOs from V5:", error);
113152
- return;
113153
- }
113154
- }
113155
- var toHex6, toArray9;
113156
- var init_fetchPaymentUtxos = __esm(() => {
113157
- init_mod();
113158
- init_backends();
113159
- init_constants2();
113160
- init_utxo();
113161
- ({ toHex: toHex6, toArray: toArray9 } = exports_utils);
113162
- });
113163
-
113164
- // tools/bap/friend.ts
113165
- function registerBapFriendTool(server, wallet, xprv, config) {
113166
- server.registerTool("bap_friend", {
113167
- description: "Initiates a friend request to another BAP ID by broadcasting an on-chain MAP transaction.",
113168
- inputSchema: bapFriendArgsSchema
113169
- }, async ({ targetBapId }, _extra) => {
113170
- const _logFunc = console.error;
113171
- try {
113172
- if (!xprv) {
113173
- return {
113174
- isError: true,
113175
- content: [
113176
- {
113177
- type: "text",
113178
- text: "Server does not have a BAP master key (xprv). Cannot derive friend public key."
113179
- }
113180
- ]
113181
- };
113182
- }
113183
- const payPk = wallet.getPaymentKey();
113184
- const identityPk = wallet.getIdentityKey();
113185
- if (!identityPk || !payPk) {
113186
- return {
113187
- isError: true,
113188
- content: [
113189
- {
113190
- type: "text",
113191
- text: !payPk ? "Wallet private key not available. Cannot fund friend request transaction." : "Wallet identity key not available. Cannot derive friend public key."
113192
- }
113193
- ]
113194
- };
113195
- }
113196
- const bap = new a(xprv);
113197
- const idpk = bap.newId().getAccountKey();
113198
- const paymentAddress = payPk.toAddress();
113199
- const friendPubKey = friendPrivateKeyFromMemberIdKey(identityPk, targetBapId).toPublicKey().toString();
113200
- const payloadParts = [
113201
- MAP_PREFIX2,
113202
- "SET",
113203
- "app",
113204
- APP_DOMAIN,
113205
- "type",
113206
- "friend",
113207
- "bapID",
113208
- targetBapId,
113209
- "publicKey",
113210
- friendPubKey
113211
- ];
113212
- const payloadBuffers = payloadParts.map((part) => toArray10(part));
113213
- const { signedData } = await signOpReturnWithAIP(payloadBuffers, idpk, idpk.toAddress());
113214
- const opReturnScript = buildOpReturnScript(signedData);
113215
- const tx = new Transaction;
113216
- tx.addOutput({ lockingScript: opReturnScript, satoshis: 0 });
113217
- const utxos = await fetchPaymentUtxosFromV5(paymentAddress);
113218
- if (!utxos || utxos.length === 0) {
113219
- return {
113220
- isError: true,
113221
- content: [
113222
- {
113223
- type: "text",
113224
- text: `No UTXOs available for payment address ${paymentAddress}. Cannot send friend request.`
113225
- }
113226
- ]
113227
- };
113228
- }
113229
- const feeModel = new SatoshisPerKilobyte(10);
113230
- let totalInput = 0n;
113231
- let estFee = await feeModel.computeFee(tx);
113232
- for (const utxo of utxos) {
113233
- if (totalInput >= BigInt(estFee))
113234
- break;
113235
- const unlockTemplate = new P2PKH().unlock(payPk, "all", false, utxo.satoshis, Script.fromBinary(toArray10(utxo.script, "hex")));
113236
- const input = fromUtxo(utxo, unlockTemplate);
113237
- tx.addInput(input);
113238
- totalInput += BigInt(utxo.satoshis);
113239
- estFee = await feeModel.computeFee(tx);
113240
- }
113241
- if (totalInput < BigInt(estFee)) {
113242
- return {
113243
- isError: true,
113244
- content: [
113245
- {
113246
- type: "text",
113247
- text: `Not enough funds to cover fee. Needed ${estFee}, have ${totalInput}.`
113248
- }
113249
- ]
113250
- };
113251
- }
113252
- const change = totalInput - BigInt(estFee);
113253
- if (change > 0n) {
113254
- tx.addOutput({
113255
- lockingScript: new P2PKH().lock(paymentAddress),
113256
- satoshis: Number(change),
113257
- change: true
113258
- });
113259
- }
113260
- await tx.fee(feeModel);
113261
- await tx.sign();
113262
- const txHex = tx.toHex();
113263
- const txid = tx.id("hex");
113264
- if (config?.disableBroadcasting) {
113265
- return {
113266
- content: [
113267
- {
113268
- type: "text",
113269
- text: JSON.stringify({
113270
- success: true,
113271
- disabledBroadcast: true,
113272
- txid,
113273
- rawTx: txHex,
113274
- message: `Broadcasting disabled. Friend request transaction built for ${targetBapId}.`
113275
- })
113276
- }
113277
- ]
113278
- };
113279
- }
113280
- const broadcaster = new BsocialBroadcaster;
113281
- const broadcastResult = await tx.broadcast(broadcaster);
113282
- let success = true;
113283
- let errorMsg;
113284
- let resultTxid = txid;
113285
- if (isBroadcastResponse(broadcastResult)) {
113286
- resultTxid = broadcastResult.txid;
113287
- } else if (isBroadcastFailure(broadcastResult)) {
113288
- success = false;
113289
- const failure = broadcastResult;
113290
- errorMsg = `Broadcast failed: ${failure.description} (Code: ${failure.code})`;
113291
- if (failure.txid)
113292
- resultTxid = failure.txid;
113293
- }
113294
- return {
113295
- isError: !success,
113296
- content: [
113297
- {
113298
- type: "text",
113299
- text: JSON.stringify({
113300
- success,
113301
- txid: resultTxid,
113302
- rawTx: txHex,
113303
- message: success ? `Friend request sent to ${targetBapId}.` : errorMsg ?? "Broadcast failed"
113304
- })
113305
- }
113306
- ]
113307
- };
113308
- } catch (err) {
113309
- const errMsg = err instanceof Error ? err.message : String(err);
113310
- return {
113311
- isError: true,
113312
- content: [
113313
- {
113314
- type: "text",
113315
- text: `Failed to send friend request: ${errMsg}`
113316
- }
113317
- ]
113318
- };
113319
- }
113320
- });
113321
- }
113322
- var toArray10, APP_DOMAIN = "bsv-mcp", bapFriendArgsSchema;
113323
- var init_friend = __esm(() => {
113324
- init_mod();
113325
- init_index_modern();
113326
- init_zod();
113327
- init_broadcaster();
113328
- init_keys2();
113329
- init_constants2();
113330
- init_aip();
113331
- init_transactionBuilder();
113332
- init_fetchPaymentUtxos();
113333
- ({ toArray: toArray10 } = exports_utils);
113334
- bapFriendArgsSchema = object2({
113335
- targetBapId: string2().min(1, "targetBapId is required.")
113336
- });
113337
- });
113338
-
113339
113009
  // utils/accounts.ts
113340
113010
  import { createHash as createHash2, randomBytes } from "node:crypto";
113341
113011
  import {
@@ -113760,7 +113430,7 @@ function isSigmaSeedBackup(value) {
113760
113430
  return true;
113761
113431
  }
113762
113432
  async function deriveKey(passphrase, salt, iterations = RECOMMENDED_PBKDF2_ITERATIONS) {
113763
- const passphraseBytes = Uint8Array.from(toArray11(passphrase, "utf8"));
113433
+ const passphraseBytes = Uint8Array.from(toArray9(passphrase, "utf8"));
113764
113434
  const keyMaterial = await globalThis.crypto.subtle.importKey("raw", passphraseBytes, { name: "PBKDF2" }, false, ["deriveKey"]);
113765
113435
  return globalThis.crypto.subtle.deriveKey({
113766
113436
  name: "PBKDF2",
@@ -113857,7 +113527,7 @@ function isValidPayload(payload) {
113857
113527
  async function decryptData(encryptedBackup, passphrase, attemptIterations) {
113858
113528
  let combinedBytesNumbers;
113859
113529
  try {
113860
- combinedBytesNumbers = toArray11(encryptedBackup, "base64");
113530
+ combinedBytesNumbers = toArray9(encryptedBackup, "base64");
113861
113531
  } catch (error) {
113862
113532
  console.error("Failed to decode base64 string (toArray threw):", error);
113863
113533
  throw new Error("Decryption failed: Invalid Base64 input.");
@@ -114608,7 +114278,7 @@ var __create3, __getProtoOf3, __defProp5, __getOwnPropNames3, __hasOwnProp3, __t
114608
114278
  if (canCache)
114609
114279
  cache.set(mod, to);
114610
114280
  return to;
114611
- }, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), require_utf8, require_ExtData, require_DecodeError, require_int, require_timestamp, require_ExtensionCodec, require_typedArrays, require_Encoder, require_encode, require_prettyByte, require_CachedKeyDecoder, require_Decoder, require_decode, require_stream2, require_decodeAsync, require_dist2, MAX_INDEX = 2147483647, fields2, profileFields2, toArray11, toBase644, RECOMMENDED_PBKDF2_ITERATIONS = 600000, LEGACY_PBKDF2_ITERATIONS = 1e5, SALT_LENGTH_BYTES = 16, IV_LENGTH_BYTES = 12, AES_KEY_LENGTH_BITS = 256, toArray22, toBase6422, INFO = "se-vault-v1", toArray32, toBase6432, ENVELOPE_VERSION = 2, MAGIC_BYTES, SALT_LENGTH_BYTES2 = 16, IV_LENGTH_BYTES2 = 12, CONTENT_KEY_LENGTH_BYTES = 32, EPHEMERAL_PUB_LENGTH = 65, NONCE_LENGTH = 12, GCM_TAG_LENGTH = 16, SLOT_ID_RE, import_msgpack;
114281
+ }, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), require_utf8, require_ExtData, require_DecodeError, require_int, require_timestamp, require_ExtensionCodec, require_typedArrays, require_Encoder, require_encode, require_prettyByte, require_CachedKeyDecoder, require_Decoder, require_decode, require_stream2, require_decodeAsync, require_dist2, MAX_INDEX = 2147483647, fields2, profileFields2, toArray9, toBase644, RECOMMENDED_PBKDF2_ITERATIONS = 600000, LEGACY_PBKDF2_ITERATIONS = 1e5, SALT_LENGTH_BYTES = 16, IV_LENGTH_BYTES = 12, AES_KEY_LENGTH_BITS = 256, toArray22, toBase6422, INFO = "se-vault-v1", toArray32, toBase6432, ENVELOPE_VERSION = 2, MAGIC_BYTES, SALT_LENGTH_BYTES2 = 16, IV_LENGTH_BYTES2 = 12, CONTENT_KEY_LENGTH_BYTES = 32, EPHEMERAL_PUB_LENGTH = 65, NONCE_LENGTH = 12, GCM_TAG_LENGTH = 16, SLOT_ID_RE, import_msgpack;
114612
114282
  var init_dist9 = __esm(() => {
114613
114283
  init_mod();
114614
114284
  init_mod();
@@ -116240,7 +115910,7 @@ var init_dist9 = __esm(() => {
116240
115910
  "label"
116241
115911
  ]);
116242
115912
  profileFields2 = new Set(["index", "bapId", "metadata"]);
116243
- ({ toArray: toArray11, toBase64: toBase644 } = exports_utils);
115913
+ ({ toArray: toArray9, toBase64: toBase644 } = exports_utils);
116244
115914
  ({ toArray: toArray22, toBase64: toBase6422 } = exports_utils);
116245
115915
  ({ toArray: toArray32, toBase64: toBase6432 } = exports_utils);
116246
115916
  MAGIC_BYTES = [66, 69, 80, 50];
@@ -116403,6 +116073,117 @@ var init_keyManager = __esm(() => {
116403
116073
  keyManager = new SecureKeyManager;
116404
116074
  });
116405
116075
 
116076
+ // tools/wallet/utxo.ts
116077
+ async function getBeefTransactionById(txid) {
116078
+ const url = `${junglebusUrl()}/transaction/beef/${txid}`;
116079
+ try {
116080
+ const response = await fetch(url);
116081
+ if (!response.ok) {
116082
+ console.warn(`Failed to fetch transaction ${txid} from Junglebus: ${response.status} ${response.statusText}`);
116083
+ return null;
116084
+ }
116085
+ const rawTxBuffer = await response.arrayBuffer();
116086
+ if (!rawTxBuffer) {
116087
+ console.warn(`Empty raw transaction buffer for ${txid} from Junglebus`);
116088
+ return null;
116089
+ }
116090
+ const uint8Array = arrayBufferToUint8Array(rawTxBuffer);
116091
+ const tx = Transaction.fromBEEF(uint8Array, txid);
116092
+ return tx;
116093
+ } catch (error) {
116094
+ console.warn(`Error fetching or parsing transaction ${txid}: ${error instanceof Error ? error.message : String(error)}`);
116095
+ return null;
116096
+ }
116097
+ }
116098
+ var init_utxo = __esm(() => {
116099
+ init_mod();
116100
+ init_backends();
116101
+ });
116102
+
116103
+ // tools/wallet/fetchPaymentUtxos.ts
116104
+ async function fetchPaymentUtxos(address) {
116105
+ if (!address) {
116106
+ console.error("fetchPaymentUtxos: No address provided");
116107
+ return;
116108
+ }
116109
+ try {
116110
+ const response = await explorerFetch(`${explorerUrl()}/address/${address}/unspent`);
116111
+ if (!response.ok) {
116112
+ console.error(`explorer API error: ${response.status} ${response.statusText}`);
116113
+ return;
116114
+ }
116115
+ const data = await response.json();
116116
+ if (!Array.isArray(data)) {
116117
+ console.error("Invalid response format from explorer API");
116118
+ return;
116119
+ }
116120
+ const utxos = await Promise.all(data.map(async (utxo) => {
116121
+ const tx = await getBeefTransactionById(utxo.tx_hash);
116122
+ const script = tx?.outputs[utxo.tx_pos]?.lockingScript.toHex();
116123
+ if (!script) {
116124
+ console.error(`Could not get script for UTXO: ${utxo.tx_hash}:${utxo.tx_pos}`);
116125
+ return null;
116126
+ }
116127
+ return {
116128
+ txid: utxo.tx_hash,
116129
+ vout: utxo.tx_pos,
116130
+ satoshis: utxo.value,
116131
+ script
116132
+ };
116133
+ }));
116134
+ const validUtxos = utxos.filter((utxo) => utxo !== null);
116135
+ return validUtxos;
116136
+ } catch (error) {
116137
+ console.error("Error fetching payment UTXOs:", error);
116138
+ return;
116139
+ }
116140
+ }
116141
+ async function fetchPaymentUtxosFromV5(address) {
116142
+ try {
116143
+ const url = `${V5_API_URL}/own/${address}/utxos?refresh=true&txo=true&script=true&limit=250&tags=p2pkh`;
116144
+ console.error(`Fetching UTXOs from V5: ${url}`);
116145
+ const response = await fetch(url);
116146
+ if (!response.ok) {
116147
+ console.error(`V5 UTXO fetch failed: ${response.status} ${response.statusText}`);
116148
+ return;
116149
+ }
116150
+ const data = await response.json();
116151
+ if (!Array.isArray(data)) {
116152
+ console.error(`V5 UTXO response was not an array: ${typeof data}`);
116153
+ return;
116154
+ }
116155
+ const utxos = [];
116156
+ for (const utxo of data) {
116157
+ if (!utxo.data.p2pkh) {
116158
+ continue;
116159
+ }
116160
+ const [txid, vout] = utxo.outpoint.split("_");
116161
+ if (!txid || !vout) {
116162
+ console.error(`Invalid outpoint: ${utxo.outpoint}`);
116163
+ continue;
116164
+ }
116165
+ utxos.push({
116166
+ txid,
116167
+ vout: Number.parseInt(vout, 10),
116168
+ satoshis: utxo.satoshis,
116169
+ script: toHex6(toArray10(utxo.script, "base64"))
116170
+ });
116171
+ }
116172
+ return utxos;
116173
+ } catch (error) {
116174
+ console.error("Error fetching payment UTXOs from V5:", error);
116175
+ return;
116176
+ }
116177
+ }
116178
+ var toHex6, toArray10;
116179
+ var init_fetchPaymentUtxos = __esm(() => {
116180
+ init_mod();
116181
+ init_backends();
116182
+ init_constants2();
116183
+ init_utxo();
116184
+ ({ toHex: toHex6, toArray: toArray10 } = exports_utils);
116185
+ });
116186
+
116406
116187
  // tools/bap/generate.ts
116407
116188
  async function generateBapKeys(args) {
116408
116189
  if (!process.env.BSV_MCP_PASSWORD || process.env.BSV_MCP_PASSWORD.length < 8)
@@ -116488,11 +116269,11 @@ async function generateBapKeys(args) {
116488
116269
  await keyManager.saveKeys(updatedKeys);
116489
116270
  console.error(`INFO: Identity saved encrypted to ${KEY_DIR}/keys.bep`);
116490
116271
  const idPayload = [
116491
- toArray12(BAP_PREFIX, "utf8"),
116492
- toArray12("ID"),
116493
- toArray12(generatedIdentityKey),
116494
- toArray12(bapId.rootAddress),
116495
- toArray12(bapId.rootAddress)
116272
+ toArray11(BAP_PREFIX, "utf8"),
116273
+ toArray11("ID"),
116274
+ toArray11(generatedIdentityKey),
116275
+ toArray11(bapId.rootAddress),
116276
+ toArray11(bapId.rootAddress)
116496
116277
  ];
116497
116278
  const { signedData: signedIdPayload } = await signOpReturnWithAIP(idPayload, identityKey, bapId.rootAddress);
116498
116279
  const idScript = buildOpReturnScript(signedIdPayload);
@@ -116504,10 +116285,10 @@ async function generateBapKeys(args) {
116504
116285
  url: `bitcoin:${paymentAddress}`
116505
116286
  };
116506
116287
  const aliasPayload = [
116507
- toArray12(BAP_PREFIX, "utf8"),
116508
- toArray12("ALIAS"),
116509
- toArray12(generatedIdentityKey),
116510
- toArray12(JSON.stringify(aliasData))
116288
+ toArray11(BAP_PREFIX, "utf8"),
116289
+ toArray11("ALIAS"),
116290
+ toArray11(generatedIdentityKey),
116291
+ toArray11(JSON.stringify(aliasData))
116511
116292
  ];
116512
116293
  const { signedData: signedAliasPayload } = await signOpReturnWithAIP(aliasPayload, identityKey, bapId.rootAddress);
116513
116294
  const aliasScript = buildOpReturnScript(signedAliasPayload);
@@ -116640,7 +116421,7 @@ function registerBapGenerateTool(server, config) {
116640
116421
  }
116641
116422
  });
116642
116423
  }
116643
- var toArray12, KEY_DIR, bapGenerateArgsSchema;
116424
+ var toArray11, KEY_DIR, bapGenerateArgsSchema;
116644
116425
  var init_generate = __esm(() => {
116645
116426
  init_dist7();
116646
116427
  init_mod();
@@ -116653,7 +116434,7 @@ var init_generate = __esm(() => {
116653
116434
  init_aip();
116654
116435
  init_transactionBuilder();
116655
116436
  init_fetchPaymentUtxos();
116656
- ({ toArray: toArray12 } = exports_utils);
116437
+ ({ toArray: toArray11 } = exports_utils);
116657
116438
  KEY_DIR = accountDir();
116658
116439
  bapGenerateArgsSchema = object2({
116659
116440
  alternateName: string2().optional().describe("Alternate name for the BAP identity profile"),
@@ -116834,7 +116615,6 @@ function registerBapTools(server, config) {
116834
116615
  identityPk,
116835
116616
  masterXprv,
116836
116617
  localAccountAvailable,
116837
- wallet,
116838
116618
  disableBroadcasting = false
116839
116619
  } = config || {};
116840
116620
  const envIdentityKeyWif = process.env.IDENTITY_KEY_WIF;
@@ -116857,24 +116637,9 @@ function registerBapTools(server, config) {
116857
116637
  logFunc("INFO: BAP tools requiring established identity not registered (no identityPk or IDENTITY_KEY_WIF).");
116858
116638
  }
116859
116639
  registerBapGetIdTool(server, identityPk);
116860
- if (masterXprv) {
116861
- try {
116862
- if (wallet) {
116863
- logFunc("INFO: Registering bap_friend tool (requires wallet & masterXprv).");
116864
- registerBapFriendTool(server, wallet, masterXprv, {
116865
- disableBroadcasting
116866
- });
116867
- } else {
116868
- logFunc("WARN: Wallet not available, bap_friend tool not registered.");
116869
- }
116870
- } catch (e) {
116871
- console.error(`ERROR: Failed during masterXprv tool registration: ${e instanceof Error ? e.message : String(e)}`);
116872
- }
116873
- }
116874
116640
  }
116875
116641
  var logFunc;
116876
116642
  var init_bap3 = __esm(() => {
116877
- init_friend();
116878
116643
  init_generate();
116879
116644
  init_getCurrentAddress();
116880
116645
  init_getId();
@@ -116941,626 +116706,528 @@ var init_context = __esm(() => {
116941
116706
  init_zod();
116942
116707
  });
116943
116708
 
116944
- // tools/bsocial/bmapFollow.ts
116945
- async function readBmapFollows(args) {
116946
- try {
116947
- const { bapId, type, limit, page } = args;
116948
- const params = new URLSearchParams;
116949
- params.append("limit", limit.toString());
116950
- params.append("page", page.toString());
116951
- const endpoint = type === "followers" ? "followers" : "following";
116952
- const response = await fetch(`${BMAP_URL}/bap/${bapId}/${endpoint}?${params}`, {
116953
- method: "GET",
116954
- headers: {
116955
- "Content-Type": "application/json"
116956
- }
116957
- });
116958
- if (!response.ok) {
116959
- const errorText = await response.text();
116960
- return {
116961
- success: false,
116962
- error: `BMAP API request failed: ${response.status} ${errorText}`
116963
- };
116964
- }
116965
- const data = await response.json();
116966
- return {
116967
- success: true,
116968
- data
116969
- };
116970
- } catch (error) {
116971
- const errorMessage = error instanceof Error ? error.message : String(error);
116972
- console.error("Error reading BMAP follows:", errorMessage);
116973
- return {
116974
- success: false,
116975
- error: errorMessage
116976
- };
116977
- }
116978
- }
116979
- function registerBmapReadFollowsTool(server) {
116980
- server.registerTool("bmap_readFollows", {
116981
- description: "Read follow relationships from the BMAP API. Shows who a user is following or who follows them.",
116982
- inputSchema: bmapReadFollowsArgsSchema
116983
- }, async ({ bapId, type, limit, page }) => {
116984
- try {
116985
- const result = await readBmapFollows({ bapId, type, limit, page });
116986
- if (result.success) {
116987
- return {
116988
- content: [
116989
- {
116990
- type: "text",
116991
- text: JSON.stringify(result.data, null, 2)
116992
- }
116993
- ],
116994
- isError: false
116995
- };
116996
- }
116997
- return {
116998
- content: [
116999
- {
117000
- type: "text",
117001
- text: result.error || "Unknown error occurred"
117002
- }
117003
- ],
117004
- isError: true
117005
- };
117006
- } catch (error) {
117007
- const msg = error instanceof Error ? error.message : String(error);
117008
- return {
117009
- content: [{ type: "text", text: `Error: ${msg}` }],
117010
- isError: true
117011
- };
117012
- }
117013
- });
116709
+ // tools/bsocial/schema.ts
116710
+ function contentFields(input) {
116711
+ let bytes;
116712
+ if (input.encoding === "base64") {
116713
+ const decoded = Buffer.from(input.content, "base64");
116714
+ if (decoded.toString("base64") !== input.content)
116715
+ throw new Error("Content must be canonical base64");
116716
+ bytes = Array.from(decoded);
116717
+ } else
116718
+ bytes = toArray2(input.content, "utf8");
116719
+ return [
116720
+ toArray2(B_PREFIX),
116721
+ bytes,
116722
+ toArray2(input.contentType),
116723
+ toArray2(input.encoding === "base64" ? "binary" : "utf-8"),
116724
+ toArray2(input.filename ?? "")
116725
+ ];
117014
116726
  }
117015
- var bmapReadFollowsArgsSchema;
117016
- var init_bmapFollow = __esm(() => {
116727
+ function socialOutputs(input) {
116728
+ const action = socialActionSchema.parse(input);
116729
+ const map = [
116730
+ MAP_PREFIX2,
116731
+ "SET",
116732
+ "app",
116733
+ action.app,
116734
+ "type",
116735
+ action.type
116736
+ ];
116737
+ if ("txid" in action)
116738
+ map.push("tx", action.txid);
116739
+ if ("bapId" in action)
116740
+ map.push("bapID", action.bapId);
116741
+ if (action.type === "friend")
116742
+ map.push("publicKey", action.publicKey);
116743
+ if ("emoji" in action && action.emoji)
116744
+ map.push("emoji", action.emoji);
116745
+ if (action.type === "post" && action.replyTo)
116746
+ map.push("context", "tx", "tx", action.replyTo);
116747
+ if ("context" in action && action.context)
116748
+ map.push("context", action.context.key, action.context.key, action.context.value);
116749
+ if ("subcontext" in action && action.subcontext)
116750
+ map.push("subcontext", action.subcontext.key, action.subcontext.key, action.subcontext.value);
116751
+ if (action.type === "video") {
116752
+ map.push("context", "videoID", "videoID", action.videoID, "subcontext", "provider", "provider", action.provider);
116753
+ if (action.channel)
116754
+ map.push("channel", action.channel);
116755
+ if (action.duration !== undefined)
116756
+ map.push("duration", String(action.duration));
116757
+ if (action.start !== undefined)
116758
+ map.push("start", String(action.start));
116759
+ }
116760
+ const primary = map.map((field) => toArray2(field, "utf8"));
116761
+ if ("content" in action)
116762
+ primary.unshift(...contentFields(action), toArray2("|"));
116763
+ const outputs = [primary];
116764
+ if ("tags" in action && action.tags?.length)
116765
+ outputs.push([MAP_PREFIX2, "ADD", "tags", ...new Set(action.tags)].map((field) => toArray2(field, "utf8")));
116766
+ if ("attachments" in action)
116767
+ for (const attachment of action.attachments ?? [])
116768
+ outputs.push(contentFields(attachment));
116769
+ const scripts = outputs.map((fields) => buildOpReturnScript(fields));
116770
+ if (scripts.reduce((size, script) => size + script.toBinary().length, 0) > 300000)
116771
+ throw new Error("Social content and attachments exceed 300 KB total");
116772
+ return { action, outputs, scripts };
116773
+ }
116774
+ var txidSchema, bapIdSchema, contextKey, context, contexts, content, contentSchema, supplements, common, socialActionSchema;
116775
+ var init_schema = __esm(() => {
116776
+ init_mod();
117017
116777
  init_zod();
117018
116778
  init_constants2();
117019
- bmapReadFollowsArgsSchema = object2({
117020
- bapId: string2().describe("BAP identity key to get follow relationships for"),
117021
- type: _enum(["followers", "following"]).default("following").describe("Type of relationship to query"),
117022
- limit: number2().min(1).max(100).default(20).describe("Maximum number of follows to return"),
117023
- page: number2().min(1).default(1).describe("Page number for pagination (1-based)")
117024
- });
117025
- });
117026
-
117027
- // tools/bsocial/bmapLikes.ts
117028
- async function readBmapLikes(args) {
117029
- try {
117030
- const { txid, limit, page } = args;
117031
- const params = new URLSearchParams;
117032
- params.append("limit", limit.toString());
117033
- params.append("page", page.toString());
117034
- const response = await fetch(`${BMAP_URL}/post/${txid}/like?${params}`, {
117035
- method: "GET",
117036
- headers: {
117037
- "Content-Type": "application/json"
117038
- }
117039
- });
117040
- if (!response.ok) {
117041
- const errorText = await response.text();
117042
- return {
117043
- success: false,
117044
- error: `BMAP API request failed: ${response.status} ${errorText}`
117045
- };
117046
- }
117047
- const data = await response.json();
117048
- return {
117049
- success: true,
117050
- data
117051
- };
117052
- } catch (error) {
117053
- const errorMessage = error instanceof Error ? error.message : String(error);
117054
- console.error("Error reading BMAP likes:", errorMessage);
117055
- return {
117056
- success: false,
117057
- error: errorMessage
117058
- };
117059
- }
117060
- }
117061
- function registerBmapReadLikesTool(server) {
117062
- server.registerTool("bmap_readLikes", {
117063
- description: "Read likes and reactions for a specific post from the BMAP API. Shows who liked the post and what emoji reactions were used.",
117064
- inputSchema: bmapReadLikesArgsSchema
117065
- }, async ({ txid, limit, page }) => {
117066
- try {
117067
- const result = await readBmapLikes({ txid, limit, page });
117068
- if (result.success) {
117069
- return {
117070
- content: [
117071
- {
117072
- type: "text",
117073
- text: JSON.stringify(result.data, null, 2)
117074
- }
117075
- ],
117076
- isError: false
117077
- };
116779
+ init_transactionBuilder();
116780
+ txidSchema = string2().regex(/^[a-f0-9]{64}$/i);
116781
+ bapIdSchema = string2().min(1).max(128).regex(/^[a-zA-Z0-9]+$/);
116782
+ contextKey = string2().min(1).max(64).regex(/^[a-zA-Z][a-zA-Z0-9_.-]*$/).refine((key) => ![
116783
+ "app",
116784
+ "type",
116785
+ "context",
116786
+ "subcontext",
116787
+ "publicKey",
116788
+ "__proto__",
116789
+ "constructor",
116790
+ "prototype"
116791
+ ].includes(key), "Reserved context key");
116792
+ context = strictObject({
116793
+ key: contextKey,
116794
+ value: string2().min(1).max(2048)
116795
+ });
116796
+ contexts = {
116797
+ context: context.optional(),
116798
+ subcontext: context.optional()
116799
+ };
116800
+ content = {
116801
+ content: string2().min(1).max(400000),
116802
+ contentType: string2().max(128).regex(/^[\w.+-]+\/[\w.+-]+(?:;[^\r\n]*)?$/).default("text/plain"),
116803
+ encoding: _enum(["utf8", "base64"]).default("utf8").describe("Input encoding. Base64 is decoded to binary B content."),
116804
+ filename: string2().max(255).optional()
116805
+ };
116806
+ contentSchema = strictObject(content);
116807
+ supplements = {
116808
+ tags: array(string2().min(1).max(100)).max(50).optional(),
116809
+ attachments: array(contentSchema).max(8).optional()
116810
+ };
116811
+ common = { app: string2().min(1).max(100).default("bsv-mcp") };
116812
+ socialActionSchema = discriminatedUnion("type", [
116813
+ strictObject({
116814
+ type: literal("post"),
116815
+ ...common,
116816
+ ...content,
116817
+ ...contexts,
116818
+ ...supplements,
116819
+ replyTo: txidSchema.optional()
116820
+ }),
116821
+ strictObject({
116822
+ type: literal("repost"),
116823
+ ...common,
116824
+ txid: txidSchema,
116825
+ ...contexts
116826
+ }),
116827
+ strictObject({
116828
+ type: _enum(["like", "unlike"]),
116829
+ ...common,
116830
+ txid: txidSchema,
116831
+ emoji: string2().min(1).max(32).optional()
116832
+ }),
116833
+ strictObject({
116834
+ type: _enum(["follow", "unfollow", "unfriend"]),
116835
+ ...common,
116836
+ bapId: bapIdSchema
116837
+ }),
116838
+ strictObject({
116839
+ type: literal("friend"),
116840
+ ...common,
116841
+ bapId: bapIdSchema,
116842
+ publicKey: string2().regex(/^(02|03)[a-f0-9]{64}$/i).refine((key) => {
116843
+ try {
116844
+ return PublicKey.fromString(key).validate();
116845
+ } catch {
116846
+ return false;
116847
+ }
116848
+ }, "Invalid public key").describe("Your communication public key, from the existing wallet/key-agreement workflow. This record does not establish encryption by itself.")
116849
+ }),
116850
+ strictObject({
116851
+ type: literal("message"),
116852
+ ...common,
116853
+ ...content,
116854
+ ...contexts,
116855
+ ...supplements
116856
+ }),
116857
+ strictObject({
116858
+ type: literal("video"),
116859
+ ...common,
116860
+ provider: string2().min(1).max(100),
116861
+ videoID: string2().min(1).max(512),
116862
+ channel: string2().min(1).max(256).optional(),
116863
+ duration: number2().nonnegative().optional(),
116864
+ start: number2().nonnegative().optional()
116865
+ })
116866
+ ]).superRefine((action, ctx) => {
116867
+ if ("subcontext" in action && action.subcontext && !action.context)
116868
+ ctx.addIssue({
116869
+ code: "custom",
116870
+ message: "subcontext requires context",
116871
+ path: ["subcontext"]
116872
+ });
116873
+ if ("context" in action && action.context) {
116874
+ if ("subcontext" in action && action.subcontext?.key === action.context.key)
116875
+ ctx.addIssue({
116876
+ code: "custom",
116877
+ message: "context and subcontext must use different keys"
116878
+ });
116879
+ for (const item of [action.context, action.subcontext]) {
116880
+ if (item?.key === "tx" && (!txidSchema.safeParse(item.value).success || action.type === "repost" && item.value !== action.txid))
116881
+ ctx.addIssue({
116882
+ code: "custom",
116883
+ message: "tx context requires a valid transaction ID matching any repost target"
116884
+ });
117078
116885
  }
117079
- return {
117080
- content: [
117081
- {
117082
- type: "text",
117083
- text: result.error || "Unknown error occurred"
117084
- }
117085
- ],
117086
- isError: true
117087
- };
117088
- } catch (error) {
117089
- const msg = error instanceof Error ? error.message : String(error);
117090
- return {
117091
- content: [{ type: "text", text: `Error: ${msg}` }],
117092
- isError: true
117093
- };
117094
116886
  }
117095
- });
117096
- }
117097
- var bmapReadLikesArgsSchema;
117098
- var init_bmapLikes = __esm(() => {
117099
- init_zod();
117100
- init_constants2();
117101
- bmapReadLikesArgsSchema = object2({
117102
- txid: string2().describe("Transaction ID of the post to get likes for"),
117103
- limit: number2().min(1).max(100).default(20).describe("Maximum number of likes to return"),
117104
- page: number2().min(1).default(1).describe("Page number for pagination (1-based)")
116887
+ if (action.type === "post" && action.replyTo && (action.context || action.subcontext))
116888
+ ctx.addIssue({
116889
+ code: "custom",
116890
+ message: "Use replyTo or explicit context, not both"
116891
+ });
117105
116892
  });
117106
116893
  });
117107
116894
 
117108
- // tools/bsocial/bmapReadPosts.ts
117109
- async function readBmapPosts(args) {
117110
- try {
117111
- const { bapId, txid, limit, page, feed, address } = args;
117112
- if (txid) {
117113
- const response = await fetch(`${BMAP_URL}/post/${txid}`, {
117114
- method: "GET",
117115
- headers: {
117116
- "Content-Type": "application/json"
117117
- }
117118
- });
117119
- if (!response.ok) {
117120
- const errorText = await response.text();
117121
- return {
117122
- success: false,
117123
- error: `BMAP API request failed: ${response.status} ${errorText}`
117124
- };
117125
- }
117126
- const data = await response.json();
117127
- return {
117128
- success: true,
117129
- data
117130
- };
117131
- }
117132
- const params = new URLSearchParams;
117133
- if (bapId)
117134
- params.append("bapId", bapId);
117135
- if (address)
117136
- params.append("address", address);
117137
- params.append("limit", limit.toString());
117138
- params.append("page", page.toString());
117139
- if (feed)
117140
- params.append("feed", "true");
117141
- const response = await fetch(`${BMAP_URL}/posts?${params}`, {
117142
- method: "GET",
117143
- headers: {
117144
- "Content-Type": "application/json"
117145
- }
117146
- });
117147
- if (!response.ok) {
117148
- const errorText = await response.text();
117149
- return {
117150
- success: false,
117151
- error: `BMAP API request failed: ${response.status} ${errorText}`
117152
- };
117153
- }
117154
- const data = await response.json();
116895
+ // tools/bsocial/publish.ts
116896
+ async function publishSocial(input, config) {
116897
+ const { action, preview } = socialPublishSchema.parse(input);
116898
+ if (!preview)
116899
+ assertBroadcastAllowed("bsocial_publish", config.disableBroadcasting);
116900
+ const { scripts, outputs } = socialOutputs(action);
116901
+ if (preview)
117155
116902
  return {
117156
- success: true,
117157
- data
117158
- };
117159
- } catch (error) {
117160
- const errorMessage = error instanceof Error ? error.message : String(error);
117161
- console.error("Error reading BMAP posts:", errorMessage);
117162
- return {
117163
- success: false,
117164
- error: errorMessage
116903
+ preview: true,
116904
+ type: action.type,
116905
+ outputs: scripts.map((script) => ({
116906
+ lockingScript: script.toHex(),
116907
+ satoshis: 0
116908
+ })),
116909
+ notice: "Unsigned public on-chain data. No transaction has been funded or broadcast."
117165
116910
  };
116911
+ if (config.identityContext) {
116912
+ const ctx = config.identityContext;
116913
+ const keyID = await resolveCurrentKeyId(ctx);
116914
+ const signed = [];
116915
+ for (const script of scripts)
116916
+ signed.push(await applyBapAip(ctx, script, keyID));
116917
+ const result = await executeTrackedAction(ctx.wallet, {
116918
+ description: `BSocial ${action.type}`,
116919
+ outputs: signed.map((script, index) => ({
116920
+ lockingScript: script.toHex(),
116921
+ satoshis: 0,
116922
+ outputDescription: index === 0 ? `BSocial ${action.type}` : "BSocial supplement",
116923
+ basket: "bsocial",
116924
+ tags: [`app:${action.app}`, `type:${action.type}`]
116925
+ })),
116926
+ options: { acceptDelayedBroadcast: false, randomizeOutputs: false }
116927
+ });
116928
+ if (result.error)
116929
+ throw new Error(result.error);
116930
+ if (!result.txid)
116931
+ throw new Error("Wallet did not return a transaction ID; inspect wallet activity before retrying");
116932
+ return { type: action.type, txid: result.txid, outputCount: signed.length };
117166
116933
  }
117167
- }
117168
- function registerBmapReadPostsTool(server) {
117169
- server.registerTool("bmap_readPosts", {
117170
- description: "Read social posts from the BMAP API (query layer). Can fetch posts by author (BAP ID), specific post by transaction ID, or recent posts from all users. Supports pagination and feed functionality.",
117171
- inputSchema: bmapReadPostsArgsSchema
117172
- }, async ({
117173
- bapId,
117174
- txid,
117175
- limit,
117176
- page,
117177
- feed,
117178
- address
117179
- }) => {
117180
- try {
117181
- const result = await readBmapPosts({
117182
- bapId,
117183
- txid,
117184
- limit,
117185
- page,
117186
- feed,
117187
- address
117188
- });
117189
- if (result.success) {
117190
- return {
117191
- content: [
117192
- {
117193
- type: "text",
117194
- text: JSON.stringify(result.data, null, 2)
117195
- }
117196
- ],
117197
- isError: false
117198
- };
117199
- }
117200
- return {
117201
- content: [
117202
- {
117203
- type: "text",
117204
- text: result.error || "Unknown error occurred"
117205
- }
117206
- ],
117207
- isError: true
117208
- };
117209
- } catch (error) {
117210
- const msg = error instanceof Error ? error.message : String(error);
117211
- return {
117212
- content: [{ type: "text", text: `Error: ${msg}` }],
117213
- isError: true
117214
- };
117215
- }
116934
+ const wallet = config.wallet;
116935
+ const identityKey = config.identityKey ?? wallet?.getIdentityKey();
116936
+ if (!wallet || !identityKey)
116937
+ throw new Error("Social publishing requires an identity wallet or explicit legacy identity key. A payment key is not an author identity.");
116938
+ const paymentKey = wallet.getPaymentKey();
116939
+ if (!paymentKey)
116940
+ throw new Error("Payment key is unavailable for transaction fees");
116941
+ const signed = [];
116942
+ for (const fields of outputs) {
116943
+ const { signedData } = await signOpReturnWithAIP(fields, identityKey, identityKey.toAddress());
116944
+ signed.push(buildOpReturnScript(signedData));
116945
+ }
116946
+ const { paymentUtxos } = await wallet.getUtxos();
116947
+ const result = await buildAndSendTransaction({
116948
+ outputs: signed.map((script) => ({ script, satoshis: 0 })),
116949
+ utxos: paymentUtxos,
116950
+ changeAddress: paymentKey.toAddress(),
116951
+ paymentKey
117216
116952
  });
116953
+ if (!result.success)
116954
+ throw new Error(result.error ?? "Social transaction failed");
116955
+ return { type: action.type, txid: result.txid, outputCount: signed.length };
117217
116956
  }
117218
- var bmapReadPostsArgsSchema;
117219
- var init_bmapReadPosts = __esm(() => {
117220
- init_zod();
117221
- init_constants2();
117222
- bmapReadPostsArgsSchema = object2({
117223
- bapId: string2().optional().describe("BAP identity key to filter posts by author"),
117224
- txid: string2().optional().describe("Specific transaction ID to fetch"),
117225
- limit: number2().min(1).max(100).default(20).describe("Maximum number of posts to return"),
117226
- page: number2().min(1).default(1).describe("Page number for pagination (1-based)"),
117227
- feed: boolean2().default(false).describe("Whether to fetch feed (posts from followed users)"),
117228
- address: string2().optional().describe("Bitcoin address to filter posts by")
117229
- });
117230
- });
117231
-
117232
- // tools/bsocial/context.ts
117233
- function registerContextSocialPost(server, ctx, disableBroadcasting = false) {
117234
- server.registerTool("bsocial_createPost", {
117235
- description: "Publish a BSocial post with an AIP signature from the selected BAP identity wallet. Requires a published identity. The identity wallet funds the transaction; content becomes public on chain.",
117236
- inputSchema: strictObject({
117237
- content: string2().min(1).max(1e5),
117238
- contentType: _enum(["text/plain", "text/markdown"]).default("text/plain"),
117239
- app: string2().min(1).max(100).default("bsv-mcp"),
117240
- tags: array(string2().max(100)).max(50).optional()
117241
- }),
116957
+ function registerSocialPublishTool(server, config) {
116958
+ registerTool(server, {
116959
+ name: "bsocial_publish",
116960
+ schema: socialPublishSchema,
116961
+ description: "Publish a signed Bitcoin Schema social action: post/reply, repost, like/unlike, follow/unfollow, friend/unfriend, message, or video. Posts/messages support context, tags and attachments. Content is public and permanent; recipient context does NOT encrypt a message. Friend records require your communication public key from an established key-agreement workflow. Requires the selected BAP identity wallet or explicit legacy identity key and funding. Use preview to inspect unsigned outputs without spending.",
117242
116962
  annotations: {
117243
116963
  readOnlyHint: false,
117244
116964
  destructiveHint: true,
117245
116965
  idempotentHint: false,
117246
116966
  openWorldHint: true
117247
- }
117248
- }, async (input) => {
117249
- try {
117250
- assertBroadcastAllowed("bsocial_createPost", disableBroadcasting);
117251
- const result = await createSocialPost.execute(ctx, input);
116967
+ },
116968
+ handler: async (input) => {
116969
+ const result = await publishSocial(input, config);
117252
116970
  return {
117253
116971
  content: [{ type: "text", text: JSON.stringify(result) }],
117254
- ...result.error ? { isError: true } : {}
117255
- };
117256
- } catch (error) {
117257
- return {
117258
- content: [
117259
- {
117260
- type: "text",
117261
- text: error instanceof Error ? error.message : String(error)
117262
- }
117263
- ],
117264
- isError: true
116972
+ structuredContent: result
117265
116973
  };
117266
116974
  }
117267
116975
  });
117268
116976
  }
117269
- var init_context2 = __esm(() => {
116977
+ var socialPublishSchema;
116978
+ var init_publish = __esm(() => {
117270
116979
  init_dist7();
117271
116980
  init_zod();
117272
- });
117273
-
117274
- // tools/bsocial/createPost.ts
117275
- async function createSocialPost2(args, wallet) {
117276
- try {
117277
- const { content, contentType, app, additionalMapData } = args;
117278
- const paymentKey = wallet.getPaymentKey();
117279
- if (!paymentKey) {
117280
- return {
117281
- success: false,
117282
- error: "Payment key not available in wallet"
117283
- };
117284
- }
117285
- const address = paymentKey.toAddress();
117286
- const fileExtension = contentType === "text/markdown" ? "md" : "txt";
117287
- const fileName = `post.${fileExtension}`;
117288
- const bData = [
117289
- toArray13(B_PREFIX, "utf8"),
117290
- toArray13(content, "utf8"),
117291
- toArray13(contentType, "utf8"),
117292
- toArray13("utf-8", "utf8"),
117293
- toArray13(fileName, "utf8")
117294
- ];
117295
- const mapData = [
117296
- toArray13(MAP_PREFIX2, "utf8"),
117297
- toArray13("SET", "utf8"),
117298
- toArray13("app", "utf8"),
117299
- toArray13(app, "utf8"),
117300
- toArray13("type", "utf8"),
117301
- toArray13("post", "utf8")
117302
- ];
117303
- if (additionalMapData) {
117304
- const parsedMapData = JSON.parse(additionalMapData);
117305
- for (const [key, value] of Object.entries(parsedMapData)) {
117306
- mapData.push(toArray13(key, "utf8"), toArray13(value, "utf8"));
117307
- }
117308
- }
117309
- const pipeData = toArray13("|", "utf8");
117310
- const dataToSign = [...bData, pipeData, ...mapData];
117311
- const { signedData } = await signOpReturnWithAIP(dataToSign, paymentKey, address);
117312
- const script = buildOpReturnScript(signedData);
117313
- const { paymentUtxos } = await wallet.getUtxos();
117314
- return await buildAndSendTransaction({
117315
- outputs: [{ script, satoshis: 0 }],
117316
- utxos: paymentUtxos,
117317
- changeAddress: address,
117318
- paymentKey
117319
- });
117320
- } catch (error) {
117321
- console.error("Error creating social post:", formatError2(error));
117322
- return {
117323
- success: false,
117324
- error: formatError2(error)
117325
- };
117326
- }
117327
- }
117328
- function registerCreatePostTool(server, wallet) {
117329
- server.registerTool("bsocial_createPost", {
117330
- description: "Create a social post on the BSV blockchain using B:// and MAP protocols. Posts are stored permanently on-chain and can include plain text or markdown content.",
117331
- inputSchema: createPostArgsSchema
117332
- }, async ({
117333
- content,
117334
- contentType,
117335
- app,
117336
- additionalMapData
117337
- }) => {
117338
- const result = await createSocialPost2({ content, contentType, app, additionalMapData }, wallet);
117339
- return createResponse(result);
117340
- });
117341
- }
117342
- var toArray13, createPostArgsSchema;
117343
- var init_createPost = __esm(() => {
117344
- init_mod();
117345
- init_zod();
117346
- init_constants2();
117347
116981
  init_aip();
117348
116982
  init_transactionBuilder();
117349
- ({ toArray: toArray13 } = exports_utils);
117350
- createPostArgsSchema = object2({
117351
- content: string2().describe("The content of the post"),
117352
- contentType: _enum(["text/plain", "text/markdown"]).default("text/plain").describe("Content type of the post"),
117353
- app: string2().default("bsv-mcp").describe("Application name creating the post"),
117354
- additionalMapData: string2().optional().describe(`Additional MAP protocol key-value pairs as a JSON object string, e.g. '{"key": "value"}'`)
116983
+ init_schema();
116984
+ socialPublishSchema = strictObject({
116985
+ action: socialActionSchema,
116986
+ preview: boolean2().default(false).describe("Return unsigned output scripts without signing, funding, or broadcasting.")
117355
116987
  });
117356
116988
  });
117357
116989
 
117358
- // tools/bsocial/readPosts.ts
117359
- async function readSocialPosts(args) {
116990
+ // tools/bsocial/read.ts
116991
+ async function request(path, params) {
116992
+ const root = BMAP_URL.replace(/\/$/, "");
116993
+ const url = `${root}${path}${params ? `?${new URLSearchParams(params)}` : ""}`;
116994
+ const response = await fetch(url, {
116995
+ headers: { Accept: "application/json" },
116996
+ signal: AbortSignal.timeout(15000)
116997
+ });
116998
+ if (!response.ok)
116999
+ throw new Error(`Social indexer returned HTTP ${response.status}. Check PUBLIC_BMAP_URL (BMAP server root); expected /social and /q routes.`);
117000
+ if (!response.body)
117001
+ throw new Error("Social indexer returned an empty response");
117002
+ const reader = response.body.getReader();
117003
+ const chunks = [];
117004
+ let size = 0;
117360
117005
  try {
117361
- const { bapId, txid, limit, page, feed } = args;
117362
- if (txid) {
117363
- const response = await fetch(`${BMAP_URL}/post/${txid}`, {
117364
- method: "GET",
117365
- headers: {
117366
- "Content-Type": "application/json"
117367
- }
117368
- });
117369
- if (!response.ok) {
117370
- const errorText = await response.text();
117371
- return {
117372
- success: false,
117373
- error: `BMAP API request failed: ${response.status} ${errorText}`
117374
- };
117375
- }
117376
- const data = await response.json();
117377
- if (data.status !== "success") {
117378
- return {
117379
- success: false,
117380
- error: data.error || "Unknown API error"
117381
- };
117382
- }
117383
- return {
117384
- success: true,
117385
- posts: [data.data.post],
117386
- signers: data.data.signers,
117387
- meta: [data.data.meta]
117388
- };
117389
- }
117390
- const params = new URLSearchParams;
117391
- if (bapId)
117392
- params.append("bapId", bapId);
117393
- params.append("limit", limit.toString());
117394
- params.append("page", page.toString());
117395
- if (feed)
117396
- params.append("feed", "true");
117397
- const response = await fetch(`${BMAP_URL}/posts?${params}`, {
117398
- method: "GET",
117399
- headers: {
117400
- "Content-Type": "application/json"
117401
- }
117402
- });
117403
- if (!response.ok) {
117404
- const errorText = await response.text();
117405
- return {
117406
- success: false,
117407
- error: `BMAP API request failed: ${response.status} ${errorText}`
117408
- };
117409
- }
117410
- const data = await response.json();
117411
- if (data.status !== "success") {
117412
- return {
117413
- success: false,
117414
- error: data.error || "Unknown API error"
117415
- };
117006
+ while (true) {
117007
+ const { done, value } = await reader.read();
117008
+ if (done)
117009
+ break;
117010
+ size += value.byteLength;
117011
+ if (size > 4 * 1024 * 1024)
117012
+ throw new Error("Social indexer response exceeds 4 MB; reduce the query limit");
117013
+ chunks.push(value);
117416
117014
  }
117417
- return {
117418
- success: true,
117419
- posts: data.data.results,
117420
- signers: data.data.signers,
117421
- meta: data.data.meta,
117422
- pagination: {
117423
- page: data.data.page,
117424
- limit: data.data.limit,
117425
- count: data.data.count
117426
- }
117427
- };
117428
- } catch (error) {
117429
- const errorMessage = error instanceof Error ? error.message : String(error);
117430
- console.error("Error reading social posts:", errorMessage);
117431
- return {
117432
- success: false,
117433
- error: errorMessage
117434
- };
117015
+ } finally {
117016
+ await reader.cancel();
117017
+ }
117018
+ const data = JSON.parse(Buffer.concat(chunks).toString("utf8"));
117019
+ if (data === null || typeof data !== "object")
117020
+ throw new Error("Social indexer returned invalid JSON data");
117021
+ if (data && typeof data === "object" && (("error" in data) && data.error || ("success" in data) && data.success === false || ("status" in data) && data.status === "error" || ("status" in data) && data.status === "failed" || ("code" in data) && data.code === "INTERNAL_SERVER_ERROR"))
117022
+ throw new Error("Social indexer reported an error");
117023
+ return "status" in data && data.status === "success" && "data" in data ? data.data : data;
117024
+ }
117025
+ async function readSocial(input) {
117026
+ const { query: q } = socialReadSchema.parse(input);
117027
+ const params = "page" in q ? { page: String(q.page), limit: String(q.limit) } : undefined;
117028
+ let path;
117029
+ let data;
117030
+ switch (q.type) {
117031
+ case "posts":
117032
+ path = q.address ? `/post/address/${segment(q.address)}` : q.bapId && !q.feed ? `/post/bap/${segment(q.bapId)}` : `/feed${q.bapId ? `/${segment(q.bapId)}` : ""}`;
117033
+ break;
117034
+ case "post":
117035
+ path = `/post/${q.txid}`;
117036
+ break;
117037
+ case "replies":
117038
+ path = `/post/${q.txid}/reply`;
117039
+ break;
117040
+ case "search":
117041
+ path = "/post/search";
117042
+ break;
117043
+ case "likes":
117044
+ path = q.txid ? `/post/${q.txid}/like` : `/bap/${segment(bapIdSchema.parse(q.bapId))}/like`;
117045
+ break;
117046
+ case "friends":
117047
+ path = `/friend/${segment(q.bapId)}`;
117048
+ break;
117049
+ case "channels":
117050
+ path = "/channels";
117051
+ break;
117052
+ case "messages":
117053
+ path = q.channel ? `/channels/${segment(q.channel)}/messages` : `/@/${segment(bapIdSchema.parse(q.bapId))}/messages${q.targetBapId ? `/${segment(q.targetBapId)}` : ""}`;
117054
+ break;
117055
+ case "videos":
117056
+ path = q.txid ? `/video/${q.txid}` : "/video";
117057
+ break;
117058
+ case "records":
117059
+ data = await readRecords(q);
117060
+ path = "";
117061
+ break;
117435
117062
  }
117436
- }
117437
- function formatPost(post, index, signer, meta) {
117438
- const lines = [
117439
- `Post ${index + 1}:`,
117440
- ` TX ID: ${post.tx.h}`,
117441
- ` Content: ${post.B[0]?.content || "[No Content]"}`,
117442
- ` Content Type: ${post.B[0]?.["content-type"] || "text/plain"}`,
117443
- ` Timestamp: ${new Date(post.timestamp * 1000).toISOString()}`
117063
+ if (path)
117064
+ data = await request(`/social${path}`, {
117065
+ ...q.type === "search" ? {
117066
+ q: q.q,
117067
+ limit: String(q.limit),
117068
+ offset: String((q.page - 1) * q.limit)
117069
+ } : params,
117070
+ ...q.type === "videos" && q.channel ? { channel: q.channel } : {}
117071
+ });
117072
+ return {
117073
+ source: BMAP_URL,
117074
+ operation: q.type,
117075
+ data,
117076
+ ...q.type === "records" ? {
117077
+ interpretation: "Raw indexed events; not current relationship state or independently verified authorship."
117078
+ } : {}
117079
+ };
117080
+ }
117081
+ async function readRecords(q) {
117082
+ const match = {};
117083
+ if (q.address)
117084
+ match["AIP.address"] = q.address;
117085
+ if (q.authorBapId) {
117086
+ const identity = await fetchProfile(q.authorBapId);
117087
+ const addresses = array(union([
117088
+ string2(),
117089
+ object2({ address: string2() }).transform((a) => a.address)
117090
+ ])).min(1).max(1000).parse(identity?.addresses);
117091
+ match["AIP.address"] = { $in: addresses };
117092
+ }
117093
+ if (q.targetBapId)
117094
+ match["MAP.bapID"] = q.targetBapId;
117095
+ if (q.txid)
117096
+ match["MAP.tx"] = q.txid;
117097
+ const [first, ...rest] = [...new Set(q.types)];
117098
+ const recent = [
117099
+ { $match: match },
117100
+ { $sort: { timestamp: -1 } },
117101
+ { $limit: q.page * q.limit },
117102
+ { $project: { in: 0, out: 0 } }
117444
117103
  ];
117445
- if (signer) {
117446
- lines.push(` Author: ${signer.displayName || signer.idKey}`);
117447
- if (signer.paymail) {
117448
- lines.push(` Paymail: ${signer.paymail}`);
117449
- }
117450
- }
117451
- const mapData = post.MAP.find((m) => m.type === "post");
117452
- if (mapData?.app) {
117453
- lines.push(` App: ${mapData.app}`);
117454
- }
117455
- if (meta) {
117456
- if (meta.likes > 0) {
117457
- lines.push(` Likes: ${meta.likes}`);
117458
- }
117459
- if (meta.replies > 0) {
117460
- lines.push(` Replies: ${meta.replies}`);
117461
- }
117462
- if (meta.reactions.length > 0) {
117463
- const reactions = meta.reactions.map((r) => `${r.emoji}(${r.count})`).join(" ");
117464
- lines.push(` Reactions: ${reactions}`);
117465
- }
117466
- }
117467
- return lines.join(`
117468
- `);
117104
+ const aggregate = [
117105
+ ...recent,
117106
+ ...rest.map((coll) => ({
117107
+ $unionWith: { coll, pipeline: recent }
117108
+ })),
117109
+ { $sort: { timestamp: -1 } },
117110
+ { $skip: (q.page - 1) * q.limit },
117111
+ { $limit: q.limit },
117112
+ { $project: { in: 0, out: 0 } }
117113
+ ];
117114
+ const encoded = segment(Buffer.from(JSON.stringify({ q: { aggregate } })).toString("base64"));
117115
+ return request(`/q/${first}/${encoded}`);
117469
117116
  }
117470
- function registerReadPostsTool(server) {
117471
- server.registerTool("bsocial_readPosts", {
117472
- description: "Read social posts from the BSV blockchain using BMAP API. Can fetch posts by author (BAP ID), specific post by transaction ID, or recent posts from all users. Supports pagination and feed functionality.",
117473
- inputSchema: readPostsArgsSchema
117474
- }, async ({ bapId, txid, limit, page, feed }) => {
117475
- try {
117476
- const result = await readSocialPosts({
117477
- bapId,
117478
- txid,
117479
- limit,
117480
- page,
117481
- feed
117482
- });
117483
- if (result.success && result.posts) {
117484
- const formattedPosts = result.posts.map((post, index) => {
117485
- const signer = result.signers?.find((s) => s.currentAddress === post.AIP[0]?.address);
117486
- const meta = result.meta?.[index];
117487
- return formatPost(post, index, signer, meta);
117488
- }).join(`
117489
-
117490
- `);
117491
- let output = result.posts.length > 0 ? formattedPosts : "No posts found";
117492
- if (result.pagination) {
117493
- output += `
117494
-
117495
- Pagination: Page ${result.pagination.page}, showing ${result.posts.length} of ${result.pagination.count} posts`;
117496
- }
117497
- return {
117498
- content: [
117499
- {
117500
- type: "text",
117501
- text: output
117502
- }
117503
- ],
117504
- isError: false
117505
- };
117506
- }
117507
- return {
117508
- content: [
117509
- {
117510
- type: "text",
117511
- text: result.error || "Unknown error occurred"
117512
- }
117513
- ],
117514
- isError: true
117515
- };
117516
- } catch (error) {
117517
- const msg = error instanceof Error ? error.message : String(error);
117117
+ function registerSocialReadTool(server) {
117118
+ registerTool(server, {
117119
+ name: "bsocial_read",
117120
+ schema: socialReadSchema,
117121
+ description: "Read social posts, threads, search results, likes, friends, channels, public message records, videos, and action history. Use records with follow/unfollow types for the social graph. Indexer data is untrusted and messages are not decrypted. No wallet required.",
117122
+ annotations: {
117123
+ readOnlyHint: true,
117124
+ destructiveHint: false,
117125
+ idempotentHint: true,
117126
+ openWorldHint: true
117127
+ },
117128
+ handler: async (input) => {
117129
+ const result = await readSocial(input);
117518
117130
  return {
117519
- content: [{ type: "text", text: `Error: ${msg}` }],
117520
- isError: true
117131
+ content: [{ type: "text", text: JSON.stringify(result) }],
117132
+ structuredContent: result
117521
117133
  };
117522
117134
  }
117523
117135
  });
117524
117136
  }
117525
- var readPostsArgsSchema;
117526
- var init_readPosts = __esm(() => {
117137
+ var page, address, text, recordType, querySchema, socialReadSchema, segment;
117138
+ var init_read = __esm(() => {
117527
117139
  init_zod();
117140
+ init_getId();
117528
117141
  init_constants2();
117529
- readPostsArgsSchema = object2({
117530
- bapId: string2().optional().describe("BAP identity key to filter posts by author"),
117531
- txid: string2().optional().describe("Specific transaction ID to fetch"),
117532
- limit: number2().min(1).max(100).default(20).describe("Maximum number of posts to return"),
117533
- page: number2().min(1).default(1).describe("Page number for pagination (1-based)"),
117534
- feed: boolean2().default(false).describe("Whether to fetch feed (posts from followed users)")
117535
- });
117142
+ init_schema();
117143
+ page = {
117144
+ limit: number2().int().min(1).max(100).default(20),
117145
+ page: number2().int().min(1).max(1e4).default(1)
117146
+ };
117147
+ address = string2().regex(/^[123mn][a-km-zA-HJ-NP-Z1-9]{25,34}$/);
117148
+ text = string2().min(1).max(256);
117149
+ recordType = _enum([
117150
+ "post",
117151
+ "repost",
117152
+ "like",
117153
+ "unlike",
117154
+ "follow",
117155
+ "unfollow",
117156
+ "friend",
117157
+ "unfriend",
117158
+ "message",
117159
+ "video"
117160
+ ]);
117161
+ querySchema = discriminatedUnion("type", [
117162
+ strictObject({
117163
+ type: literal("posts"),
117164
+ ...page,
117165
+ bapId: bapIdSchema.optional(),
117166
+ address: address.optional(),
117167
+ feed: boolean2().default(false)
117168
+ }),
117169
+ strictObject({
117170
+ type: _enum(["post", "replies"]),
117171
+ txid: txidSchema,
117172
+ ...page
117173
+ }),
117174
+ strictObject({ type: literal("search"), q: text, ...page }),
117175
+ strictObject({
117176
+ type: literal("likes"),
117177
+ txid: txidSchema.optional(),
117178
+ bapId: bapIdSchema.optional(),
117179
+ ...page
117180
+ }),
117181
+ strictObject({ type: literal("friends"), bapId: bapIdSchema }),
117182
+ strictObject({ type: literal("channels") }),
117183
+ strictObject({
117184
+ type: literal("messages"),
117185
+ channel: text.optional(),
117186
+ bapId: bapIdSchema.optional(),
117187
+ targetBapId: bapIdSchema.optional(),
117188
+ ...page
117189
+ }),
117190
+ strictObject({
117191
+ type: literal("records"),
117192
+ types: array(recordType).min(1).max(10),
117193
+ authorBapId: bapIdSchema.optional(),
117194
+ address: address.optional(),
117195
+ targetBapId: bapIdSchema.optional(),
117196
+ txid: txidSchema.optional(),
117197
+ ...page
117198
+ }).describe("Raw action history, including follow/unfollow and repost records. Filter authorBapId for outgoing follows or targetBapId for incoming follows. This is not a reduced current relationship state."),
117199
+ strictObject({
117200
+ type: literal("videos"),
117201
+ txid: txidSchema.optional(),
117202
+ channel: text.optional(),
117203
+ ...page
117204
+ })
117205
+ ]).superRefine((q, ctx) => {
117206
+ const invalid = (message) => ctx.addIssue({ code: "custom", message });
117207
+ if (q.type === "posts" && (q.bapId && q.address || q.feed && (!q.bapId || q.address)))
117208
+ invalid("Choose author bapId, address, or feed with bapId");
117209
+ if (q.type === "likes" && Boolean(q.txid) === Boolean(q.bapId))
117210
+ invalid("Provide exactly one of txid or bapId");
117211
+ if (q.type === "messages" && (Boolean(q.channel) === Boolean(q.bapId) || q.targetBapId && !q.bapId))
117212
+ invalid("Choose channel or bapId, optionally with targetBapId");
117213
+ if (q.type === "records" && q.authorBapId && q.address)
117214
+ invalid("Choose authorBapId or address");
117215
+ if (q.type === "videos" && q.txid && q.channel)
117216
+ invalid("Choose txid or channel");
117217
+ });
117218
+ socialReadSchema = strictObject({ query: querySchema });
117219
+ segment = encodeURIComponent;
117536
117220
  });
117537
117221
 
117538
117222
  // tools/bsocial/index.ts
117539
117223
  function registerBsocialTools(server, config = {}) {
117540
- registerReadPostsTool(server);
117541
- console.error("✅ Registered bsocial_readPosts tool");
117542
- registerBmapReadPostsTool(server);
117543
- console.error("✅ Registered bmap_readPosts tool");
117544
- registerBmapReadLikesTool(server);
117545
- console.error("✅ Registered bmap_readLikes tool");
117546
- registerBmapReadFollowsTool(server);
117547
- console.error("✅ Registered bmap_readFollows tool");
117548
- if (config.identityContext) {
117549
- registerContextSocialPost(server, config.identityContext, config.disableBroadcasting);
117550
- } else if (config.wallet) {
117551
- registerCreatePostTool(server, config.wallet);
117552
- console.error("✅ Registered bsocial_createPost tool");
117553
- } else {
117554
- console.error("⚠️ bsocial_createPost tool not registered (no wallet available)");
117555
- }
117224
+ registerSocialReadTool(server);
117225
+ if (config.identityContext || config.wallet)
117226
+ registerSocialPublishTool(server, config);
117556
117227
  }
117557
117228
  var init_bsocial2 = __esm(() => {
117558
- init_bmapFollow();
117559
- init_bmapLikes();
117560
- init_bmapReadPosts();
117561
- init_context2();
117562
- init_createPost();
117563
- init_readPosts();
117229
+ init_publish();
117230
+ init_read();
117564
117231
  });
117565
117232
 
117566
117233
  // utils/x402-auth.ts
@@ -120296,7 +119963,7 @@ class BaseHash2 {
120296
119963
  throw new Error("Not implemented");
120297
119964
  }
120298
119965
  update(msg, enc) {
120299
- msg = toArray14(msg, enc);
119966
+ msg = toArray12(msg, enc);
120300
119967
  if (this.pending == null) {
120301
119968
  this.pending = msg;
120302
119969
  } else {
@@ -120373,7 +120040,7 @@ function isSurrogatePair(msg, i) {
120373
120040
  }
120374
120041
  return (msg.charCodeAt(i + 1) & 64512) === 56320;
120375
120042
  }
120376
- function toArray14(msg, enc) {
120043
+ function toArray12(msg, enc) {
120377
120044
  if (Array.isArray(msg)) {
120378
120045
  return msg.slice();
120379
120046
  }
@@ -120587,7 +120254,7 @@ class SHA2562 {
120587
120254
  this.h = new FastSHA2562;
120588
120255
  }
120589
120256
  update(msg, enc) {
120590
- const data = msg instanceof Uint8Array ? msg : Uint8Array.from(toArray14(msg, enc));
120257
+ const data = msg instanceof Uint8Array ? msg : Uint8Array.from(toArray12(msg, enc));
120591
120258
  this.h.update(data);
120592
120259
  return this;
120593
120260
  }
@@ -120604,11 +120271,11 @@ class SHA256HMAC2 {
120604
120271
  blockSize = 64;
120605
120272
  outSize = 32;
120606
120273
  constructor(key) {
120607
- const k = key instanceof Uint8Array ? key : Uint8Array.from(toArray14(key, typeof key === "string" ? "hex" : undefined));
120274
+ const k = key instanceof Uint8Array ? key : Uint8Array.from(toArray12(key, typeof key === "string" ? "hex" : undefined));
120608
120275
  this.h = new HMAC2(sha256Fast2, k);
120609
120276
  }
120610
120277
  update(msg, enc) {
120611
- const data = msg instanceof Uint8Array ? msg : Uint8Array.from(toArray14(msg, enc));
120278
+ const data = msg instanceof Uint8Array ? msg : Uint8Array.from(toArray12(msg, enc));
120612
120279
  this.h.update(data);
120613
120280
  return this;
120614
120281
  }
@@ -120625,11 +120292,11 @@ class SHA512HMAC2 {
120625
120292
  blockSize = 128;
120626
120293
  outSize = 32;
120627
120294
  constructor(key) {
120628
- const k = key instanceof Uint8Array ? key : Uint8Array.from(toArray14(key, typeof key === "string" ? "hex" : undefined));
120295
+ const k = key instanceof Uint8Array ? key : Uint8Array.from(toArray12(key, typeof key === "string" ? "hex" : undefined));
120629
120296
  this.h = new HMAC2(sha512Fast2, k);
120630
120297
  }
120631
120298
  update(msg, enc) {
120632
- const data = msg instanceof Uint8Array ? msg : Uint8Array.from(toArray14(msg, enc));
120299
+ const data = msg instanceof Uint8Array ? msg : Uint8Array.from(toArray12(msg, enc));
120633
120300
  this.h.update(data);
120634
120301
  return this;
120635
120302
  }
@@ -122548,8 +122215,8 @@ var BufferCtor7, CAN_USE_BUFFER5, HEX_DIGITS3 = "0123456789abcdef", HEX_BYTE_STR
122548
122215
  }, toUint8Array2 = (msg, enc) => {
122549
122216
  if (msg instanceof Uint8Array)
122550
122217
  return msg;
122551
- return new Uint8Array(toArray15(msg, enc));
122552
- }, toArray15 = (msg, enc) => {
122218
+ return new Uint8Array(toArray13(msg, enc));
122219
+ }, toArray13 = (msg, enc) => {
122553
122220
  if (Array.isArray(msg))
122554
122221
  return msg.slice();
122555
122222
  if (msg === undefined)
@@ -122977,7 +122644,7 @@ var init_Point2 = __esm(() => {
122977
122644
  throw new Error("Unknown point format");
122978
122645
  }
122979
122646
  static fromString(str) {
122980
- const bytes = toArray15(str, "hex");
122647
+ const bytes = toArray13(str, "hex");
122981
122648
  return Point2._assertOnCurve(Point2.fromDER(bytes));
122982
122649
  }
122983
122650
  static fromX(x, odd) {
@@ -123666,7 +123333,7 @@ class Curve2 {
123666
123333
  };
123667
123334
  }
123668
123335
  static parseBytes(bytes) {
123669
- return typeof bytes === "string" ? toArray15(bytes, "hex") : bytes;
123336
+ return typeof bytes === "string" ? toArray13(bytes, "hex") : bytes;
123670
123337
  }
123671
123338
  static intFromLE(bytes) {
123672
123339
  return new BigNumber2(bytes, "hex", "le");
@@ -124697,7 +124364,7 @@ class Signature2 {
124697
124364
  this.place = 0;
124698
124365
  }
124699
124366
  }
124700
- data = toArray15(data, enc);
124367
+ data = toArray13(data, enc);
124701
124368
  const p = new Position;
124702
124369
  if (data[p.place++] !== 48) {
124703
124370
  throw new Error("Signature DER must start with 0x30");
@@ -124737,7 +124404,7 @@ class Signature2 {
124737
124404
  return new Signature2(new BigNumber2(r), new BigNumber2(s));
124738
124405
  }
124739
124406
  static fromCompact(data, enc) {
124740
- data = toArray15(data, enc);
124407
+ data = toArray13(data, enc);
124741
124408
  if (data.length !== 65) {
124742
124409
  throw new Error("Invalid Compact Signature");
124743
124410
  }
@@ -124881,8 +124548,8 @@ class DRBG2 {
124881
124548
  K;
124882
124549
  V;
124883
124550
  constructor(entropy, nonce) {
124884
- const entropyBytes = toArray15(entropy, "hex");
124885
- const nonceBytes = toArray15(nonce, "hex");
124551
+ const entropyBytes = toArray13(entropy, "hex");
124552
+ const nonceBytes = toArray13(nonce, "hex");
124886
124553
  if (entropyBytes.length !== 32) {
124887
124554
  throw new Error("Entropy must be exactly 32 bytes (256 bits)");
124888
124555
  }
@@ -125141,7 +124808,7 @@ var init_PublicKey2 = __esm(() => {
125141
124808
  } else {
125142
124809
  sharedSecret = this.deriveSharedSecret(privateKey);
125143
124810
  }
125144
- const invoiceNumberBin = toArray15(invoiceNumber, "utf8");
124811
+ const invoiceNumberBin = toArray13(invoiceNumber, "utf8");
125145
124812
  const hmac = sha256hmac2(sharedSecret.encode(true), invoiceNumberBin);
125146
124813
  const curve = new Curve2;
125147
124814
  const point = curve.g.mul(new BigNumber2(hmac));
@@ -125149,7 +124816,7 @@ var init_PublicKey2 = __esm(() => {
125149
124816
  return new PublicKey2(finalPoint.x, finalPoint.y);
125150
124817
  }
125151
124818
  static fromMsgHashAndCompactSignature(msgHash, signature, enc) {
125152
- const data = toArray15(signature, enc);
124819
+ const data = toArray13(signature, enc);
125153
124820
  if (data.length !== 65) {
125154
124821
  throw new Error("Invalid Compact Signature");
125155
124822
  }
@@ -125430,7 +125097,7 @@ var init_PrivateKey2 = __esm(() => {
125430
125097
  } else {
125431
125098
  sharedSecret = this.deriveSharedSecret(publicKey);
125432
125099
  }
125433
- const invoiceNumberBin = toArray15(invoiceNumber, "utf8");
125100
+ const invoiceNumberBin = toArray13(invoiceNumber, "utf8");
125434
125101
  const hmac = sha256hmac2(sharedSecret.encode(true), invoiceNumberBin);
125435
125102
  const curve = new Curve2;
125436
125103
  return new PrivateKey2(this.add(new BigNumber2(hmac)).mod(curve.n).toArray());
@@ -125832,7 +125499,7 @@ var init_TransactionSignature2 = __esm(() => {
125832
125499
  }
125833
125500
  writer.write(input.sourceTransaction.hash());
125834
125501
  } else {
125835
- writer.writeReverse(toArray15(input.sourceTXID, "hex"));
125502
+ writer.writeReverse(toArray13(input.sourceTXID, "hex"));
125836
125503
  }
125837
125504
  writer.writeUInt32LE(input.sourceOutputIndex);
125838
125505
  }
@@ -125916,7 +125583,7 @@ var init_TransactionSignature2 = __esm(() => {
125916
125583
  writer.writeInt32LE(params.transactionVersion);
125917
125584
  writer.write(hashPrevouts);
125918
125585
  writer.write(hashSequence);
125919
- writer.writeReverse(toArray15(params.sourceTXID, "hex"));
125586
+ writer.writeReverse(toArray13(params.sourceTXID, "hex"));
125920
125587
  writer.writeUInt32LE(params.sourceOutputIndex);
125921
125588
  const subscriptBin = params.subscript.toUint8Array();
125922
125589
  writer.writeVarIntNum(subscriptBin.length);
@@ -126230,7 +125897,7 @@ class Script2 {
126230
125897
  if (hex.length % 2 !== 0) {
126231
125898
  hex = "0" + hex;
126232
125899
  }
126233
- const arr = toArray15(hex, "hex");
125900
+ const arr = toArray13(hex, "hex");
126234
125901
  if (encode5(arr, "hex") !== hex) {
126235
125902
  throw new Error("invalid hex string in script");
126236
125903
  }
@@ -126251,7 +125918,7 @@ class Script2 {
126251
125918
  i = i + 1;
126252
125919
  } else if (opCodeNum === OP_default2.OP_PUSHDATA1 || opCodeNum === OP_default2.OP_PUSHDATA2 || opCodeNum === OP_default2.OP_PUSHDATA4) {
126253
125920
  chunks.push({
126254
- data: toArray15(tokens[i + 2], "hex"),
125921
+ data: toArray13(tokens[i + 2], "hex"),
126255
125922
  op: opCodeNum
126256
125923
  });
126257
125924
  i = i + 3;
@@ -126273,7 +125940,7 @@ class Script2 {
126273
125940
  if (!/^[0-9a-fA-F]+$/.test(hex)) {
126274
125941
  throw new Error("Some elements in this string are not hex encoded.");
126275
125942
  }
126276
- const bin = toArray15(hex, "hex");
125943
+ const bin = toArray13(hex, "hex");
126277
125944
  const rawBytes = Uint8Array.from(bin);
126278
125945
  return new Script2([], rawBytes, hex.toLowerCase(), false);
126279
125946
  }
@@ -128316,7 +127983,7 @@ class MerklePath2 {
128316
127983
  blockHeight;
128317
127984
  path;
128318
127985
  static fromHex(hex) {
128319
- return MerklePath2.fromBinary(toArray15(hex, "hex"));
127986
+ return MerklePath2.fromBinary(toArray13(hex, "hex"));
128320
127987
  }
128321
127988
  static fromReader(reader, legalOffsetsOnly = true) {
128322
127989
  const blockHeight = reader.readVarIntNum();
@@ -128408,7 +128075,7 @@ class MerklePath2 {
128408
128075
  }
128409
128076
  writer.writeUInt8(flags);
128410
128077
  if ((flags & 1) === 0) {
128411
- writer.write(toArray15(leaf.hash, "hex").reverse());
128078
+ writer.write(toArray13(leaf.hash, "hex").reverse());
128412
128079
  }
128413
128080
  }
128414
128081
  }
@@ -128448,7 +128115,7 @@ class MerklePath2 {
128448
128115
  if (typeof index !== "number") {
128449
128116
  throw new Error(`This proof does not contain the txid: ${txid ?? "undefined"}`);
128450
128117
  }
128451
- const hash = (m) => toHex7(hash2562(toArray15(m, "hex").reverse()).reverse());
128118
+ const hash = (m) => toHex7(hash2562(toArray13(m, "hex").reverse()).reverse());
128452
128119
  let workingHash = txid;
128453
128120
  if (this.path.length === 1 && this.path[0].length === 1)
128454
128121
  return workingHash;
@@ -128470,7 +128137,7 @@ class MerklePath2 {
128470
128137
  return workingHash;
128471
128138
  }
128472
128139
  findOrComputeLeaf(height, offset) {
128473
- const hash = (m) => toHex7(hash2562(toArray15(m, "hex").reverse()).reverse());
128140
+ const hash = (m) => toHex7(hash2562(toArray13(m, "hex").reverse()).reverse());
128474
128141
  let leaf = this.path[height].find((l) => l.offset === offset);
128475
128142
  if (leaf != null)
128476
128143
  return leaf;
@@ -128697,7 +128364,7 @@ class BeefTx2 {
128697
128364
  if (this._txid == null) {
128698
128365
  throw new Error("Transaction ID (_txid) is undefined");
128699
128366
  }
128700
- writer.writeReverse(toArray15(this._txid, "hex"));
128367
+ writer.writeReverse(toArray13(this._txid, "hex"));
128701
128368
  };
128702
128369
  const writeTx = () => {
128703
128370
  const bytes = this.rawTxUint8Array;
@@ -128819,7 +128486,7 @@ class Beef3 {
128819
128486
  }
128820
128487
  const writer = new WriterUint8Array2;
128821
128488
  writer.writeUInt32LE(ATOMIC_BEEF2);
128822
- writer.writeReverse(toArray15(txid, "hex"));
128489
+ writer.writeReverse(toArray13(txid, "hex"));
128823
128490
  return { beef, writer };
128824
128491
  }
128825
128492
  findTxid(txid) {
@@ -129334,7 +129001,7 @@ ${t.inputTxids.map((it) => ` '${it}'`).join(`,
129334
129001
  return log;
129335
129002
  }
129336
129003
  addComputedLeaves() {
129337
- const hash = (m) => toHex7(hash2562(toArray15(m, "hex").reverse()).reverse());
129004
+ const hash = (m) => toHex7(hash2562(toArray13(m, "hex").reverse()).reverse());
129338
129005
  for (const bump of this.bumps) {
129339
129006
  for (let row = 1;row < bump.path.length; row++) {
129340
129007
  for (const leafL of bump.path[row - 1]) {
@@ -129551,7 +129218,7 @@ class Transaction2 {
129551
129218
  return Transaction2.fromEF(toUint8Array2(hex, "hex"));
129552
129219
  }
129553
129220
  static fromHexBEEF(hex, txid) {
129554
- return Transaction2.fromBEEF(toArray15(hex, "hex"), txid);
129221
+ return Transaction2.fromBEEF(toArray13(hex, "hex"), txid);
129555
129222
  }
129556
129223
  constructor(version = 1, inputs = [], outputs = [], lockTime = 0, metadata = new Map, merklePath) {
129557
129224
  this.version = version;
@@ -129740,7 +129407,7 @@ class Transaction2 {
129740
129407
  throw new Error("sourceTransaction is undefined");
129741
129408
  }
129742
129409
  } else {
129743
- writer.writeReverse(toArray15(i.sourceTXID, "hex"));
129410
+ writer.writeReverse(toArray13(i.sourceTXID, "hex"));
129744
129411
  }
129745
129412
  writer.writeUInt32LE(i.sourceOutputIndex);
129746
129413
  if (i.unlockingScript == null) {
@@ -129788,7 +129455,7 @@ class Transaction2 {
129788
129455
  if (typeof i.sourceTXID === "undefined") {
129789
129456
  writer.write(i.sourceTransaction.hash());
129790
129457
  } else {
129791
- writer.write(toArray15(i.sourceTXID, "hex").reverse());
129458
+ writer.write(toArray13(i.sourceTXID, "hex").reverse());
129792
129459
  }
129793
129460
  writer.writeUInt32LE(i.sourceOutputIndex);
129794
129461
  if (i.unlockingScript == null) {
@@ -130193,7 +129860,7 @@ class HD2 {
130193
129860
  if (bytes.length > 512 / 8) {
130194
129861
  throw new Error("More than 512 bits of entropy is nonstandard");
130195
129862
  }
130196
- const hash = sha512hmac2(toArray15("Bitcoin seed", "utf8"), bytes);
129863
+ const hash = sha512hmac2(toArray13("Bitcoin seed", "utf8"), bytes);
130197
129864
  this.depth = 0;
130198
129865
  this.parentFingerPrint = [0, 0, 0, 0];
130199
129866
  this.childIndex = 0;
@@ -132410,7 +132077,7 @@ class Mnemonic2 {
132410
132077
  toBinary() {
132411
132078
  const bw = new Writer2;
132412
132079
  if (this.mnemonic !== "") {
132413
- const buf = toArray15(this.mnemonic, "utf8");
132080
+ const buf = toArray13(this.mnemonic, "utf8");
132414
132081
  bw.writeVarIntNum(buf.length);
132415
132082
  bw.write(buf);
132416
132083
  } else {
@@ -132538,10 +132205,10 @@ class Mnemonic2 {
132538
132205
  }
132539
132206
  mnemonic = mnemonic.normalize("NFKD");
132540
132207
  passphrase = passphrase.normalize("NFKD");
132541
- const mbuf = toArray15(mnemonic, "utf8");
132208
+ const mbuf = toArray13(mnemonic, "utf8");
132542
132209
  const pbuf = [
132543
- ...toArray15("mnemonic", "utf8"),
132544
- ...toArray15(passphrase, "utf8")
132210
+ ...toArray13("mnemonic", "utf8"),
132211
+ ...toArray13(passphrase, "utf8")
132545
132212
  ];
132546
132213
  this.seed = pbkdf23(mbuf, pbuf, 2048, 64, "sha512");
132547
132214
  return this;
@@ -156241,12 +155908,12 @@ class F7 {
156241
155908
  i.push(...o.sigResponses);
156242
155909
  }
156243
155910
  for (const r of i)
156244
- e.inputs[r.inputIndex].unlockingScript = new Script2().writeBin(toArray15(r.sig, "hex")).writeBin(toArray15(r.pubKey, "hex"));
155911
+ e.inputs[r.inputIndex].unlockingScript = new Script2().writeBin(toArray13(r.sig, "hex")).writeBin(toArray13(r.pubKey, "hex"));
156245
155912
  return {};
156246
155913
  }
156247
155914
  applySignatures(e, r) {
156248
155915
  for (const s of r)
156249
- e.inputs[s.inputIndex].unlockingScript = new Script2().writeBin(toArray15(s.sig, "hex")).writeBin(toArray15(s.pubKey, "hex"));
155916
+ e.inputs[s.inputIndex].unlockingScript = new Script2().writeBin(toArray13(s.sig, "hex")).writeBin(toArray13(s.pubKey, "hex"));
156250
155917
  return e;
156251
155918
  }
156252
155919
  async buildUnsignedMneeTransaction(t) {
@@ -156635,7 +156302,7 @@ var f11, v7 = (t) => Buffer.from(t).toString("hex"), w4 = (t, r, s, n = false) =
156635
156302
  const n = e.senders.includes(r) ? "send" : "receive", i = e.height > 0 ? "confirmed" : "unconfirmed";
156636
156303
  if (!e.rawtx)
156637
156304
  return null;
156638
- const a = toArray15(e.rawtx, "base64"), c = toHex7(a), u = Transaction2.fromHex(c).outputs.map((t) => t.lockingScript), d = S7(u), h = u.map(T5), l = d.map((t) => t.address), f = l.indexOf(s.feeAddress), p = e.senders[0];
156305
+ const a = toArray13(e.rawtx, "base64"), c = toHex7(a), u = Transaction2.fromHex(c).outputs.map((t) => t.lockingScript), d = S7(u), h = u.map(T5), l = d.map((t) => t.address), f = l.indexOf(s.feeAddress), p = e.senders[0];
156639
156306
  let m = 0;
156640
156307
  const g = new Map;
156641
156308
  h.forEach((e, n) => {
@@ -157775,6 +157442,14 @@ function registerAllTools(server, config = {}) {
157775
157442
  const enableWalletTools = process.env.DISABLE_WALLET_TOOLS !== "true" && config.enableWalletTools !== false;
157776
157443
  const enableMneeTools = process.env.DISABLE_MNEE_TOOLS !== "true" && config.enableMneeTools !== false;
157777
157444
  const enableBsocialTools = process.env.DISABLE_BSOCIAL_TOOLS !== "true" && config.enableBsocialTools !== false;
157445
+ if (enableBsocialTools) {
157446
+ registerBsocialTools(server, {
157447
+ wallet: config.roleContexts || config.walletScope === "payments" ? undefined : config.wallet,
157448
+ identityKey: config.identityPk,
157449
+ identityContext: config.walletScope === "payments" ? undefined : config.roleContexts ? config.roleContexts.identity : config.ctx,
157450
+ disableBroadcasting: config.disableBroadcasting
157451
+ });
157452
+ }
157778
157453
  if (profile === "compact") {
157779
157454
  registerCompactCatalog(server, config);
157780
157455
  return;
@@ -157811,13 +157486,6 @@ function registerAllTools(server, config = {}) {
157811
157486
  registerBapGetIdTool(server, config.identityPk);
157812
157487
  }
157813
157488
  }
157814
- if (enableBsocialTools) {
157815
- registerBsocialTools(server, {
157816
- wallet: config.wallet,
157817
- identityContext: config.roleContexts ? config.roleContexts.identity : config.ctx,
157818
- disableBroadcasting: config.disableBroadcasting
157819
- });
157820
- }
157821
157489
  if (enableWalletTools) {
157822
157490
  const externalWallet = config.externalWallet ?? (isExternalWalletContext(config.ctx) || config.ctx?.isBaseWallet === false);
157823
157491
  if (config.enableAccountTools === true && !process.env.BRC100_WALLET_URL)
@@ -260731,7 +260399,7 @@ var require_timestamp2 = __commonJS(function(exports, module) {
260731
260399
 
260732
260400
  // node_modules/knex/lib/migrations/migrate/MigrationGenerator.js
260733
260401
  var require_MigrationGenerator = __commonJS(function(exports, module) {
260734
- var __dirname = "/Users/satchmo/.codex/worktrees/local-mcp-tool-reference/node_modules/knex/lib/migrations/migrate";
260402
+ var __dirname = "/Users/satchmo/.codex/worktrees/consolidate-social/node_modules/knex/lib/migrations/migrate";
260735
260403
  var path = __require("path");
260736
260404
  var { writeJsFileUsingTemplate } = require_template2();
260737
260405
  var { getMergedConfig } = require_migrator_configuration_merger();
@@ -261438,7 +261106,7 @@ var require_seeder_configuration_merger = __commonJS(function(exports, module) {
261438
261106
 
261439
261107
  // node_modules/knex/lib/migrations/seed/Seeder.js
261440
261108
  var require_Seeder = __commonJS(function(exports, module) {
261441
- var __dirname = "/Users/satchmo/.codex/worktrees/local-mcp-tool-reference/node_modules/knex/lib/migrations/seed";
261109
+ var __dirname = "/Users/satchmo/.codex/worktrees/consolidate-social/node_modules/knex/lib/migrations/seed";
261442
261110
  var path = __require("path");
261443
261111
  var { ensureDirectoryExists } = require_fs();
261444
261112
  var { writeJsFileUsingTemplate } = require_template2();