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/CHANGELOG.md +19 -0
- package/README.md +15 -0
- package/dist/index.js +671 -1003
- package/package.json +1 -2
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.
|
|
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
|
|
84267
|
-
|
|
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
|
-
|
|
84273
|
-
|
|
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
|
-
|
|
84279
|
-
|
|
84280
|
-
|
|
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 +
|
|
84251
|
+
error: `Insufficient funds. Have ${totalInputSatoshis} sats, need ${totalOutputSatoshis + estimatedFee} sats`
|
|
84284
84252
|
};
|
|
84285
84253
|
}
|
|
84286
|
-
const
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
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 =
|
|
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,
|
|
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:
|
|
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
|
-
|
|
116492
|
-
|
|
116493
|
-
|
|
116494
|
-
|
|
116495
|
-
|
|
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
|
-
|
|
116508
|
-
|
|
116509
|
-
|
|
116510
|
-
|
|
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
|
|
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:
|
|
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/
|
|
116945
|
-
|
|
116946
|
-
|
|
116947
|
-
|
|
116948
|
-
const
|
|
116949
|
-
|
|
116950
|
-
|
|
116951
|
-
|
|
116952
|
-
|
|
116953
|
-
|
|
116954
|
-
|
|
116955
|
-
|
|
116956
|
-
|
|
116957
|
-
|
|
116958
|
-
|
|
116959
|
-
|
|
116960
|
-
|
|
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
|
-
|
|
117016
|
-
|
|
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
|
-
|
|
117020
|
-
|
|
117021
|
-
|
|
117022
|
-
|
|
117023
|
-
|
|
117024
|
-
|
|
117025
|
-
|
|
117026
|
-
|
|
117027
|
-
|
|
117028
|
-
|
|
117029
|
-
|
|
117030
|
-
|
|
117031
|
-
|
|
117032
|
-
|
|
117033
|
-
|
|
117034
|
-
|
|
117035
|
-
|
|
117036
|
-
|
|
117037
|
-
|
|
117038
|
-
|
|
117039
|
-
|
|
117040
|
-
|
|
117041
|
-
|
|
117042
|
-
|
|
117043
|
-
|
|
117044
|
-
|
|
117045
|
-
|
|
117046
|
-
|
|
117047
|
-
|
|
117048
|
-
|
|
117049
|
-
|
|
117050
|
-
|
|
117051
|
-
|
|
117052
|
-
|
|
117053
|
-
|
|
117054
|
-
|
|
117055
|
-
|
|
117056
|
-
|
|
117057
|
-
|
|
117058
|
-
|
|
117059
|
-
|
|
117060
|
-
}
|
|
117061
|
-
|
|
117062
|
-
|
|
117063
|
-
|
|
117064
|
-
|
|
117065
|
-
|
|
117066
|
-
|
|
117067
|
-
|
|
117068
|
-
|
|
117069
|
-
|
|
117070
|
-
|
|
117071
|
-
|
|
117072
|
-
|
|
117073
|
-
|
|
117074
|
-
|
|
117075
|
-
|
|
117076
|
-
|
|
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
|
-
|
|
117098
|
-
|
|
117099
|
-
|
|
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/
|
|
117109
|
-
async function
|
|
117110
|
-
|
|
117111
|
-
|
|
117112
|
-
|
|
117113
|
-
|
|
117114
|
-
|
|
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
|
-
|
|
117157
|
-
|
|
117158
|
-
|
|
117159
|
-
|
|
117160
|
-
|
|
117161
|
-
|
|
117162
|
-
|
|
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
|
-
|
|
117169
|
-
|
|
117170
|
-
|
|
117171
|
-
|
|
117172
|
-
|
|
117173
|
-
|
|
117174
|
-
|
|
117175
|
-
|
|
117176
|
-
|
|
117177
|
-
|
|
117178
|
-
|
|
117179
|
-
}
|
|
117180
|
-
|
|
117181
|
-
|
|
117182
|
-
|
|
117183
|
-
|
|
117184
|
-
|
|
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
|
-
|
|
117219
|
-
|
|
117220
|
-
|
|
117221
|
-
|
|
117222
|
-
|
|
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
|
-
|
|
117249
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
(
|
|
117350
|
-
|
|
117351
|
-
|
|
117352
|
-
|
|
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/
|
|
117359
|
-
async function
|
|
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
|
-
|
|
117362
|
-
|
|
117363
|
-
|
|
117364
|
-
|
|
117365
|
-
|
|
117366
|
-
|
|
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
|
-
|
|
117418
|
-
|
|
117419
|
-
|
|
117420
|
-
|
|
117421
|
-
|
|
117422
|
-
|
|
117423
|
-
|
|
117424
|
-
|
|
117425
|
-
|
|
117426
|
-
|
|
117427
|
-
|
|
117428
|
-
}
|
|
117429
|
-
|
|
117430
|
-
|
|
117431
|
-
|
|
117432
|
-
|
|
117433
|
-
|
|
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
|
-
|
|
117438
|
-
|
|
117439
|
-
|
|
117440
|
-
|
|
117441
|
-
|
|
117442
|
-
|
|
117443
|
-
|
|
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
|
-
|
|
117446
|
-
|
|
117447
|
-
|
|
117448
|
-
|
|
117449
|
-
}
|
|
117450
|
-
|
|
117451
|
-
|
|
117452
|
-
|
|
117453
|
-
|
|
117454
|
-
|
|
117455
|
-
|
|
117456
|
-
|
|
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
|
|
117471
|
-
|
|
117472
|
-
|
|
117473
|
-
|
|
117474
|
-
|
|
117475
|
-
|
|
117476
|
-
|
|
117477
|
-
|
|
117478
|
-
|
|
117479
|
-
|
|
117480
|
-
|
|
117481
|
-
|
|
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:
|
|
117520
|
-
|
|
117131
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
117132
|
+
structuredContent: result
|
|
117521
117133
|
};
|
|
117522
117134
|
}
|
|
117523
117135
|
});
|
|
117524
117136
|
}
|
|
117525
|
-
var
|
|
117526
|
-
var
|
|
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
|
-
|
|
117530
|
-
|
|
117531
|
-
|
|
117532
|
-
|
|
117533
|
-
|
|
117534
|
-
|
|
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
|
-
|
|
117541
|
-
|
|
117542
|
-
|
|
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
|
-
|
|
117559
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
122552
|
-
},
|
|
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 =
|
|
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" ?
|
|
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 =
|
|
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 =
|
|
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 =
|
|
124885
|
-
const nonceBytes =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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:
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
132208
|
+
const mbuf = toArray13(mnemonic, "utf8");
|
|
132542
132209
|
const pbuf = [
|
|
132543
|
-
...
|
|
132544
|
-
...
|
|
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(
|
|
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(
|
|
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 =
|
|
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/
|
|
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/
|
|
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();
|