@jdr377/mapapp-agent-connector 0.1.0-pre.13 → 0.1.0-pre.14
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/README.md +3 -3
- package/dist/{chunk-7txe8897.js → chunk-355wg846.js} +4 -4
- package/dist/{chunk-rk0z9bdp.js → chunk-ab7h8qq0.js} +1 -1
- package/dist/{chunk-kq6zsttw.js → chunk-mb8a3fs5.js} +1 -1
- package/dist/{chunk-ffcv7x5a.js → chunk-n19v6f2m.js} +1 -1
- package/dist/chunk-tssaj9jc.js +17 -0
- package/dist/participant-mcp-server.js +2 -2
- package/distribution.json +19 -19
- package/package.json +1 -1
- package/dist/chunk-618mghb5.js +0 -17
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{normalizePaidPostActionOutcome}from"./chunk-e6y2yzbj.js";import{__require}from"./chunk-btwmey1h.js";import{HTTPWalletJSON,PublicKey}from"@bsv/sdk";var AGENT_WALLET_CONNECTION_READS=Object.freeze(["isAuthenticated","getNetwork","getVersion","getPublicKey"]);class AgentWalletConnectionConfigurationError extends Error{code="invalid_agent_wallet_connection_configuration";constructor(){super("The trusted agent wallet connection configuration is invalid.");this.name="AgentWalletConnectionConfigurationError"}}var DEFAULT_TIMEOUT_MS=5000;var MAX_TIMEOUT_MS=30000;var READ_TIMEOUT=Symbol("agent-wallet-read-timeout");function createAgentWalletConnectionInspector(options){const binding=Object.freeze({...options.binding});const timeoutMs=options.timeoutMs??DEFAULT_TIMEOUT_MS;validateConfiguration(binding,timeoutMs);const wallet=options.wallet;const captured=new Map;for(const method of AGENT_WALLET_CONNECTION_READS){try{const candidate=wallet?.[method];if(typeof candidate==="function")captured.set(method,candidate)}catch{}}let inspectionInProgress=false;let outstandingRead=null;function sameProviderBinding(){try{return AGENT_WALLET_CONNECTION_READS.every((method)=>wallet[method]===captured.get(method))}catch{return false}}return{async inspect(authenticatedCallerId){const reads=AGENT_WALLET_CONNECTION_READS.map((method)=>({method,state:"not_called"}));let versionObserved=false;const result=(state,reason)=>({schema:"mapapp-agent-wallet-connection-v1",connectionId:binding.connectionId,route:binding.route,state,reason,wallet:state==="ready"?{identityKey:binding.expectedIdentityKey,network:binding.expectedNetwork}:null,versionObserved,authority:{declared:binding.declaredAuthority,enforcement:"unqualified"},capabilities:{connectionRead:state==="ready"?"observed":"blocked",publicAction:"unqualified",privateMessage:"unqualified"},reads:reads.map((read)=>({...read}))});if(authenticatedCallerId!==binding.callerId)return result("denied","caller_mismatch");if(inspectionInProgress||outstandingRead!==null)return result("unavailable","read_in_progress");if(captured.size!==AGENT_WALLET_CONNECTION_READS.length)return result("unavailable","required_method_missing");if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");inspectionInProgress=true;const deadline=performance.now()+timeoutMs;try{for(const read of reads){if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");if(performance.now()>=deadline)return result("unavailable","read_timeout");const callable=captured.get(read.method);const args=read.method==="getPublicKey"?{identityKey:true,seekPermission:false}:{};const pending=Promise.resolve().then(()=>{if(performance.now()>=deadline)throw READ_TIMEOUT;return callable.call(wallet,args,binding.originator)});outstandingRead=pending;const clearOutstandingRead=()=>{if(outstandingRead===pending)outstandingRead=null};pending.then(clearOutstandingRead,clearOutstandingRead);let value;try{value=await beforeDeadline(pending,deadline)}catch(error){read.state=error===READ_TIMEOUT?"timed_out":"failed";if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");if(error===READ_TIMEOUT)return result("unavailable","read_timeout");if(providerErrorCode(error)==="ERR_WALLET_LOCKED")return result("locked","wallet_unauthenticated");if(providerErrorCode(error)==="ERR_WALLET_UNAUTHENTICATED")return result("unauthenticated","wallet_unauthenticated");if(providerErrorCode(error)==="ERR_WALLET_ORIGIN_REFUSED")return result("denied","origin_refused");if(providerErrorCode(error)==="ERR_METHOD_NOT_SUPPORTED")return result("unavailable","required_method_missing");return isPermissionDenied(error)?result("denied","permission_denied"):result("unavailable","read_failed")}if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");read.state="observed";try{if(!isRecord(value))throw new Error;if(value.isError===true){read.state="failed";return isPermissionDenied(value)?result("denied","permission_denied"):result("unavailable","read_failed")}switch(read.method){case"isAuthenticated":if(value.authenticated===false)return result("unauthenticated","wallet_unauthenticated");if(value.authenticated!==true)throw new Error;break;case"getNetwork":if(value.network!=="mainnet"&&value.network!=="testnet")throw new Error;if(value.network!==binding.expectedNetwork)return result("binding_changed","network_binding_changed");break;case"getVersion":versionObserved=typeof value.version==="string";break;case"getPublicKey":if(!validIdentity(value.publicKey))throw new Error;if(value.publicKey!==binding.expectedIdentityKey)return result("binding_changed","identity_binding_changed");break}}catch{read.state="failed";return result("unavailable","invalid_read_response")}}return result("ready","connection_reads_observed")}finally{inspectionInProgress=false}}}}async function beforeDeadline(pending,deadline){let timer;try{const value=await Promise.race([pending,new Promise((_,reject)=>{timer=setTimeout(()=>reject(READ_TIMEOUT),Math.max(0,deadline-performance.now()))})]);if(performance.now()>=deadline)throw READ_TIMEOUT;return value}finally{if(timer!==undefined)clearTimeout(timer)}}function isPermissionDenied(error){try{return isRecord(error)&&error.code==="ERR_PERMISSION_DENIED"}catch{return false}}function providerErrorCode(error){try{return isRecord(error)?error.code:undefined}catch{return}}function validIdentity(value){if(typeof value!=="string"||!/^(02|03)[0-9a-f]{64}$/.test(value))return false;try{return PublicKey.fromString(value).toString()===value}catch{return false}}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function trustedHTTPEndpoint(endpoint){try{if(typeof endpoint!=="string"||endpoint.includes("?")||endpoint.includes("#"))throw new Error;const url=new URL(endpoint);const localHTTP=url.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(url.hostname);if(url.username||url.password||url.protocol!=="https:"&&!localHTTP)throw new Error;return url.href.replace(/\/+$/,"")}catch{throw new AgentWalletConnectionConfigurationError}}function validateConfiguration(binding,timeoutMs){const identifier=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;const domain=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;if(typeof binding.connectionId!=="string"||!identifier.test(binding.connectionId)||typeof binding.callerId!=="string"||!identifier.test(binding.callerId)||typeof binding.originator!=="string"||binding.originator.length>=250||binding.originator.split(".").length<2||!binding.originator.split(".").every((label)=>domain.test(label))||!validIdentity(binding.expectedIdentityKey)||!["mainnet","testnet"].includes(binding.expectedNetwork)||!["existing_brc100","agent_environment"].includes(binding.route)||!["provider","isolated_stock_client","full_root_authority"].includes(binding.declaredAuthority)||!Number.isInteger(timeoutMs)||timeoutMs<=0||timeoutMs>MAX_TIMEOUT_MS){throw new AgentWalletConnectionConfigurationError}}var POST_GEOHASH_MIN_PRECISION=8;var POST_GEOHASH_MAX_PRECISION=16;var POST_GEOHASH_DEFAULT_PRECISION=9;var POST_GEOHASH_PATTERN=/^[0123456789bcdefghjkmnpqrstuvwxyz]{8,16}$/;var BASE32="0123456789bcdefghjkmnpqrstuvwxyz";function encodeGeohash(lat,lng,precision=6){const safePrecision=Math.max(4,Math.min(16,Math.trunc(precision)));const latRange=[-90,90];const lngRange=[-180,180];const bits=[16,8,4,2,1];let isEven=true;let bit=0;let ch=0;let geohash="";const safeLat=clampFinite(lat,-90,90);const safeLng=clampFinite(lng,-180,180);while(geohash.length<safePrecision){if(isEven){const mid=(lngRange[0]+lngRange[1])/2;if(safeLng>=mid){ch|=bits[bit]??0;lngRange[0]=mid}else{lngRange[1]=mid}}else{const mid=(latRange[0]+latRange[1])/2;if(safeLat>=mid){ch|=bits[bit]??0;latRange[0]=mid}else{latRange[1]=mid}}isEven=!isEven;if(bit<4){bit+=1}else{geohash+=BASE32[ch]??"0";bit=0;ch=0}}return geohash}function geohashBounds(geohash){const safeGeohash=geohash.trim().toLowerCase();if(!safeGeohash)return null;const latRange=[-90,90];const lngRange=[-180,180];let isEven=true;for(const character of safeGeohash){const value=BASE32.indexOf(character);if(value<0)return null;for(const mask of[16,8,4,2,1]){if(isEven){bisectRange(lngRange,(value&mask)!==0)}else{bisectRange(latRange,(value&mask)!==0)}isEven=!isEven}}return{west:lngRange[0],south:latRange[0],east:lngRange[1],north:latRange[1]}}function bisectRange(range,useUpperHalf){const mid=(range[0]+range[1])/2;if(useUpperHalf){range[0]=mid}else{range[1]=mid}}function clampFinite(value,min,max){if(value===Number.POSITIVE_INFINITY)return max;if(value===Number.NEGATIVE_INFINITY)return min;if(!Number.isFinite(value))return min;return Math.min(max,Math.max(min,value))}var MEDIA_RELAY_SAFE_MAX_BYTES=99*1024;function readWebpDimensions(bytes){if(bytes.length<20||text4(bytes,0)!=="RIFF"||text4(bytes,8)!=="WEBP"||u32(bytes,4)+8!==bytes.length)return null;let offset=12;let extended=null;let image=null;while(offset<bytes.length){if(offset+8>bytes.length)return null;const kind=text4(bytes,offset);const length=u32(bytes,offset+4);const payload=offset+8;const end=payload+length;const paddedEnd=end+(length&1);if(end>bytes.length||paddedEnd>bytes.length)return null;if(!extended&&kind==="VP8X"){if(length!==10)return null;extended={width:1+u24(bytes,payload+4),height:1+u24(bytes,payload+7)}}else if(!image&&kind==="VP8 "){if(length<10||bytes[payload+3]!==157||bytes[payload+4]!==1||bytes[payload+5]!==42)return null;image={width:(bytes[payload+6]|bytes[payload+7]<<8)&16383,height:(bytes[payload+8]|bytes[payload+9]<<8)&16383}}else if(!image&&kind==="VP8L"){if(length<5||bytes[payload]!==47)return null;const bits=u32(bytes,payload+1);image={width:1+(bits&16383),height:1+(bits>>>14&16383)}}offset=paddedEnd}if(offset!==bytes.length||!image)return null;if(extended&&(extended.width!==image.width||extended.height!==image.height))return null;return extended??image}function text4(bytes,offset){return String.fromCharCode(...bytes.slice(offset,offset+4))}function u24(bytes,offset){return bytes[offset]|bytes[offset+1]<<8|bytes[offset+2]<<16}function u32(bytes,offset){return(bytes[offset]|bytes[offset+1]<<8|bytes[offset+2]<<16|bytes[offset+3]<<24)>>>0}var AGENT_MEDIA_MAX_BASE64_LENGTH=4*Math.ceil(MEDIA_RELAY_SAFE_MAX_BYTES/3);class AgentMediaError extends Error{code;constructor(code){super(code);this.code=code}}function fail(code){throw new AgentMediaError(code)}function validAgentMediaInput(value){if(!value||typeof value!=="object"||Array.isArray(value))return false;const media=value;return Object.keys(media).length===4&&Object.keys(media).every((key)=>["contentType","base64","byteSize","sha256"].includes(key))&&["image/webp","video/webm"].includes(media.contentType)&&typeof media.base64==="string"&&media.base64.length>0&&media.base64.length<=AGENT_MEDIA_MAX_BASE64_LENGTH&&media.base64.length%4===0&&/^[A-Za-z0-9+/]*={0,2}$/.test(media.base64)&&Number.isSafeInteger(media.byteSize)&&media.byteSize>0&&media.byteSize<=MEDIA_RELAY_SAFE_MAX_BYTES&&typeof media.sha256==="string"&&/^[0-9a-f]{64}$/.test(media.sha256)}async function inspectAgentMedia(value){if(!validAgentMediaInput(value))fail("invalid_media_input");const binary=atob(value.base64);if(btoa(binary)!==value.base64)fail("invalid_media_base64");const bytes=Uint8Array.from(binary,(character)=>character.charCodeAt(0));if(bytes.length!==value.byteSize)fail("media_size_mismatch");const hash=new Uint8Array(await crypto.subtle.digest("SHA-256",bytes.buffer));const sha256=Array.from(hash,(byte)=>byte.toString(16).padStart(2,"0")).join("");if(sha256!==value.sha256)fail("media_hash_mismatch");const dimensions=value.contentType==="image/webp"?await inspectImage(bytes):await inspectVideo(bytes);return{media:value.contentType==="image/webp"?{kind:"image",contentType:"image/webp",bytes}:{kind:"video",contentType:"video/webm",bytes},summary:{contentType:value.contentType,byteSize:bytes.length,sha256,...dimensions}}}async function inspectImage(bytes){const dimensions=readWebpDimensions(bytes);if(!dimensions)fail("invalid_media_container");if(dimensions.width<1||dimensions.height<1||dimensions.width>1024||dimensions.height>1024)fail("media_dimensions_too_large");try{const{default:decode}=await import("@jsquash/webp/decode.js");const decoded=await decode(Uint8Array.from(bytes).buffer);if(decoded.width!==dimensions.width||decoded.height!==dimensions.height)fail("invalid_media_container");return dimensions}catch{return fail("invalid_media_container")}}async function inspectVideo(bytes){const{Input,BufferSource,WEBM}=await import("mediabunny");const input=new Input({source:new BufferSource(bytes),formats:[WEBM]});let timeout;try{return await Promise.race([(async()=>{const[videos,audios,tracks]=await Promise.all([input.getVideoTracks(),input.getAudioTracks(),input.getTracks()]);if(videos.length!==1||audios.length>1||tracks.length!==videos.length+audios.length)fail("media_tracks_unsupported");const track=videos[0];const[codec,width,height,displayWidth,displayHeight,duration,stats]=await Promise.all([track.getCodec(),track.getCodedWidth(),track.getCodedHeight(),track.getDisplayWidth(),track.getDisplayHeight(),input.computeDuration(),track.computePacketStats(1)]);if(codec!=="vp8"&&codec!=="vp9")fail("media_codec_unsupported");if([width,height,displayWidth,displayHeight].some((size)=>!Number.isFinite(size)||size<1||size>512))fail("media_dimensions_too_large");if(!Number.isFinite(duration)||duration<=0||duration>30)fail("media_video_duration_invalid");if(stats.packetCount<1)fail("invalid_media_container");if(audios[0]&&!["opus","vorbis"].includes(await audios[0].getCodec()??""))fail("media_codec_unsupported");return{width,height,durationMs:Math.ceil(duration*1000)}})(),new Promise((_,reject)=>{timeout=setTimeout(()=>{input.dispose();reject(new AgentMediaError("media_inspection_timeout"))},5000)})])}catch(error){if(error instanceof AgentMediaError)throw error;return fail("invalid_media_container")}finally{clearTimeout(timeout);input.dispose()}}var MAPAPP_CATEGORY_TOKENS=["\uD83C\uDF31","\uD83D\uDCCD","\uD83E\uDDED","\uD83C\uDFA8","\uD83C\uDFB5","\uD83C\uDF7D\uFE0F","\u2615","\uD83D\uDED2","\uD83C\uDFC0","\uD83C\uDFAE","\uD83D\uDCF0","\uD83D\uDCAC","\uD83D\uDCF8","\uD83C\uDFAC","\uD83D\uDCBB","\uD83D\uDEE0\uFE0F","\uD83C\uDFE0","\uD83D\uDE97","\uD83C\uDF0A","\u26F0\uFE0F","\uD83C\uDF33","\uD83D\uDC3E","\uD83C\uDF93","\uD83C\uDFE5","\u26A0\uFE0F","\uD83C\uDF89","\uD83D\uDCBC","\uD83D\uDD2C","\u2708\uFE0F","\uD83E\uDDD8","\uD83E\uDE99","\u2764\uFE0F"];var DEFAULT_MAPAPP_CATEGORY=MAPAPP_CATEGORY_TOKENS[0];import{sendAllBsv,sendBsv}from"@1sat/actions";import{P2PKH,Transaction,Utils}from"@bsv/sdk";var MAX_DIRECT_BSV_SEND_SATOSHIS=2099999999999998;function validateDirectBsvInput(input){const address=input.to.trim();let decoded;try{decoded=Utils.fromBase58Check(address)}catch{return{ok:false,code:"bsv_address_invalid",message:"Enter a valid mainnet BSV address."}}if(decoded.data.length!==20){return{ok:false,code:"bsv_address_invalid",message:"Enter a valid mainnet P2PKH address."}}if(decoded.prefix.length!==1||decoded.prefix[0]!==0){return{ok:false,code:"bsv_address_wrong_network",message:"Direct sends require a mainnet BSV address."}}if(!("satoshis"in input))return{ok:true,address,max:true};if(!Number.isSafeInteger(input.satoshis)||input.satoshis<1||input.satoshis>MAX_DIRECT_BSV_SEND_SATOSHIS){return{ok:false,code:"bsv_amount_invalid",message:`Amount must be a whole number from 1 to ${MAX_DIRECT_BSV_SEND_SATOSHIS} satoshis.`}}return{ok:true,address,satoshis:input.satoshis}}function inspectDirectBsvEvidence(atomicBeef,address){try{const tx=Transaction.fromBEEF(atomicBeef);const script=new P2PKH().lock(address).toHex();const matching=tx.outputs.filter((output)=>output.lockingScript.toHex()===script);if(matching.length!==1)return null;const satoshis=matching[0]?.satoshis;if(typeof satoshis!=="number"||!Number.isSafeInteger(satoshis)||satoshis<1)return null;const inputSatoshis=tx.inputs.map((input)=>input.sourceTransaction?.outputs[input.sourceOutputIndex]?.satoshis);const fee=inputSatoshis.every((value)=>Number.isSafeInteger(value))?inputSatoshis.reduce((sum,value)=>sum+(value??0),0)-tx.outputs.reduce((sum,output)=>sum+(output.satoshis??0),0):null;return{satoshis,fee:fee!==null&&Number.isSafeInteger(fee)&&fee>=0?fee:null}}catch{return null}}import{Transaction as Transaction3}from"@bsv/sdk";import{executeTrackedAction}from"@1sat/actions";import{LOCK_BASKET}from"@1sat/types";import{Beef}from"@bsv/sdk";import{Lock}from"@1sat/templates";import{PublicKey as PublicKey2,Script}from"@bsv/sdk";var LOCK_DISCOVERY_PAGE_LIMIT=1000;var LOCK_DISCOVERY_LIMIT=1e4;var DEFAULT_CHECKED_AT=()=>new Date().toISOString();function parseLockCustomInstructions(value){if(typeof value!=="string"||!value.trim())return null;let parsed;try{parsed=JSON.parse(value)}catch{return null}if(!isRecord2(parsed))return null;const rawProtocol=parsed.protocolID;if(!Array.isArray(rawProtocol)||rawProtocol.length!==2)return null;const securityLevel=rawProtocol[0];const protocolName=rawProtocol[1];if(!isSafeInteger(securityLevel)||securityLevel<0||securityLevel>2)return null;if(typeof protocolName!=="string"||!hasByteLength(protocolName,5,400)||protocolName.trim()!==protocolName){return null}const keyID=parsed.keyID;if(typeof keyID!=="string"||!hasByteLength(keyID,1,800)||keyID.trim()!==keyID||/\s/.test(keyID)){return null}let counterparty="self";if(parsed.counterparty!==undefined){if(typeof parsed.counterparty!=="string"||!hasByteLength(parsed.counterparty,1,800)||parsed.counterparty.trim()!==parsed.counterparty||/\s/.test(parsed.counterparty)){return null}counterparty=parsed.counterparty}if(parsed.forSelf!==undefined&&parsed.forSelf!==true)return null;return{protocolID:[securityLevel,protocolName],keyID,counterparty,forSelf:true}}async function normalizeWalletLockRows(rows,options){const currentHeight=readNonNegativeSafeInteger(options.currentHeight);const empty={currentHeight,outputs:[],legacyOutputs:[],incompatibleOutputs:[],complete:false,paginationComplete:false,derivationUnavailable:false,derivationFailed:false,aggregateSafe:true,message:null};if(currentHeight===null){return{...empty,message:"Current chain height is unavailable."}}if(!Array.isArray(rows)){return{...empty,message:"The wallet returned an invalid lock list."}}const pagination=readPagination(options);const paginationComplete=assessPagination(rows.length,pagination);const result={...empty,complete:paginationComplete.complete,paginationComplete:paginationComplete.complete,message:paginationComplete.message};const seenOutpoints=new Set;const duplicateIds=new Set;const idOwners=new Map;const keyChecks=new Map;const decode=options.decodeLock??((script,mainnet2)=>Lock.decode(script,mainnet2));const mainnet=options.mainnet!==false;for(const rawRow of rows){const record=isRecord2(rawRow)?rawRow:null;if(!record){result.incompatibleOutputs.push({outpoint:null,reason:"row-not-object"});continue}const outpoint=readOutpoint(record.outpoint);if(!outpoint){result.incompatibleOutputs.push({outpoint:null,reason:"invalid-outpoint"});continue}if(seenOutpoints.has(outpoint)){result.incompatibleOutputs.push({outpoint,reason:"duplicate-outpoint"});continue}seenOutpoints.add(outpoint);const satoshis=readPositiveSafeInteger(record.satoshis);if(satoshis===null){result.incompatibleOutputs.push({outpoint,reason:"invalid-satoshis"});continue}const tags=readTags(record.tags);if(!tags.ok){result.incompatibleOutputs.push({outpoint,reason:"invalid-tags"});continue}const until=readUntilTag(tags.tags);if(until.kind==="invalid"){result.incompatibleOutputs.push({outpoint,reason:until.reason});continue}const id=readIdTag(tags.tags);if(id.kind==="invalid"){result.incompatibleOutputs.push({outpoint,reason:id.reason});continue}if(until.kind==="valid"&&id.kind==="valid"){if(duplicateIds.has(id.value)){result.incompatibleOutputs.push({outpoint,reason:"duplicate-id"});continue}const owner2=idOwners.get(id.value);if(owner2){duplicateIds.add(id.value);if(owner2.output){const priorIndex=result.outputs.findIndex((output2)=>output2.id===id.value);if(priorIndex>=0)result.outputs.splice(priorIndex,1)}if(!owner2.incompatible){result.incompatibleOutputs.push({outpoint:owner2.outpoint,reason:"duplicate-id"});owner2.incompatible=true}result.incompatibleOutputs.push({outpoint,reason:"duplicate-id"});continue}idOwners.set(id.value,{outpoint,output:null,incompatible:false})}const script=readScript(record.lockingScript);if(!script){result.incompatibleOutputs.push({outpoint,reason:"invalid-locking-script"});continue}let decoded;try{decoded=decode(script,mainnet)}catch{decoded=null}const decodedHeight=decoded?readPositiveSafeInteger(decoded.until):null;const decodedAddress=decoded&&typeof decoded.address==="string"&&decoded.address.trim()===decoded.address&&decoded.address.length>0?decoded.address:null;if(!decoded||decodedHeight===null||!decodedAddress){result.incompatibleOutputs.push({outpoint,reason:"not-a-valid-lock-script"});continue}if(until.kind==="valid"&&until.value!==decodedHeight){result.incompatibleOutputs.push({outpoint,reason:"tag-script-height-mismatch"});continue}const metadata=parseLockCustomInstructions(record.customInstructions);if(!metadata){result.incompatibleOutputs.push({outpoint,reason:"invalid-custom-instructions"});continue}const tupleKey=JSON.stringify([metadata.protocolID,metadata.keyID,metadata.counterparty]);let derivedAddressPromise=keyChecks.get(tupleKey);if(!derivedAddressPromise){derivedAddressPromise=deriveAddress(metadata,options,result);keyChecks.set(tupleKey,derivedAddressPromise)}const derivedAddress=await derivedAddressPromise;if(!derivedAddress){result.incompatibleOutputs.push({outpoint,reason:"lock-key-unavailable"});continue}if(derivedAddress!==decodedAddress){result.incompatibleOutputs.push({outpoint,reason:"derived-key-address-mismatch"});continue}if(until.kind==="missing"||id.kind==="missing"){const legacy={outpoint,satoshis,unlockHeight:decodedHeight,state:decodedHeight<currentHeight?"matured":"locked"};result.legacyOutputs.push(legacy);continue}const output={id:id.value,outpoint,satoshis,unlockHeight:decodedHeight,blocksRemaining:Math.max(0,decodedHeight-currentHeight),state:decodedHeight<currentHeight?"matured":"locked"};const owner=idOwners.get(id.value);if(duplicateIds.has(id.value)){result.incompatibleOutputs.push({outpoint,reason:"duplicate-id"});continue}if(owner)owner.output=output;result.outputs.push(output)}result.outputs.sort(compareLockOutputs);result.legacyOutputs.sort(compareLegacyOutputs);result.complete=paginationComplete.complete&&result.incompatibleOutputs.length===0;result.message=normalizationMessage(result,paginationComplete.message);return result}async function summarizeWalletLocks(rows,options){const checkedAt=options.checkedAt===undefined?DEFAULT_CHECKED_AT():options.checkedAt;const normalized=await normalizeWalletLockRows(rows,options);if(normalized.currentHeight===null){return{...emptyWalletLockSummary("error",normalized.message??"Current chain height is unavailable.",checkedAt)}}const sums=sumValidatedLocks(normalized.outputs,normalized.legacyOutputs);if(!sums.safe){return{...emptyWalletLockSummary("error","Validated lock totals exceed the safe integer range.",checkedAt),currentHeight:normalized.currentHeight,outputs:normalized.outputs,incompatibleOutputCount:normalized.incompatibleOutputs.length,legacyOutputCount:normalized.legacyOutputs.length,legacyLockedSats:0,complete:false}}const nextUnlockHeight=normalized.outputs.filter((output)=>output.state==="locked").reduce((next,output)=>next===null?output.unlockHeight:Math.min(next,output.unlockHeight),null);const state=normalized.derivationUnavailable?"unsupported":normalized.derivationFailed?"error":"ready";const message=state==="ready"?normalized.message:normalized.message??(state==="unsupported"?"The connected wallet does not expose the key derivation needed to inspect locks.":"The connected wallet denied or failed the lock-key derivation check.");return{state,checkedAt,currentHeight:normalized.currentHeight,recoverableLockedSats:sums.recoverable,unlockableSats:sums.unlockable,nextUnlockHeight,blocksUntilNextUnlock:nextUnlockHeight===null?null:Math.max(0,nextUnlockHeight-normalized.currentHeight),outputs:normalized.outputs,incompatibleOutputCount:normalized.incompatibleOutputs.length,legacyOutputCount:normalized.legacyOutputs.length,legacyLockedSats:sums.legacy,complete:normalized.complete,message}}function emptyWalletLockSummary(state,message=null,checkedAt=null){return{state,checkedAt,currentHeight:null,recoverableLockedSats:0,unlockableSats:0,nextUnlockHeight:null,blocksUntilNextUnlock:null,outputs:[],incompatibleOutputCount:0,legacyOutputCount:0,legacyLockedSats:0,complete:false,message}}function deriveAddress(metadata,options,result){const request=options.originator===undefined?{...metadata}:{...metadata,originator:options.originator};if(!options.deriveLockAddress&&!options.derivePublicKey){result.derivationUnavailable=true;return Promise.resolve(null)}const resolver=options.deriveLockAddress??options.derivePublicKey;return Promise.resolve().then(()=>resolver(request)).then((value)=>options.derivePublicKey&&!options.deriveLockAddress?addressFromPublicKeyResult(value):addressFromDerivationResult(value)).catch(()=>{result.derivationFailed=true;return null})}function addressFromDerivationResult(value){if(typeof value==="string"){const normalized=value.trim();if(!normalized||normalized!==value)return null;if(/^(02|03)[0-9a-f]{64}$/i.test(normalized))return publicKeyToAddress(normalized);return normalized}if(!isRecord2(value))return null;if(typeof value.address==="string"&&value.address.trim()===value.address&&value.address.length>0){const publicKeyAddress=typeof value.publicKey==="string"?publicKeyToAddress(value.publicKey):null;if(value.publicKey!==undefined&&!publicKeyAddress)return null;if(publicKeyAddress&&publicKeyAddress!==value.address)return null;return value.address}return typeof value.publicKey==="string"?publicKeyToAddress(value.publicKey):null}function addressFromPublicKeyResult(value){if(typeof value==="string")return publicKeyToAddress(value);if(isRecord2(value)&&typeof value.publicKey==="string")return publicKeyToAddress(value.publicKey);return null}function publicKeyToAddress(value){try{return PublicKey2.fromString(value).toAddress()}catch{return null}}function readScript(value){if(value instanceof Script)return value;if(typeof value!=="string"||value.length===0||value.length%2!==0||!/^[0-9a-f]+$/i.test(value))return null;try{return Script.fromHex(value)}catch{return null}}function readOutpoint(value){if(typeof value!=="string"||value.trim()!==value)return null;const match=/^([0-9a-f]{64})([._])(\d+)$/i.exec(value);if(!match)return null;const outputIndex=Number(match[3]);if(!Number.isSafeInteger(outputIndex)||outputIndex<0)return null;return`${match[1].toLowerCase()}.${outputIndex}`}function readTags(value){if(value===undefined)return{ok:true,tags:[]};if(!Array.isArray(value)||value.some((tag)=>typeof tag!=="string"))return{ok:false};return{ok:true,tags:value}}function readUntilTag(tags){const matches=tags.filter((tag)=>tag.startsWith("until:"));if(matches.length===0)return{kind:"missing"};if(matches.length!==1)return{kind:"invalid",reason:"duplicate-until-tag"};const raw=matches[0].slice("until:".length);if(!/^[1-9]\d*$/.test(raw))return{kind:"invalid",reason:"invalid-until-tag"};const value=Number(raw);return Number.isSafeInteger(value)&&value>0?{kind:"valid",value}:{kind:"invalid",reason:"unsafe-until-tag"}}function readIdTag(tags){const matches=tags.filter((tag)=>tag.startsWith("id:"));if(matches.length===0)return{kind:"missing"};if(matches.length!==1)return{kind:"invalid",reason:"duplicate-id-tag"};const value=matches[0].slice("id:".length);if(!value||value.trim()!==value||/\s/.test(value)||!hasByteLength(value,1,300)){return{kind:"invalid",reason:"invalid-id-tag"}}return{kind:"valid",value}}function readPagination(options){const nested=options.pagination??{};return{totalOutputs:options.totalOutputs!==undefined?options.totalOutputs:nested.totalOutputs,limit:options.limit!==undefined?options.limit:nested.limit,offset:options.offset!==undefined?options.offset:nested.offset,hasMore:options.hasMore!==undefined?options.hasMore:nested.hasMore,complete:options.complete!==undefined?options.complete:nested.complete}}function assessPagination(rowsLength,page){const offset=page.offset===undefined?0:readNonNegativeSafeInteger(page.offset);const limit=page.limit===undefined?null:readPositiveSafeInteger(page.limit);const total=page.totalOutputs===undefined?null:readNonNegativeSafeInteger(page.totalOutputs);let complete=true;let message=null;if(offset===null||page.limit!==undefined&&limit===null||page.totalOutputs!==undefined&&total===null||page.hasMore!==undefined&&typeof page.hasMore!=="boolean"||page.complete!==undefined&&typeof page.complete!=="boolean"){complete=false;message="Lock discovery returned invalid pagination metadata."}else if(offset>0){complete=false;message="Lock discovery returned a partial page."}else if(total!==null&&total>rowsLength){complete=false;message="Lock discovery is incomplete; the wallet reported more lock outputs than it returned."}else if(total!==null&&total<rowsLength){complete=false;message="Lock discovery returned more rows than its total output count."}else if(limit!==null&&rowsLength>=limit&&page.hasMore!==false&&total===null&&page.complete!==true){complete=false;message="Lock discovery may be truncated at the wallet page limit."}if(page.hasMore===true){complete=false;message="Lock discovery has another wallet page; totals are incomplete."}if(page.complete===false){complete=false;message=message??"Lock discovery is incomplete."}return{complete,message}}function normalizationMessage(result,paginationMessage){const parts=[];if(result.incompatibleOutputs.length>0){const count=result.incompatibleOutputs.length;parts.push(`Skipped ${count} incompatible lock output${count===1?"":"s"}.`)}if(result.legacyOutputs.length>0){const count=result.legacyOutputs.length;parts.push(`Found ${count} legacy lock output${count===1?"":"s"}; current recovery cannot unlock ${count===1?"it":"them"}.`)}if(paginationMessage)parts.push(paginationMessage);if(result.derivationUnavailable)parts.push("The connected wallet does not expose lock-key derivation.");if(result.derivationFailed)parts.push("The connected wallet denied or failed lock-key derivation.");return parts.length>0?parts.join(" "):null}function sumValidatedLocks(outputs,legacy){let recoverable=0;let unlockable=0;let legacyTotal=0;for(const output of outputs){recoverable=safeAdd(recoverable,output.satoshis);if(output.state==="matured")unlockable=safeAdd(unlockable,output.satoshis)}for(const output of legacy)legacyTotal=safeAdd(legacyTotal,output.satoshis);const safe=Number.isSafeInteger(recoverable)&&Number.isSafeInteger(unlockable)&&Number.isSafeInteger(legacyTotal);return{recoverable:safe?recoverable:0,unlockable:safe?unlockable:0,legacy:safe?legacyTotal:0,safe}}function safeAdd(left,right){const value=left+right;return Number.isSafeInteger(value)?value:Number.NaN}function compareLockOutputs(left,right){if(left.state!==right.state)return left.state==="matured"?-1:1;if(left.unlockHeight!==right.unlockHeight)return left.unlockHeight-right.unlockHeight;return left.outpoint.localeCompare(right.outpoint)}function compareLegacyOutputs(left,right){if(left.state!==right.state)return left.state==="matured"?-1:1;if(left.unlockHeight!==right.unlockHeight)return left.unlockHeight-right.unlockHeight;return left.outpoint.localeCompare(right.outpoint)}function isRecord2(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function isSafeInteger(value){return typeof value==="number"&&Number.isSafeInteger(value)}function readPositiveSafeInteger(value){return isSafeInteger(value)&&value>0?value:null}function readNonNegativeSafeInteger(value){return isSafeInteger(value)&&value>=0?value:null}function hasByteLength(value,minimum,maximum){const bytes=new TextEncoder().encode(value).byteLength;return bytes>=minimum&&bytes<=maximum}async function inspectSelectedLocks(context,ids){if(!context.services||!ids.length||ids.length>LOCK_DISCOVERY_LIMIT||new Set(ids).size!==ids.length){return{error:"invalid-lock-selection"}}const currentHeight=await context.services.chaintracks.currentHeight();const outputs=[];const beef=new Beef;while(outputs.length<ids.length){const listed=await context.wallet.listOutputs({basket:LOCK_BASKET,tags:ids.map((id)=>`id:${id}`),tagQueryMode:"any",include:"entire transactions",includeTags:true,includeCustomInstructions:true,limit:Math.min(LOCK_DISCOVERY_PAGE_LIMIT,ids.length-outputs.length),offset:outputs.length});if(listed.totalOutputs!==ids.length||!listed.outputs.length||listed.outputs.length>Math.min(LOCK_DISCOVERY_PAGE_LIMIT,ids.length-outputs.length))return{error:"lock-selection-changed"};if(listed.BEEF?.length)beef.mergeBeef(listed.BEEF);outputs.push(...listed.outputs)}for(const txid of new Set(outputs.map((output)=>output.outpoint.split(".")[0]))){if(!beef.findTxid(txid)?.tx)beef.mergeBeef(await context.services.getBeefForTxid(txid))}const inputBEEF=beef.toBinary();const rows=outputs.map((output)=>{const[txid,vout]=output.outpoint.split(".");const source=beef.findTxid(txid)?.tx?.outputs[Number(vout)];if(!source||source.satoshis!==output.satoshis)throw Error("Lock source evidence conflicts with wallet discovery.");return{...output,lockingScript:source.lockingScript.toHex()}});const validated=await summarizeWalletLocks(rows,{currentHeight,mainnet:context.chain==="main",totalOutputs:ids.length,limit:LOCK_DISCOVERY_LIMIT,offset:0,derivePublicKey:(request)=>context.wallet.getPublicKey({protocolID:request.protocolID,keyID:request.keyID,counterparty:request.counterparty,forSelf:true})});if(validated.state!=="ready"||!validated.complete||validated.outputs.length!==ids.length||validated.outputs.some((output)=>!ids.includes(output.id))){return{error:"lock-selection-changed"}}return{rows,inputBEEF,outputs:validated.outputs,currentHeight}}async function executeBoundedLockUnlock(context,ids,beforeDispatch,recovery={}){const selection=await inspectSelectedLocks(context,ids);if("error"in selection)return selection;const{rows,inputBEEF,outputs}=selection;if(outputs.some((output)=>output.state!=="matured")||recovery.expectedOutpoints&&(recovery.expectedOutpoints.length!==outputs.length||outputs.some((output)=>!recovery.expectedOutpoints.includes(output.outpoint)))){return{error:"lock-selection-changed"}}beforeDispatch?.();return executeTrackedAction(context.wallet,{description:`Unlock ${rows.length} lock(s)`,inputBEEF,...recovery.labels?.length?{labels:recovery.labels}:{},inputs:rows.map((output)=>({outpoint:output.outpoint,inputDescription:"Locked BSV",unlockingScriptLength:1205,sequenceNumber:0})),outputs:[],lockTime:Math.max(...outputs.map((output)=>output.unlockHeight)),options:{acceptDelayedBroadcast:false,returnTXIDOnly:false}},undefined,inputBEEF,undefined,{spends:rows.map((output)=>({outpoint:output.outpoint,customInstructions:output.customInstructions})),usePermissionModule:false,permissionScheme:"lock"})}import{Transaction as Transaction2}from"@bsv/sdk";async function recoverNativeActionEvidence(options){const fail2=(code,message)=>({ok:false,code,message});const{record,checkpoint}=options;const retained=record.returnedEvidence;const format=record.reference.evidenceFormat;if(!retained||!["mapapp_direct_bsv_v1","mapapp_post_v2","mapapp_social_v2","mapapp_upgrade_v2","mapapp_sponsored_v2","mapapp_bap_alias_v1"].includes(format??"")){return fail2("exact_evidence_unavailable","This native action has no retained exact evidence. Do not repeat the spend.")}if(retained.originator!==options.originator||checkpoint&&checkpoint.txid!==retained.txid){return fail2("recovery_binding_conflict","The retained evidence does not match this origin or pending native action.")}try{if(!/^[0-9a-f]{64}$/.test(retained.txid)||!Array.isArray(retained.atomicBeef)||!retained.atomicBeef.length||retained.atomicBeef.length>2*1024*1024)throw new Error;for(let index=0;index<retained.atomicBeef.length;index++){const byte=retained.atomicBeef[index];if(!Number.isInteger(byte)||byte<0||byte>255)throw new Error}const atomicBeef=Uint8Array.from(retained.atomicBeef);const tx=Transaction2.fromAtomicBEEF(atomicBeef);if(tx.id("hex")!==retained.txid)throw new Error;if(format==="mapapp_direct_bsv_v1"){const draft=record.draft;if(!draft||draft.kind!=="bsv_send"||typeof draft.to!=="string")throw new Error;const payment=inspectDirectBsvEvidence(atomicBeef,draft.to);if(!payment||draft.max!==true&&payment.satoshis!==draft.satoshis)throw new Error}if(format==="mapapp_sponsored_v2"||format==="mapapp_bap_alias_v1"){if(!options.wallet.listOutputs)return fail2("wallet_commit_unverified","The author wallet cannot inspect its internalized sponsor output.");const profile=format==="mapapp_bap_alias_v1";const draft=record.draft;if(profile&&!draft?.bapId)return fail2("recovery_binding_conflict","The retained profile has no original BAP binding.");const tags=profile?["type:alias",`bapId:${draft.bapId}`]:[record.reference.correlationTag];const listed=await options.wallet.listOutputs({basket:profile?"bap":"bsocial",tags,tagQueryMode:"all",include:"entire transactions",includeTags:true,limit:1000,offset:0});if(!listed.totalOutputs||listed.outputs.length!==listed.totalOutputs||!listed.BEEF?.length){return fail2("wallet_commit_unverified","The author wallet has no complete internalized output for this sponsor evidence.")}const restoredTx=Transaction2.fromBEEF(listed.BEEF,retained.txid);if(restoredTx.toHex()!==tx.toHex()||listed.outputs.some((output)=>{const[txid,vout]=output.outpoint.split(".");const expected=tx.outputs[Number(vout)];return txid!==retained.txid||!expected||output.satoshis!==expected.satoshis||tags.some((tag)=>!output.tags?.includes(tag.toLowerCase()))}))return fail2("wallet_evidence_conflict","Wallet basket output conflicts with retained exact evidence.");return{ok:true,txid:retained.txid,atomicBeef,walletStatus:profile?"retained wallet ALIAS":"internalized sponsor evidence"}}const label=format==="mapapp_direct_bsv_v1"?`mapapp intent ${record.reference.intentId}`:`mapapp correlation ${record.reference.correlationTag}`;const verified=await verifyWalletActionEvidence(options.wallet,tx,label);return verified.ok?{...verified,atomicBeef}:verified}catch{return fail2("exact_evidence_invalid","Exact evidence could not be verified through this wallet. The spend remains recovery-only.")}}async function verifyWalletActionEvidence(wallet,tx,label){const fail2=(code,message)=>({ok:false,code,message});try{const listed=await wallet.listActions({labels:[label],labelQueryMode:"all",includeLabels:true,includeInputs:true,includeOutputs:true,includeOutputLockingScripts:true,limit:2});if(listed.totalActions!==1||listed.actions.length!==1||listed.actions[0]?.txid!==tx.id("hex")){return fail2("wallet_commit_unverified","The wallet has no unique committed action for the exact retained transaction.")}const action=listed.actions[0];if(!["unproven","completed"].includes(action.status)){return fail2("wallet_commit_unverified",`The wallet action is ${action.status}; commit and network acceptance remain unverified. Do not retry it.`)}if(!action.isOutgoing||action.version!==tx.version||action.lockTime!==tx.lockTime||!Array.isArray(action.labels)||!action.labels.includes(label.toLowerCase())||!Array.isArray(action.inputs)||action.inputs.length!==tx.inputs.length||new Set(action.inputs.map((input)=>input.sourceOutpoint)).size!==tx.inputs.length||Array.from(action.inputs).some((input)=>{const expected=tx.inputs.find((candidate)=>`${candidate.sourceTXID}.${candidate.sourceOutputIndex}`===input.sourceOutpoint);return!expected||input.sequenceNumber!==expected.sequence||input.sourceSatoshis!==expected.sourceTransaction?.outputs[expected.sourceOutputIndex]?.satoshis})||!Array.isArray(action.outputs)||!action.outputs.length||Array.from(action.outputs).some((output)=>{if(!output||!Number.isSafeInteger(output.outputIndex)||output.outputIndex<0)return true;const expected=tx.outputs[output.outputIndex];return!expected||output.satoshis!==expected.satoshis||output.lockingScript!==expected.lockingScript.toHex()})){return fail2("wallet_evidence_conflict","Wallet action inputs or outputs conflict with the retained signed transaction.")}return{ok:true,txid:tx.id("hex"),atomicBeef:tx.toAtomicBEEFUint8Array(true),walletStatus:action.status}}catch{return fail2("wallet_commit_unverified","Exact wallet filing could not be verified. Do not repeat the spend.")}}async function readWalletLocks(actionContext,page={}){if(!actionContext.services){return emptyWalletLockSummary("error","Wallet services are unavailable for lock discovery.",new Date().toISOString())}try{const maximum=Math.min(page.limit??LOCK_DISCOVERY_LIMIT,LOCK_DISCOVERY_LIMIT);const offset=page.offset??0;if(!Number.isSafeInteger(maximum)||maximum<1||!Number.isSafeInteger(offset)||offset<0)throw Error("Invalid lock page.");const[{listLocks},currentHeight]=await Promise.all([import("@1sat/actions"),actionContext.services.chaintracks.currentHeight()]);const outputs=[];let totalOutputs;while(outputs.length<maximum){const limit=Math.min(LOCK_DISCOVERY_PAGE_LIMIT,maximum-outputs.length);const listed=await listLocks.execute(actionContext,{include:"locking scripts",includeTags:true,includeCustomInstructions:true,limit,offset:offset+outputs.length});if(!Array.isArray(listed.outputs)||listed.outputs.length>limit){throw new Error("The wallet returned an invalid lock page.")}if(listed.totalOutputs!==undefined){if(!Number.isSafeInteger(listed.totalOutputs)||listed.totalOutputs<0){throw new Error("Lock discovery returned an invalid total output count.")}totalOutputs=Math.max(totalOutputs??0,listed.totalOutputs)}outputs.push(...listed.outputs);if(totalOutputs!==undefined&&offset+outputs.length>=totalOutputs)break;if(!listed.outputs.length||totalOutputs===undefined&&listed.outputs.length<limit)break}const summary=await summarizeWalletLocks(outputs,{currentHeight,mainnet:actionContext.chain==="main",totalOutputs,limit:maximum,offset,derivePublicKey:async(request)=>await actionContext.wallet.getPublicKey({protocolID:request.protocolID,keyID:request.keyID,counterparty:request.counterparty,forSelf:request.forSelf})});return{...summary,...page.limit!==undefined||page.offset!==undefined?{page:{offset,limit:maximum,returned:outputs.length,...totalOutputs!==undefined?{totalOutputs}:{},nextOffset:outputs.length&&outputs.length>=maximum&&(totalOutputs===undefined||offset+outputs.length<totalOutputs)?offset+outputs.length:null}}:{}}}catch(error){return emptyWalletLockSummary("error",error instanceof Error?error.message:"Lock discovery failed.",new Date().toISOString())}}var AGENT_LOCK_LIMIT=100;var schema="mapapp-agent-lock-reclaim-v1";var marker=(id)=>`agent-lock-reclaim:${id}`;var label=(id)=>`mapapp lock reclaim ${id}`;function createAgentLockExecutor(options){const binding=Object.freeze({...options.binding}),deployment=new URL(options.deployment).origin;if(!options.store.updateDraft||!options.store.persistEvidence)throw Error("agent_executor_configuration_invalid");const wallet=options.context.wallet;const inspector=createAgentWalletConnectionInspector({wallet,binding});let busy=false;const blocked=(reason)=>({kind:"blocked",reason});async function run(caller,work){if(busy)return blocked("execution_in_progress");busy=true;try{const state=await inspector.inspect(caller);return state.state==="ready"?await work():blocked(state.reason)}finally{busy=false}}function prepared(record){const draft=record.draft;if(draft?.schema!==schema)return null;if(record.reference.intentId!==marker(draft.operationId)||draft.deployment!==deployment||JSON.stringify(draft.connection)!==JSON.stringify(binding)||!["prepared","attempt_started"].includes(draft.phase)||!validIds(draft.outputs?.map((output)=>output.id)))throw Error("recovery_binding_conflict");return draft}function matching(draft,tx){return draft.outputs.every((output)=>tx.inputs.filter((input)=>`${input.sourceTXID??input.sourceTransaction?.id("hex")}.${input.sourceOutputIndex}`===output.outpoint&&input.sequence!==undefined&&input.sequence!==4294967295).length===1)&&tx.lockTime>=Math.max(...draft.outputs.map((output)=>output.unlockHeight))}function result(kind,draft,evidence){const tx=evidence?Transaction3.fromAtomicBEEF(evidence.atomicBeef):null;const inputValues=tx?.inputs.map((input)=>input.sourceTransaction?.outputs[input.sourceOutputIndex]?.satoshis);const fee=tx&&inputValues?.every((value)=>Number.isSafeInteger(value))?inputValues.reduce((sum,value)=>sum+value,0)-tx.outputs.reduce((sum,output)=>sum+(output.satoshis??0),0):null;const selectedSats=draft.outputs.reduce((sum,output)=>sum+output.satoshis,0);return{kind,operationId:draft.operationId,phase:draft.phase,outputs:draft.outputs,selectedSats,reclaimedSats:evidence&&draft.relay?.accepted?selectedSats:null,feeSats:fee,...evidence?{txid:evidence.txid}:{},...draft.relay?{relay:draft.relay}:{}}}async function recover(draft,record){if(draft.phase==="prepared")return blocked("operation_not_started");try{let evidence=record.returnedEvidence;if(!evidence&&options.recoverEvidence){const history=await wallet.listActions({labels:[label(draft.operationId)],labelQueryMode:"all",limit:2});const txid=history.totalActions===1&&history.actions.length===1?history.actions[0]?.txid:undefined;if(txid){const bytes=await options.recoverEvidence(txid),tx2=Transaction3.fromBEEF(bytes,txid);if(tx2.id("hex")!==txid||!matching(draft,tx2))throw Error("lock_evidence_mismatch");await options.store.persistEvidence(marker(draft.operationId),txid,tx2.toAtomicBEEFUint8Array(true));evidence=(await options.store.list()).find((row)=>row.reference.intentId===marker(draft.operationId))?.returnedEvidence}}if(!evidence)return{kind:"recovery_required",operationId:draft.operationId,reason:"original_lock_evidence_unavailable"};const tx=Transaction3.fromAtomicBEEF(evidence.atomicBeef);if(evidence.originator!==binding.originator||tx.id("hex")!==evidence.txid||!matching(draft,tx))return blocked("lock_evidence_mismatch");const filed=await verifyWalletActionEvidence(wallet,tx,label(draft.operationId));if(!filed.ok)return{kind:"recovery_required",operationId:draft.operationId,reason:filed.code};const relay=await options.relay(evidence.txid,Uint8Array.from(evidence.atomicBeef));const next={...draft,relay:{accepted:relay.accepted,status:relay.relayStatus}};await options.store.updateDraft(marker(draft.operationId),next);return result("reconciled",next,evidence)}catch{return{kind:"recovery_required",operationId:draft.operationId,reason:"original_lock_evidence_unavailable"}}}return{list:(caller,page={})=>run(caller,async()=>{const locks=await readWalletLocks(options.context,{limit:Math.min(page.limit??AGENT_LOCK_LIMIT,AGENT_LOCK_LIMIT),offset:page.offset});return{kind:"locks",locks:{...locks,message:null}}}),prepare:(caller,request)=>run(caller,async()=>{if(!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/u.test(request.operationId)||!validIds(request.ids))return blocked("lock_selection_invalid");const records=await options.store.list(),original=records.find((record)=>record.reference.clientIntentId===request.operationId);if(original){const draft2=prepared(original);if(!draft2||JSON.stringify(draft2.outputs.map((output)=>output.id).sort())!==JSON.stringify([...request.ids].sort()))return blocked("operation_input_conflict");return draft2.phase==="prepared"?result("prepared",draft2):blocked("operation_already_started")}const selected=await inspectSelectedLocks(options.context,request.ids).catch(()=>null);if(!selected||"error"in selected)return blocked("lock_selection_invalid");if(selected.outputs.some((output)=>output.state!=="matured"))return blocked("locks_not_matured");const draft={schema,operationId:request.operationId,connection:binding,deployment,outputs:selected.outputs,phase:"prepared"};await options.store.persistReference({intentId:marker(request.operationId),clientIntentId:request.operationId,nonce:marker(request.operationId),correlationTag:`intent:${marker(request.operationId)}`},draft);return result("prepared",draft)}),execute:(caller,operationId,signal)=>run(caller,async()=>{const record=(await options.store.list()).find((row)=>row.reference.intentId===marker(operationId)),draft=record&&prepared(record);if(!record||!draft)return blocked("operation_not_prepared");if(draft.phase==="attempt_started")return recover(draft,record);if(signal?.aborted)return blocked("request_cancelled");const selected=await inspectSelectedLocks(options.context,draft.outputs.map((output)=>output.id)).catch(()=>null);if(!selected||"error"in selected||JSON.stringify(selected.outputs)!==JSON.stringify(draft.outputs))return blocked("lock_selection_changed");const attempted={...draft,phase:"attempt_started"};await options.store.updateDraft(marker(operationId),attempted);try{const returned=await executeBoundedLockUnlock(options.context,draft.outputs.map((output)=>output.id),()=>{if(signal?.aborted)throw Error("request_cancelled")},{labels:[label(operationId)],expectedOutpoints:draft.outputs.map((output)=>output.outpoint)});const exact=normalizePaidPostActionOutcome("agent-wallet-node",returned);if(exact.kind!=="creation_evidence"||exact.anomaly)return{kind:"recovery_required",operationId,reason:"original_lock_evidence_unavailable"};await options.store.persistEvidence(marker(operationId),exact.txid,exact.atomicBeef);const current=(await options.store.list()).find((row)=>row.reference.intentId===marker(operationId));const recovered=await recover(attempted,current);return recovered.kind==="reconciled"?{...recovered,kind:"execution"}:recovered}catch{return{kind:"recovery_required",operationId,reason:"original_lock_evidence_unavailable"}}}),status:(caller,operationId)=>run(caller,async()=>{const record=(await options.store.list()).find((row)=>row.reference.intentId===marker(operationId)),draft=record&&prepared(record);return record&&draft?result("status",draft,record.returnedEvidence):blocked("operation_not_prepared")}),reconcile:(caller,operationId)=>run(caller,async()=>{const record=(await options.store.list()).find((row)=>row.reference.intentId===marker(operationId)),draft=record&&prepared(record);return record&&draft?recover(draft,record):blocked("operation_not_prepared")})}}function validIds(ids){return Array.isArray(ids)&&ids.length>0&&ids.length<=AGENT_LOCK_LIMIT&&new Set(ids).size===ids.length&&ids.every((id)=>typeof id==="string"&&id.length>0&&id.length<300)}import{Hash,Utils as Utils2}from"@bsv/sdk";var MESSAGING_IDENTITY_VERSION="mapapp-messaging-identity-v1";var MESSAGING_IDENTITY_MUTATION_VERSION="mapapp-messaging-identity-mutation-v1";var MAPAPP_MESSAGE_VERSION="mapapp-message-v1";var MAPAPP_MESSAGE_BOX_NAME="mapapp-messaging-v1";var MESSAGEBOX_PROTOCOL=[1,"messagebox"];var MESSAGEBOX_KEY_ID="1";var DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES=8*1024;var MAPAPP_MESSAGE_ID_MAX_BYTES=256;function serializeMessagingIdentityMutationV1(input){const mutation=assertMessagingIdentityMutationV1(input);return new TextEncoder().encode(JSON.stringify({version:mutation.version,operation:mutation.operation,bapId:mutation.bapId,walletIdentityKey:mutation.walletIdentityKey,messageBoxHost:mutation.messageBoxHost,deployment:mutation.deployment,canonicalOrigin:mutation.canonicalOrigin,network:mutation.network,expectedProfileOutpoint:mutation.expectedProfileOutpoint,expectedEvidenceHash:mutation.expectedEvidenceHash,acceptedSequence:mutation.acceptedSequence,projectionVersion:mutation.projectionVersion,clientOperationId:mutation.clientOperationId}))}function serializeMapAppMessageV1(input,maxPlaintextBytes=DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES){const message=assertMapAppMessageV1(input,maxPlaintextBytes);return JSON.stringify({version:message.version,messageId:message.messageId,senderIdentityKey:message.senderIdentityKey,recipientIdentityKey:message.recipientIdentityKey,conversationId:message.conversationId,sentAt:message.sentAt,text:message.text})}function conversationIdForIdentityKeys(first,second){assertCompressedIdentityKey(first,"first identity key");assertCompressedIdentityKey(second,"second identity key");if(first.toLowerCase()===second.toLowerCase())throw new TypeError("Self-messaging is not allowed.");const[left,right]=[first.toLowerCase(),second.toLowerCase()].sort();return Utils2.toHex(Hash.sha256(Array.from(new TextEncoder().encode(`mapapp-messaging/conversation/v1\\0${left}\\0${right}`))))}function assertMapAppMessageV1(value,maxPlaintextBytes=DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES){const record=strictRecord(value,["version","messageId","senderIdentityKey","recipientIdentityKey","conversationId","sentAt","text"],"MapAppMessageV1");if(record.version!==MAPAPP_MESSAGE_VERSION)throw new TypeError("Unsupported MapApp message version.");const messageId=stringField(record,"messageId");if(messageId.trim()===""||new TextEncoder().encode(messageId).byteLength>MAPAPP_MESSAGE_ID_MAX_BYTES)throw new TypeError("messageId must be a bounded non-empty string.");assertCanonicalIsoTimestamp(stringField(record,"sentAt"),"sentAt");const senderIdentityKey=stringField(record,"senderIdentityKey");const recipientIdentityKey=stringField(record,"recipientIdentityKey");assertCompressedIdentityKey(senderIdentityKey,"sender identity key");assertCompressedIdentityKey(recipientIdentityKey,"recipient identity key");if(senderIdentityKey.toLowerCase()===recipientIdentityKey.toLowerCase())throw new TypeError("Self-messaging is not allowed.");const expectedConversationId=conversationIdForIdentityKeys(senderIdentityKey,recipientIdentityKey);if(stringField(record,"conversationId")!==expectedConversationId)throw new TypeError("Message conversation ID does not match its participants.");if(!Number.isSafeInteger(maxPlaintextBytes)||maxPlaintextBytes<=0)throw new TypeError("Plaintext maximum must be a positive safe integer.");const text=stringField(record,"text");if(text.trim()==="")throw new TypeError("Message text must not be blank.");if(new TextEncoder().encode(text).byteLength>maxPlaintextBytes)throw new RangeError("Message text exceeds the plaintext maximum.");return record}function assertMessagingIdentityMutationV1(value){const record=strictRecord(value,["version","operation","bapId","walletIdentityKey","messageBoxHost","deployment","canonicalOrigin","network","expectedProfileOutpoint","expectedEvidenceHash","acceptedSequence","projectionVersion","clientOperationId"],"MessagingIdentityMutationV1");if(record.version!==MESSAGING_IDENTITY_MUTATION_VERSION)throw new TypeError("Unsupported messaging identity mutation version.");if(record.operation!=="register"&&record.operation!=="rotate"&&record.operation!=="revoke")throw new TypeError("Unsupported messaging identity operation.");for(const key of["bapId","messageBoxHost","deployment","canonicalOrigin","clientOperationId"])assertNonEmptyString(record[key],key);assertCompressedIdentityKey(stringField(record,"walletIdentityKey"),"wallet identity key");if(record.network!=="mainnet"&&record.network!=="testnet")throw new TypeError("Unsupported messaging network.");assertProfileEvidenceGroup(record);assertHttpsUrl(stringField(record,"messageBoxHost"),"messageBoxHost");assertHttpsUrl(stringField(record,"canonicalOrigin"),"canonicalOrigin");return record}function assertMessagingIdentityV1(value){const record=strictRecord(value,["version","bapId","walletIdentityKey","messageBoxHost","deployment","canonicalOrigin","network","expectedProfileOutpoint","expectedEvidenceHash","acceptedSequence","projectionVersion"],"MessagingIdentityV1");if(record.version!==MESSAGING_IDENTITY_VERSION)throw new TypeError("Unsupported messaging identity version.");for(const key of["bapId","messageBoxHost","deployment","canonicalOrigin"])assertNonEmptyString(record[key],key);assertCompressedIdentityKey(stringField(record,"walletIdentityKey"),"wallet identity key");if(record.network!=="mainnet"&&record.network!=="testnet")throw new TypeError("Unsupported messaging network.");assertProfileEvidenceGroup(record);assertHttpsUrl(stringField(record,"messageBoxHost"),"messageBoxHost");assertHttpsUrl(stringField(record,"canonicalOrigin"),"canonicalOrigin");return record}function assertCompressedIdentityKey(value,field="identity key"){if(!/^(02|03)[0-9a-fA-F]{64}$/.test(value))throw new TypeError(`${field} must be a compressed public key.`)}function strictRecord(value,keys,name){if(!value||typeof value!=="object"||Array.isArray(value))throw new TypeError(`${name} must be an object.`);const record=value;if(Object.keys(record).length!==keys.length||keys.some((key)=>!(key in record)))throw new TypeError(`${name} has unsupported or missing fields.`);return record}function stringField(record,key){const value=record[key];if(typeof value!=="string")throw new TypeError(`${key} must be a string.`);return value}function numberField(record,key){const value=record[key];if(typeof value!=="number"||!Number.isSafeInteger(value))throw new TypeError(`${key} must be a non-negative safe integer.`);return value}function assertProfileEvidenceGroup(record){const fields=[record.expectedProfileOutpoint,record.expectedEvidenceHash,record.acceptedSequence,record.projectionVersion];if(fields.every((value)=>value===null))return;if(fields.some((value)=>value===null))throw new TypeError("Profile evidence must be entirely present or absent.");assertNonEmptyString(record.expectedProfileOutpoint,"expectedProfileOutpoint");assertNonEmptyString(record.expectedEvidenceHash,"expectedEvidenceHash");if(numberField(record,"acceptedSequence")<1)throw new TypeError("acceptedSequence must be positive.");if(numberField(record,"projectionVersion")<0)throw new TypeError("projectionVersion must be non-negative.")}function assertNonEmptyString(value,field){if(typeof value!=="string"||value.trim()==="")throw new TypeError(`${field} must be a non-empty string.`)}function assertHttpsUrl(value,field){try{const parsed=new URL(String(value));if(parsed.protocol!=="https:"||parsed.username||parsed.password||parsed.pathname!=="/"||parsed.search||parsed.hash)throw new Error}catch{throw new TypeError(`${field} must be an HTTPS origin without a path.`)}}function assertCanonicalIsoTimestamp(value,field="timestamp"){if(!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)||!Number.isFinite(Date.parse(value))||new Date(value).toISOString()!==value)throw new TypeError(`${field} must be a canonical ISO-8601 UTC timestamp.`)}
|
|
2
|
+
import{normalizePaidPostActionOutcome}from"./chunk-e6y2yzbj.js";import{__require}from"./chunk-btwmey1h.js";import{HTTPWalletJSON,PublicKey}from"@bsv/sdk";var AGENT_WALLET_CONNECTION_READS=Object.freeze(["isAuthenticated","getNetwork","getVersion","getPublicKey"]);class AgentWalletConnectionConfigurationError extends Error{code="invalid_agent_wallet_connection_configuration";constructor(){super("The trusted agent wallet connection configuration is invalid.");this.name="AgentWalletConnectionConfigurationError"}}var DEFAULT_TIMEOUT_MS=5000;var MAX_TIMEOUT_MS=30000;var READ_TIMEOUT=Symbol("agent-wallet-read-timeout");function createAgentWalletConnectionInspector(options){const binding=Object.freeze({...options.binding});const timeoutMs=options.timeoutMs??DEFAULT_TIMEOUT_MS;validateConfiguration(binding,timeoutMs);const wallet=options.wallet;const captured=new Map;for(const method of AGENT_WALLET_CONNECTION_READS){try{const candidate=wallet?.[method];if(typeof candidate==="function")captured.set(method,candidate)}catch{}}let inspectionInProgress=false;let outstandingRead=null;function sameProviderBinding(){try{return AGENT_WALLET_CONNECTION_READS.every((method)=>wallet[method]===captured.get(method))}catch{return false}}return{async inspect(authenticatedCallerId){const reads=AGENT_WALLET_CONNECTION_READS.map((method)=>({method,state:"not_called"}));let versionObserved=false;const result=(state,reason)=>({schema:"mapapp-agent-wallet-connection-v1",connectionId:binding.connectionId,route:binding.route,state,reason,wallet:state==="ready"?{identityKey:binding.expectedIdentityKey,network:binding.expectedNetwork}:null,versionObserved,authority:{declared:binding.declaredAuthority,enforcement:"unqualified"},capabilities:{connectionRead:state==="ready"?"observed":"blocked",publicAction:"unqualified",privateMessage:"unqualified"},reads:reads.map((read)=>({...read}))});if(authenticatedCallerId!==binding.callerId)return result("denied","caller_mismatch");if(inspectionInProgress||outstandingRead!==null)return result("unavailable","read_in_progress");if(captured.size!==AGENT_WALLET_CONNECTION_READS.length)return result("unavailable","required_method_missing");if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");inspectionInProgress=true;const deadline=performance.now()+timeoutMs;try{for(const read of reads){if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");if(performance.now()>=deadline)return result("unavailable","read_timeout");const callable=captured.get(read.method);const args=read.method==="getPublicKey"?{identityKey:true,seekPermission:false}:{};const pending=Promise.resolve().then(()=>{if(performance.now()>=deadline)throw READ_TIMEOUT;return callable.call(wallet,args,binding.originator)});outstandingRead=pending;const clearOutstandingRead=()=>{if(outstandingRead===pending)outstandingRead=null};pending.then(clearOutstandingRead,clearOutstandingRead);let value;try{value=await beforeDeadline(pending,deadline)}catch(error){read.state=error===READ_TIMEOUT?"timed_out":"failed";if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");if(error===READ_TIMEOUT)return result("unavailable","read_timeout");if(providerErrorCode(error)==="ERR_WALLET_LOCKED")return result("locked","wallet_unauthenticated");if(providerErrorCode(error)==="ERR_WALLET_UNAUTHENTICATED")return result("unauthenticated","wallet_unauthenticated");if(providerErrorCode(error)==="ERR_WALLET_ORIGIN_REFUSED")return result("denied","origin_refused");if(providerErrorCode(error)==="ERR_METHOD_NOT_SUPPORTED")return result("unavailable","required_method_missing");return isPermissionDenied(error)?result("denied","permission_denied"):result("unavailable","read_failed")}if(!sameProviderBinding())return result("binding_changed","provider_binding_changed");read.state="observed";try{if(!isRecord(value))throw new Error;if(value.isError===true){read.state="failed";return isPermissionDenied(value)?result("denied","permission_denied"):result("unavailable","read_failed")}switch(read.method){case"isAuthenticated":if(value.authenticated===false)return result("unauthenticated","wallet_unauthenticated");if(value.authenticated!==true)throw new Error;break;case"getNetwork":if(value.network!=="mainnet"&&value.network!=="testnet")throw new Error;if(value.network!==binding.expectedNetwork)return result("binding_changed","network_binding_changed");break;case"getVersion":versionObserved=typeof value.version==="string";break;case"getPublicKey":if(!validIdentity(value.publicKey))throw new Error;if(value.publicKey!==binding.expectedIdentityKey)return result("binding_changed","identity_binding_changed");break}}catch{read.state="failed";return result("unavailable","invalid_read_response")}}return result("ready","connection_reads_observed")}finally{inspectionInProgress=false}}}}async function beforeDeadline(pending,deadline){let timer;try{const value=await Promise.race([pending,new Promise((_,reject)=>{timer=setTimeout(()=>reject(READ_TIMEOUT),Math.max(0,deadline-performance.now()))})]);if(performance.now()>=deadline)throw READ_TIMEOUT;return value}finally{if(timer!==undefined)clearTimeout(timer)}}function isPermissionDenied(error){try{return isRecord(error)&&error.code==="ERR_PERMISSION_DENIED"}catch{return false}}function providerErrorCode(error){try{return isRecord(error)?error.code:undefined}catch{return}}function validIdentity(value){if(typeof value!=="string"||!/^(02|03)[0-9a-f]{64}$/.test(value))return false;try{return PublicKey.fromString(value).toString()===value}catch{return false}}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function trustedHTTPEndpoint(endpoint){try{if(typeof endpoint!=="string"||endpoint.includes("?")||endpoint.includes("#"))throw new Error;const url=new URL(endpoint);const localHTTP=url.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(url.hostname);if(url.username||url.password||url.protocol!=="https:"&&!localHTTP)throw new Error;return url.href.replace(/\/+$/,"")}catch{throw new AgentWalletConnectionConfigurationError}}function validateConfiguration(binding,timeoutMs){const identifier=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;const domain=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;if(typeof binding.connectionId!=="string"||!identifier.test(binding.connectionId)||typeof binding.callerId!=="string"||!identifier.test(binding.callerId)||typeof binding.originator!=="string"||binding.originator.length>=250||binding.originator.split(".").length<2||!binding.originator.split(".").every((label)=>domain.test(label))||!validIdentity(binding.expectedIdentityKey)||!["mainnet","testnet"].includes(binding.expectedNetwork)||!["existing_brc100","agent_environment"].includes(binding.route)||!["provider","isolated_stock_client","full_root_authority"].includes(binding.declaredAuthority)||!Number.isInteger(timeoutMs)||timeoutMs<=0||timeoutMs>MAX_TIMEOUT_MS){throw new AgentWalletConnectionConfigurationError}}var POST_GEOHASH_MIN_PRECISION=8;var POST_GEOHASH_MAX_PRECISION=16;var POST_GEOHASH_DEFAULT_PRECISION=9;var POST_GEOHASH_PATTERN=/^[0123456789bcdefghjkmnpqrstuvwxyz]{8,16}$/;var BASE32="0123456789bcdefghjkmnpqrstuvwxyz";function encodeGeohash(lat,lng,precision=6){const safePrecision=Math.max(4,Math.min(16,Math.trunc(precision)));const latRange=[-90,90];const lngRange=[-180,180];const bits=[16,8,4,2,1];let isEven=true;let bit=0;let ch=0;let geohash="";const safeLat=clampFinite(lat,-90,90);const safeLng=clampFinite(lng,-180,180);while(geohash.length<safePrecision){if(isEven){const mid=(lngRange[0]+lngRange[1])/2;if(safeLng>=mid){ch|=bits[bit]??0;lngRange[0]=mid}else{lngRange[1]=mid}}else{const mid=(latRange[0]+latRange[1])/2;if(safeLat>=mid){ch|=bits[bit]??0;latRange[0]=mid}else{latRange[1]=mid}}isEven=!isEven;if(bit<4){bit+=1}else{geohash+=BASE32[ch]??"0";bit=0;ch=0}}return geohash}function geohashBounds(geohash){const safeGeohash=geohash.trim().toLowerCase();if(!safeGeohash)return null;const latRange=[-90,90];const lngRange=[-180,180];let isEven=true;for(const character of safeGeohash){const value=BASE32.indexOf(character);if(value<0)return null;for(const mask of[16,8,4,2,1]){if(isEven){bisectRange(lngRange,(value&mask)!==0)}else{bisectRange(latRange,(value&mask)!==0)}isEven=!isEven}}return{west:lngRange[0],south:latRange[0],east:lngRange[1],north:latRange[1]}}function bisectRange(range,useUpperHalf){const mid=(range[0]+range[1])/2;if(useUpperHalf){range[0]=mid}else{range[1]=mid}}function clampFinite(value,min,max){if(value===Number.POSITIVE_INFINITY)return max;if(value===Number.NEGATIVE_INFINITY)return min;if(!Number.isFinite(value))return min;return Math.min(max,Math.max(min,value))}var MEDIA_RELAY_SAFE_MAX_BYTES=99*1024;function readWebpDimensions(bytes){if(bytes.length<20||text4(bytes,0)!=="RIFF"||text4(bytes,8)!=="WEBP"||u32(bytes,4)+8!==bytes.length)return null;let offset=12;let extended=null;let image=null;while(offset<bytes.length){if(offset+8>bytes.length)return null;const kind=text4(bytes,offset);const length=u32(bytes,offset+4);const payload=offset+8;const end=payload+length;const paddedEnd=end+(length&1);if(end>bytes.length||paddedEnd>bytes.length)return null;if(!extended&&kind==="VP8X"){if(length!==10)return null;extended={width:1+u24(bytes,payload+4),height:1+u24(bytes,payload+7)}}else if(!image&&kind==="VP8 "){if(length<10||bytes[payload+3]!==157||bytes[payload+4]!==1||bytes[payload+5]!==42)return null;image={width:(bytes[payload+6]|bytes[payload+7]<<8)&16383,height:(bytes[payload+8]|bytes[payload+9]<<8)&16383}}else if(!image&&kind==="VP8L"){if(length<5||bytes[payload]!==47)return null;const bits=u32(bytes,payload+1);image={width:1+(bits&16383),height:1+(bits>>>14&16383)}}offset=paddedEnd}if(offset!==bytes.length||!image)return null;if(extended&&(extended.width!==image.width||extended.height!==image.height))return null;return extended??image}function text4(bytes,offset){return String.fromCharCode(...bytes.slice(offset,offset+4))}function u24(bytes,offset){return bytes[offset]|bytes[offset+1]<<8|bytes[offset+2]<<16}function u32(bytes,offset){return(bytes[offset]|bytes[offset+1]<<8|bytes[offset+2]<<16|bytes[offset+3]<<24)>>>0}var AGENT_MEDIA_MAX_BASE64_LENGTH=4*Math.ceil(MEDIA_RELAY_SAFE_MAX_BYTES/3);class AgentMediaError extends Error{code;constructor(code){super(code);this.code=code}}function fail(code){throw new AgentMediaError(code)}function validAgentMediaInput(value){if(!value||typeof value!=="object"||Array.isArray(value))return false;const media=value;return Object.keys(media).length===4&&Object.keys(media).every((key)=>["contentType","base64","byteSize","sha256"].includes(key))&&["image/webp","video/webm"].includes(media.contentType)&&typeof media.base64==="string"&&media.base64.length>0&&media.base64.length<=AGENT_MEDIA_MAX_BASE64_LENGTH&&media.base64.length%4===0&&/^[A-Za-z0-9+/]*={0,2}$/.test(media.base64)&&Number.isSafeInteger(media.byteSize)&&media.byteSize>0&&media.byteSize<=MEDIA_RELAY_SAFE_MAX_BYTES&&typeof media.sha256==="string"&&/^[0-9a-f]{64}$/.test(media.sha256)}async function inspectAgentMedia(value){if(!validAgentMediaInput(value))fail("invalid_media_input");const binary=atob(value.base64);if(btoa(binary)!==value.base64)fail("invalid_media_base64");const bytes=Uint8Array.from(binary,(character)=>character.charCodeAt(0));if(bytes.length!==value.byteSize)fail("media_size_mismatch");const hash=new Uint8Array(await crypto.subtle.digest("SHA-256",bytes.buffer));const sha256=Array.from(hash,(byte)=>byte.toString(16).padStart(2,"0")).join("");if(sha256!==value.sha256)fail("media_hash_mismatch");const dimensions=value.contentType==="image/webp"?await inspectImage(bytes):await inspectVideo(bytes);return{media:value.contentType==="image/webp"?{kind:"image",contentType:"image/webp",bytes}:{kind:"video",contentType:"video/webm",bytes},summary:{contentType:value.contentType,byteSize:bytes.length,sha256,...dimensions}}}async function inspectImage(bytes){const dimensions=readWebpDimensions(bytes);if(!dimensions)fail("invalid_media_container");if(dimensions.width<1||dimensions.height<1||dimensions.width>1024||dimensions.height>1024)fail("media_dimensions_too_large");try{const{default:decode}=await import("@jsquash/webp/decode.js");const decoded=await decode(Uint8Array.from(bytes).buffer);if(decoded.width!==dimensions.width||decoded.height!==dimensions.height)fail("invalid_media_container");return dimensions}catch{return fail("invalid_media_container")}}async function inspectVideo(bytes){const{Input,BufferSource,WEBM}=await import("mediabunny");const input=new Input({source:new BufferSource(bytes),formats:[WEBM]});let timeout;try{return await Promise.race([(async()=>{const[videos,audios,tracks]=await Promise.all([input.getVideoTracks(),input.getAudioTracks(),input.getTracks()]);if(videos.length!==1||audios.length>1||tracks.length!==videos.length+audios.length)fail("media_tracks_unsupported");const track=videos[0];const[codec,width,height,displayWidth,displayHeight,duration,stats]=await Promise.all([track.getCodec(),track.getCodedWidth(),track.getCodedHeight(),track.getDisplayWidth(),track.getDisplayHeight(),input.computeDuration(),track.computePacketStats(1)]);if(codec!=="vp8"&&codec!=="vp9")fail("media_codec_unsupported");if([width,height,displayWidth,displayHeight].some((size)=>!Number.isFinite(size)||size<1||size>512))fail("media_dimensions_too_large");if(!Number.isFinite(duration)||duration<=0||duration>30)fail("media_video_duration_invalid");if(stats.packetCount<1)fail("invalid_media_container");if(audios[0]&&!["opus","vorbis"].includes(await audios[0].getCodec()??""))fail("media_codec_unsupported");return{width,height,durationMs:Math.ceil(duration*1000)}})(),new Promise((_,reject)=>{timeout=setTimeout(()=>{input.dispose();reject(new AgentMediaError("media_inspection_timeout"))},5000)})])}catch(error){if(error instanceof AgentMediaError)throw error;return fail("invalid_media_container")}finally{clearTimeout(timeout);input.dispose()}}var MAPAPP_CATEGORY_TOKENS=["\uD83C\uDF31","\uD83D\uDCCD","\uD83E\uDDED","\uD83C\uDFA8","\uD83C\uDFB5","\uD83C\uDF7D\uFE0F","\u2615","\uD83D\uDED2","\uD83C\uDFC0","\uD83C\uDFAE","\uD83D\uDCF0","\uD83D\uDCAC","\uD83D\uDCF8","\uD83C\uDFAC","\uD83D\uDCBB","\uD83D\uDEE0\uFE0F","\uD83C\uDFE0","\uD83D\uDE97","\uD83C\uDF0A","\u26F0\uFE0F","\uD83C\uDF33","\uD83D\uDC3E","\uD83C\uDF93","\uD83C\uDFE5","\u26A0\uFE0F","\uD83C\uDF89","\uD83D\uDCBC","\uD83D\uDD2C","\u2708\uFE0F","\uD83E\uDDD8","\uD83E\uDE99","\u2764\uFE0F"];var DEFAULT_MAPAPP_CATEGORY=MAPAPP_CATEGORY_TOKENS[0];import{sendAllBsv,sendBsv}from"@1sat/actions";import{P2PKH,Transaction,Utils}from"@bsv/sdk";var MAX_DIRECT_BSV_SEND_SATOSHIS=2099999999999998;function validateDirectBsvInput(input){const address=input.to.trim();let decoded;try{decoded=Utils.fromBase58Check(address)}catch{return{ok:false,code:"bsv_address_invalid",message:"Enter a valid mainnet BSV address."}}if(decoded.data.length!==20){return{ok:false,code:"bsv_address_invalid",message:"Enter a valid mainnet P2PKH address."}}if(decoded.prefix.length!==1||decoded.prefix[0]!==0){return{ok:false,code:"bsv_address_wrong_network",message:"Direct sends require a mainnet BSV address."}}if(!("satoshis"in input))return{ok:true,address,max:true};if(!Number.isSafeInteger(input.satoshis)||input.satoshis<1||input.satoshis>MAX_DIRECT_BSV_SEND_SATOSHIS){return{ok:false,code:"bsv_amount_invalid",message:`Amount must be a whole number from 1 to ${MAX_DIRECT_BSV_SEND_SATOSHIS} satoshis.`}}return{ok:true,address,satoshis:input.satoshis}}function inspectDirectBsvEvidence(atomicBeef,address){try{const tx=Transaction.fromBEEF(atomicBeef);const script=new P2PKH().lock(address).toHex();const matching=tx.outputs.filter((output)=>output.lockingScript.toHex()===script);if(matching.length!==1)return null;const satoshis=matching[0]?.satoshis;if(typeof satoshis!=="number"||!Number.isSafeInteger(satoshis)||satoshis<1)return null;const inputSatoshis=tx.inputs.map((input)=>input.sourceTransaction?.outputs[input.sourceOutputIndex]?.satoshis);const fee=inputSatoshis.every((value)=>Number.isSafeInteger(value))?inputSatoshis.reduce((sum,value)=>sum+(value??0),0)-tx.outputs.reduce((sum,output)=>sum+(output.satoshis??0),0):null;return{satoshis,fee:fee!==null&&Number.isSafeInteger(fee)&&fee>=0?fee:null}}catch{return null}}import{Transaction as Transaction3}from"@bsv/sdk";import{executeTrackedAction}from"@1sat/actions";import{LOCK_BASKET}from"@1sat/types";import{Beef}from"@bsv/sdk";import{Lock}from"@1sat/templates";import{PublicKey as PublicKey2,Script}from"@bsv/sdk";var LOCK_DISCOVERY_PAGE_LIMIT=1000;var LOCK_DISCOVERY_LIMIT=1e4;var DEFAULT_CHECKED_AT=()=>new Date().toISOString();function parseLockCustomInstructions(value){if(typeof value!=="string"||!value.trim())return null;let parsed;try{parsed=JSON.parse(value)}catch{return null}if(!isRecord2(parsed))return null;const rawProtocol=parsed.protocolID;if(!Array.isArray(rawProtocol)||rawProtocol.length!==2)return null;const securityLevel=rawProtocol[0];const protocolName=rawProtocol[1];if(!isSafeInteger(securityLevel)||securityLevel<0||securityLevel>2)return null;if(typeof protocolName!=="string"||!hasByteLength(protocolName,5,400)||protocolName.trim()!==protocolName){return null}const keyID=parsed.keyID;if(typeof keyID!=="string"||!hasByteLength(keyID,1,800)||keyID.trim()!==keyID||/\s/.test(keyID)){return null}let counterparty="self";if(parsed.counterparty!==undefined){if(typeof parsed.counterparty!=="string"||!hasByteLength(parsed.counterparty,1,800)||parsed.counterparty.trim()!==parsed.counterparty||/\s/.test(parsed.counterparty)){return null}counterparty=parsed.counterparty}if(parsed.forSelf!==undefined&&parsed.forSelf!==true)return null;return{protocolID:[securityLevel,protocolName],keyID,counterparty,forSelf:true}}async function normalizeWalletLockRows(rows,options){const currentHeight=readNonNegativeSafeInteger(options.currentHeight);const empty={currentHeight,outputs:[],legacyOutputs:[],incompatibleOutputs:[],complete:false,paginationComplete:false,derivationUnavailable:false,derivationFailed:false,aggregateSafe:true,message:null};if(currentHeight===null){return{...empty,message:"Current chain height is unavailable."}}if(!Array.isArray(rows)){return{...empty,message:"The wallet returned an invalid lock list."}}const pagination=readPagination(options);const paginationComplete=assessPagination(rows.length,pagination);const result={...empty,complete:paginationComplete.complete,paginationComplete:paginationComplete.complete,message:paginationComplete.message};const seenOutpoints=new Set;const duplicateIds=new Set;const idOwners=new Map;const keyChecks=new Map;const decode=options.decodeLock??((script,mainnet2)=>Lock.decode(script,mainnet2));const mainnet=options.mainnet!==false;for(const rawRow of rows){const record=isRecord2(rawRow)?rawRow:null;if(!record){result.incompatibleOutputs.push({outpoint:null,reason:"row-not-object"});continue}const outpoint=readOutpoint(record.outpoint);if(!outpoint){result.incompatibleOutputs.push({outpoint:null,reason:"invalid-outpoint"});continue}if(seenOutpoints.has(outpoint)){result.incompatibleOutputs.push({outpoint,reason:"duplicate-outpoint"});continue}seenOutpoints.add(outpoint);const satoshis=readPositiveSafeInteger(record.satoshis);if(satoshis===null){result.incompatibleOutputs.push({outpoint,reason:"invalid-satoshis"});continue}const tags=readTags(record.tags);if(!tags.ok){result.incompatibleOutputs.push({outpoint,reason:"invalid-tags"});continue}const until=readUntilTag(tags.tags);if(until.kind==="invalid"){result.incompatibleOutputs.push({outpoint,reason:until.reason});continue}const id=readIdTag(tags.tags);if(id.kind==="invalid"){result.incompatibleOutputs.push({outpoint,reason:id.reason});continue}if(until.kind==="valid"&&id.kind==="valid"){if(duplicateIds.has(id.value)){result.incompatibleOutputs.push({outpoint,reason:"duplicate-id"});continue}const owner2=idOwners.get(id.value);if(owner2){duplicateIds.add(id.value);if(owner2.output){const priorIndex=result.outputs.findIndex((output2)=>output2.id===id.value);if(priorIndex>=0)result.outputs.splice(priorIndex,1)}if(!owner2.incompatible){result.incompatibleOutputs.push({outpoint:owner2.outpoint,reason:"duplicate-id"});owner2.incompatible=true}result.incompatibleOutputs.push({outpoint,reason:"duplicate-id"});continue}idOwners.set(id.value,{outpoint,output:null,incompatible:false})}const script=readScript(record.lockingScript);if(!script){result.incompatibleOutputs.push({outpoint,reason:"invalid-locking-script"});continue}let decoded;try{decoded=decode(script,mainnet)}catch{decoded=null}const decodedHeight=decoded?readPositiveSafeInteger(decoded.until):null;const decodedAddress=decoded&&typeof decoded.address==="string"&&decoded.address.trim()===decoded.address&&decoded.address.length>0?decoded.address:null;if(!decoded||decodedHeight===null||!decodedAddress){result.incompatibleOutputs.push({outpoint,reason:"not-a-valid-lock-script"});continue}if(until.kind==="valid"&&until.value!==decodedHeight){result.incompatibleOutputs.push({outpoint,reason:"tag-script-height-mismatch"});continue}const metadata=parseLockCustomInstructions(record.customInstructions);if(!metadata){result.incompatibleOutputs.push({outpoint,reason:"invalid-custom-instructions"});continue}const tupleKey=JSON.stringify([metadata.protocolID,metadata.keyID,metadata.counterparty]);let derivedAddressPromise=keyChecks.get(tupleKey);if(!derivedAddressPromise){derivedAddressPromise=deriveAddress(metadata,options,result);keyChecks.set(tupleKey,derivedAddressPromise)}const derivedAddress=await derivedAddressPromise;if(!derivedAddress){result.incompatibleOutputs.push({outpoint,reason:"lock-key-unavailable"});continue}if(derivedAddress!==decodedAddress){result.incompatibleOutputs.push({outpoint,reason:"derived-key-address-mismatch"});continue}if(until.kind==="missing"||id.kind==="missing"){const legacy={outpoint,satoshis,unlockHeight:decodedHeight,state:decodedHeight<currentHeight?"matured":"locked"};result.legacyOutputs.push(legacy);continue}const output={id:id.value,outpoint,satoshis,unlockHeight:decodedHeight,blocksRemaining:Math.max(0,decodedHeight-currentHeight),state:decodedHeight<currentHeight?"matured":"locked"};const owner=idOwners.get(id.value);if(duplicateIds.has(id.value)){result.incompatibleOutputs.push({outpoint,reason:"duplicate-id"});continue}if(owner)owner.output=output;result.outputs.push(output)}result.outputs.sort(compareLockOutputs);result.legacyOutputs.sort(compareLegacyOutputs);result.complete=paginationComplete.complete&&result.incompatibleOutputs.length===0;result.message=normalizationMessage(result,paginationComplete.message);return result}async function summarizeWalletLocks(rows,options){const checkedAt=options.checkedAt===undefined?DEFAULT_CHECKED_AT():options.checkedAt;const normalized=await normalizeWalletLockRows(rows,options);if(normalized.currentHeight===null){return{...emptyWalletLockSummary("error",normalized.message??"Current chain height is unavailable.",checkedAt)}}const sums=sumValidatedLocks(normalized.outputs,normalized.legacyOutputs);if(!sums.safe){return{...emptyWalletLockSummary("error","Validated lock totals exceed the safe integer range.",checkedAt),currentHeight:normalized.currentHeight,outputs:normalized.outputs,incompatibleOutputCount:normalized.incompatibleOutputs.length,legacyOutputCount:normalized.legacyOutputs.length,legacyLockedSats:0,complete:false}}const nextUnlockHeight=normalized.outputs.filter((output)=>output.state==="locked").reduce((next,output)=>next===null?output.unlockHeight:Math.min(next,output.unlockHeight),null);const state=normalized.derivationUnavailable?"unsupported":normalized.derivationFailed?"error":"ready";const message=state==="ready"?normalized.message:normalized.message??(state==="unsupported"?"The connected wallet does not expose the key derivation needed to inspect locks.":"The connected wallet denied or failed the lock-key derivation check.");return{state,checkedAt,currentHeight:normalized.currentHeight,recoverableLockedSats:sums.recoverable,unlockableSats:sums.unlockable,nextUnlockHeight,blocksUntilNextUnlock:nextUnlockHeight===null?null:Math.max(0,nextUnlockHeight-normalized.currentHeight),outputs:normalized.outputs,incompatibleOutputCount:normalized.incompatibleOutputs.length,legacyOutputCount:normalized.legacyOutputs.length,legacyLockedSats:sums.legacy,complete:normalized.complete,message}}function emptyWalletLockSummary(state,message=null,checkedAt=null){return{state,checkedAt,currentHeight:null,recoverableLockedSats:0,unlockableSats:0,nextUnlockHeight:null,blocksUntilNextUnlock:null,outputs:[],incompatibleOutputCount:0,legacyOutputCount:0,legacyLockedSats:0,complete:false,message}}function deriveAddress(metadata,options,result){const request=options.originator===undefined?{...metadata}:{...metadata,originator:options.originator};if(!options.deriveLockAddress&&!options.derivePublicKey){result.derivationUnavailable=true;return Promise.resolve(null)}const resolver=options.deriveLockAddress??options.derivePublicKey;return Promise.resolve().then(()=>resolver(request)).then((value)=>options.derivePublicKey&&!options.deriveLockAddress?addressFromPublicKeyResult(value):addressFromDerivationResult(value)).catch(()=>{result.derivationFailed=true;return null})}function addressFromDerivationResult(value){if(typeof value==="string"){const normalized=value.trim();if(!normalized||normalized!==value)return null;if(/^(02|03)[0-9a-f]{64}$/i.test(normalized))return publicKeyToAddress(normalized);return normalized}if(!isRecord2(value))return null;if(typeof value.address==="string"&&value.address.trim()===value.address&&value.address.length>0){const publicKeyAddress=typeof value.publicKey==="string"?publicKeyToAddress(value.publicKey):null;if(value.publicKey!==undefined&&!publicKeyAddress)return null;if(publicKeyAddress&&publicKeyAddress!==value.address)return null;return value.address}return typeof value.publicKey==="string"?publicKeyToAddress(value.publicKey):null}function addressFromPublicKeyResult(value){if(typeof value==="string")return publicKeyToAddress(value);if(isRecord2(value)&&typeof value.publicKey==="string")return publicKeyToAddress(value.publicKey);return null}function publicKeyToAddress(value){try{return PublicKey2.fromString(value).toAddress()}catch{return null}}function readScript(value){if(value instanceof Script)return value;if(typeof value!=="string"||value.length===0||value.length%2!==0||!/^[0-9a-f]+$/i.test(value))return null;try{return Script.fromHex(value)}catch{return null}}function readOutpoint(value){if(typeof value!=="string"||value.trim()!==value)return null;const match=/^([0-9a-f]{64})([._])(\d+)$/i.exec(value);if(!match)return null;const outputIndex=Number(match[3]);if(!Number.isSafeInteger(outputIndex)||outputIndex<0)return null;return`${match[1].toLowerCase()}.${outputIndex}`}function readTags(value){if(value===undefined)return{ok:true,tags:[]};if(!Array.isArray(value)||value.some((tag)=>typeof tag!=="string"))return{ok:false};return{ok:true,tags:value}}function readUntilTag(tags){const matches=tags.filter((tag)=>tag.startsWith("until:"));if(matches.length===0)return{kind:"missing"};if(matches.length!==1)return{kind:"invalid",reason:"duplicate-until-tag"};const raw=matches[0].slice("until:".length);if(!/^[1-9]\d*$/.test(raw))return{kind:"invalid",reason:"invalid-until-tag"};const value=Number(raw);return Number.isSafeInteger(value)&&value>0?{kind:"valid",value}:{kind:"invalid",reason:"unsafe-until-tag"}}function readIdTag(tags){const matches=tags.filter((tag)=>tag.startsWith("id:"));if(matches.length===0)return{kind:"missing"};if(matches.length!==1)return{kind:"invalid",reason:"duplicate-id-tag"};const value=matches[0].slice("id:".length);if(!value||value.trim()!==value||/\s/.test(value)||!hasByteLength(value,1,300)){return{kind:"invalid",reason:"invalid-id-tag"}}return{kind:"valid",value}}function readPagination(options){const nested=options.pagination??{};return{totalOutputs:options.totalOutputs!==undefined?options.totalOutputs:nested.totalOutputs,limit:options.limit!==undefined?options.limit:nested.limit,offset:options.offset!==undefined?options.offset:nested.offset,hasMore:options.hasMore!==undefined?options.hasMore:nested.hasMore,complete:options.complete!==undefined?options.complete:nested.complete}}function assessPagination(rowsLength,page){const offset=page.offset===undefined?0:readNonNegativeSafeInteger(page.offset);const limit=page.limit===undefined?null:readPositiveSafeInteger(page.limit);const total=page.totalOutputs===undefined?null:readNonNegativeSafeInteger(page.totalOutputs);let complete=true;let message=null;if(offset===null||page.limit!==undefined&&limit===null||page.totalOutputs!==undefined&&total===null||page.hasMore!==undefined&&typeof page.hasMore!=="boolean"||page.complete!==undefined&&typeof page.complete!=="boolean"){complete=false;message="Lock discovery returned invalid pagination metadata."}else if(offset>0){complete=false;message="Lock discovery returned a partial page."}else if(total!==null&&total>rowsLength){complete=false;message="Lock discovery is incomplete; the wallet reported more lock outputs than it returned."}else if(total!==null&&total<rowsLength){complete=false;message="Lock discovery returned more rows than its total output count."}else if(limit!==null&&rowsLength>=limit&&page.hasMore!==false&&total===null&&page.complete!==true){complete=false;message="Lock discovery may be truncated at the wallet page limit."}if(page.hasMore===true){complete=false;message="Lock discovery has another wallet page; totals are incomplete."}if(page.complete===false){complete=false;message=message??"Lock discovery is incomplete."}return{complete,message}}function normalizationMessage(result,paginationMessage){const parts=[];if(result.incompatibleOutputs.length>0){const count=result.incompatibleOutputs.length;parts.push(`Skipped ${count} incompatible lock output${count===1?"":"s"}.`)}if(result.legacyOutputs.length>0){const count=result.legacyOutputs.length;parts.push(`Found ${count} legacy lock output${count===1?"":"s"}; current recovery cannot unlock ${count===1?"it":"them"}.`)}if(paginationMessage)parts.push(paginationMessage);if(result.derivationUnavailable)parts.push("The connected wallet does not expose lock-key derivation.");if(result.derivationFailed)parts.push("The connected wallet denied or failed lock-key derivation.");return parts.length>0?parts.join(" "):null}function sumValidatedLocks(outputs,legacy){let recoverable=0;let unlockable=0;let legacyTotal=0;for(const output of outputs){recoverable=safeAdd(recoverable,output.satoshis);if(output.state==="matured")unlockable=safeAdd(unlockable,output.satoshis)}for(const output of legacy)legacyTotal=safeAdd(legacyTotal,output.satoshis);const safe=Number.isSafeInteger(recoverable)&&Number.isSafeInteger(unlockable)&&Number.isSafeInteger(legacyTotal);return{recoverable:safe?recoverable:0,unlockable:safe?unlockable:0,legacy:safe?legacyTotal:0,safe}}function safeAdd(left,right){const value=left+right;return Number.isSafeInteger(value)?value:Number.NaN}function compareLockOutputs(left,right){if(left.state!==right.state)return left.state==="matured"?-1:1;if(left.unlockHeight!==right.unlockHeight)return left.unlockHeight-right.unlockHeight;return left.outpoint.localeCompare(right.outpoint)}function compareLegacyOutputs(left,right){if(left.state!==right.state)return left.state==="matured"?-1:1;if(left.unlockHeight!==right.unlockHeight)return left.unlockHeight-right.unlockHeight;return left.outpoint.localeCompare(right.outpoint)}function isRecord2(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function isSafeInteger(value){return typeof value==="number"&&Number.isSafeInteger(value)}function readPositiveSafeInteger(value){return isSafeInteger(value)&&value>0?value:null}function readNonNegativeSafeInteger(value){return isSafeInteger(value)&&value>=0?value:null}function hasByteLength(value,minimum,maximum){const bytes=new TextEncoder().encode(value).byteLength;return bytes>=minimum&&bytes<=maximum}async function inspectSelectedLocks(context,ids){if(!context.services||!ids.length||ids.length>LOCK_DISCOVERY_LIMIT||new Set(ids).size!==ids.length){return{error:"invalid-lock-selection"}}const currentHeight=await context.services.chaintracks.currentHeight();const outputs=[];const beef=new Beef;while(outputs.length<ids.length){const listed=await context.wallet.listOutputs({basket:LOCK_BASKET,tags:ids.map((id)=>`id:${id}`),tagQueryMode:"any",include:"entire transactions",includeTags:true,includeCustomInstructions:true,limit:Math.min(LOCK_DISCOVERY_PAGE_LIMIT,ids.length-outputs.length),offset:outputs.length});if(listed.totalOutputs!==ids.length||!listed.outputs.length||listed.outputs.length>Math.min(LOCK_DISCOVERY_PAGE_LIMIT,ids.length-outputs.length))return{error:"lock-selection-changed"};if(listed.BEEF?.length)beef.mergeBeef(listed.BEEF);outputs.push(...listed.outputs)}for(const txid of new Set(outputs.map((output)=>output.outpoint.split(".")[0]))){if(!beef.findTxid(txid)?.tx)beef.mergeBeef(await context.services.getBeefForTxid(txid))}const inputBEEF=beef.toBinary();const rows=outputs.map((output)=>{const[txid,vout]=output.outpoint.split(".");const source=beef.findTxid(txid)?.tx?.outputs[Number(vout)];if(!source||source.satoshis!==output.satoshis)throw Error("Lock source evidence conflicts with wallet discovery.");return{...output,lockingScript:source.lockingScript.toHex()}});const validated=await summarizeWalletLocks(rows,{currentHeight,mainnet:context.chain==="main",totalOutputs:ids.length,limit:LOCK_DISCOVERY_LIMIT,offset:0,derivePublicKey:(request)=>context.wallet.getPublicKey({protocolID:request.protocolID,keyID:request.keyID,counterparty:request.counterparty,forSelf:true})});if(validated.state!=="ready"||!validated.complete||validated.outputs.length!==ids.length||validated.outputs.some((output)=>!ids.includes(output.id))){return{error:"lock-selection-changed"}}return{rows,inputBEEF,outputs:validated.outputs,currentHeight}}async function executeBoundedLockUnlock(context,ids,beforeDispatch,recovery={}){const selection=await inspectSelectedLocks(context,ids);if("error"in selection)return selection;const{rows,inputBEEF,outputs}=selection;if(outputs.some((output)=>output.state!=="matured")||recovery.expectedOutpoints&&(recovery.expectedOutpoints.length!==outputs.length||outputs.some((output)=>!recovery.expectedOutpoints.includes(output.outpoint)))){return{error:"lock-selection-changed"}}beforeDispatch?.();return executeTrackedAction(context.wallet,{description:`Unlock ${rows.length} lock(s)`,inputBEEF,...recovery.labels?.length?{labels:recovery.labels}:{},inputs:rows.map((output)=>({outpoint:output.outpoint,inputDescription:"Locked BSV",unlockingScriptLength:1205,sequenceNumber:0})),outputs:[],lockTime:Math.max(...outputs.map((output)=>output.unlockHeight)),options:{acceptDelayedBroadcast:false,returnTXIDOnly:false}},undefined,inputBEEF,undefined,{spends:rows.map((output)=>({outpoint:output.outpoint,customInstructions:output.customInstructions})),usePermissionModule:false,permissionScheme:"lock"})}import{Transaction as Transaction2}from"@bsv/sdk";async function recoverNativeActionEvidence(options){const fail2=(code,message)=>({ok:false,code,message});const{record,checkpoint}=options;const retained=record.returnedEvidence;const format=record.reference.evidenceFormat;if(!retained||!["mapapp_direct_bsv_v1","mapapp_post_v2","mapapp_social_v2","mapapp_upgrade_v2","mapapp_sponsored_v2","mapapp_bap_alias_v1"].includes(format??"")){return fail2("exact_evidence_unavailable","This native action has no retained exact evidence. Do not repeat the spend.")}if(retained.originator!==options.originator||checkpoint&&checkpoint.txid!==retained.txid){return fail2("recovery_binding_conflict","The retained evidence does not match this origin or pending native action.")}try{if(!/^[0-9a-f]{64}$/.test(retained.txid)||!Array.isArray(retained.atomicBeef)||!retained.atomicBeef.length||retained.atomicBeef.length>2*1024*1024)throw new Error;for(let index=0;index<retained.atomicBeef.length;index++){const byte=retained.atomicBeef[index];if(!Number.isInteger(byte)||byte<0||byte>255)throw new Error}const atomicBeef=Uint8Array.from(retained.atomicBeef);const tx=Transaction2.fromAtomicBEEF(atomicBeef);if(tx.id("hex")!==retained.txid)throw new Error;if(format==="mapapp_direct_bsv_v1"){const draft=record.draft;if(!draft||draft.kind!=="bsv_send"||typeof draft.to!=="string")throw new Error;const payment=inspectDirectBsvEvidence(atomicBeef,draft.to);if(!payment||draft.max!==true&&payment.satoshis!==draft.satoshis)throw new Error}if(format==="mapapp_sponsored_v2"||format==="mapapp_bap_alias_v1"){if(!options.wallet.listOutputs)return fail2("wallet_commit_unverified","The author wallet cannot inspect its internalized sponsor output.");const profile=format==="mapapp_bap_alias_v1";const draft=record.draft;if(profile&&!draft?.bapId)return fail2("recovery_binding_conflict","The retained profile has no original BAP binding.");const tags=profile?["type:alias",`bapId:${draft.bapId}`]:[record.reference.correlationTag];const listed=await options.wallet.listOutputs({basket:profile?"bap":"bsocial",tags,tagQueryMode:"all",include:"entire transactions",includeTags:true,limit:1000,offset:0});if(!listed.totalOutputs||listed.outputs.length!==listed.totalOutputs||!listed.BEEF?.length){return fail2("wallet_commit_unverified","The author wallet has no complete internalized output for this sponsor evidence.")}const restoredTx=Transaction2.fromBEEF(listed.BEEF,retained.txid);if(restoredTx.toHex()!==tx.toHex()||listed.outputs.some((output)=>{const[txid,vout]=output.outpoint.split(".");const expected=tx.outputs[Number(vout)];return txid!==retained.txid||!expected||output.satoshis!==expected.satoshis||tags.some((tag)=>!output.tags?.includes(tag.toLowerCase()))}))return fail2("wallet_evidence_conflict","Wallet basket output conflicts with retained exact evidence.");return{ok:true,txid:retained.txid,atomicBeef,walletStatus:profile?"retained wallet ALIAS":"internalized sponsor evidence"}}const label=format==="mapapp_direct_bsv_v1"?`mapapp intent ${record.reference.intentId}`:`mapapp correlation ${record.reference.correlationTag}`;const verified=await verifyWalletActionEvidence(options.wallet,tx,label);return verified.ok?{...verified,atomicBeef}:verified}catch{return fail2("exact_evidence_invalid","Exact evidence could not be verified through this wallet. The spend remains recovery-only.")}}async function verifyWalletActionEvidence(wallet,tx,label){const fail2=(code,message)=>({ok:false,code,message});try{const listed=await wallet.listActions({labels:[label],labelQueryMode:"all",includeLabels:true,includeInputs:true,includeOutputs:true,includeOutputLockingScripts:true,limit:2});if(listed.totalActions!==1||listed.actions.length!==1||listed.actions[0]?.txid!==tx.id("hex")){return fail2("wallet_commit_unverified","The wallet has no unique committed action for the exact retained transaction.")}const action=listed.actions[0];if(!["unproven","completed"].includes(action.status)){return fail2("wallet_commit_unverified",`The wallet action is ${action.status}; commit and network acceptance remain unverified. Do not retry it.`)}if(!action.isOutgoing||action.version!==tx.version||action.lockTime!==tx.lockTime||!Array.isArray(action.labels)||!action.labels.includes(label.toLowerCase())||!Array.isArray(action.inputs)||action.inputs.length!==tx.inputs.length||new Set(action.inputs.map((input)=>input.sourceOutpoint)).size!==tx.inputs.length||Array.from(action.inputs).some((input)=>{const expected=tx.inputs.find((candidate)=>`${candidate.sourceTXID}.${candidate.sourceOutputIndex}`===input.sourceOutpoint);return!expected||input.sequenceNumber!==expected.sequence||input.sourceSatoshis!==expected.sourceTransaction?.outputs[expected.sourceOutputIndex]?.satoshis})||!Array.isArray(action.outputs)||!action.outputs.length||Array.from(action.outputs).some((output)=>{if(!output||!Number.isSafeInteger(output.outputIndex)||output.outputIndex<0)return true;const expected=tx.outputs[output.outputIndex];return!expected||output.satoshis!==expected.satoshis||output.lockingScript!==expected.lockingScript.toHex()})){return fail2("wallet_evidence_conflict","Wallet action inputs or outputs conflict with the retained signed transaction.")}return{ok:true,txid:tx.id("hex"),atomicBeef:tx.toAtomicBEEFUint8Array(true),walletStatus:action.status}}catch{return fail2("wallet_commit_unverified","Exact wallet filing could not be verified. Do not repeat the spend.")}}async function readWalletLocks(actionContext,page={}){if(!actionContext.services){return emptyWalletLockSummary("error","Wallet services are unavailable for lock discovery.",new Date().toISOString())}try{const maximum=Math.min(page.limit??LOCK_DISCOVERY_LIMIT,LOCK_DISCOVERY_LIMIT);const offset=page.offset??0;if(!Number.isSafeInteger(maximum)||maximum<1||!Number.isSafeInteger(offset)||offset<0)throw Error("Invalid lock page.");const[{listLocks},currentHeight]=await Promise.all([import("@1sat/actions"),actionContext.services.chaintracks.currentHeight()]);const outputs=[];let totalOutputs;while(outputs.length<maximum){const limit=Math.min(LOCK_DISCOVERY_PAGE_LIMIT,maximum-outputs.length);const listed=await listLocks.execute(actionContext,{include:"locking scripts",includeTags:true,includeCustomInstructions:true,limit,offset:offset+outputs.length});if(!Array.isArray(listed.outputs)||listed.outputs.length>limit){throw new Error("The wallet returned an invalid lock page.")}if(listed.totalOutputs!==undefined){if(!Number.isSafeInteger(listed.totalOutputs)||listed.totalOutputs<0){throw new Error("Lock discovery returned an invalid total output count.")}totalOutputs=Math.max(totalOutputs??0,listed.totalOutputs)}outputs.push(...listed.outputs);if(totalOutputs!==undefined&&offset+outputs.length>=totalOutputs)break;if(!listed.outputs.length||totalOutputs===undefined&&listed.outputs.length<limit)break}const summary=await summarizeWalletLocks(outputs,{currentHeight,mainnet:actionContext.chain==="main",totalOutputs,limit:maximum,offset,derivePublicKey:async(request)=>await actionContext.wallet.getPublicKey({protocolID:request.protocolID,keyID:request.keyID,counterparty:request.counterparty,forSelf:request.forSelf})});return{...summary,...page.limit!==undefined||page.offset!==undefined?{page:{offset,limit:maximum,returned:outputs.length,...totalOutputs!==undefined?{totalOutputs}:{},nextOffset:outputs.length&&outputs.length>=maximum&&(totalOutputs===undefined||offset+outputs.length<totalOutputs)?offset+outputs.length:null}}:{}}}catch(error){return emptyWalletLockSummary("error",error instanceof Error?error.message:"Lock discovery failed.",new Date().toISOString())}}var AGENT_LOCK_LIMIT=100;var schema="mapapp-agent-lock-reclaim-v1";var marker=(id)=>`agent-lock-reclaim:${id}`;var label=(id)=>`mapapp lock reclaim ${id}`;function createAgentLockExecutor(options){const binding=Object.freeze({...options.binding}),deployment=new URL(options.deployment).origin;if(!options.store.updateDraft||!options.store.persistEvidence)throw Error("agent_executor_configuration_invalid");const wallet=options.context.wallet;const inspector=createAgentWalletConnectionInspector({wallet,binding});let busy=false;const blocked=(reason)=>({kind:"blocked",reason});async function run(caller,work){if(busy)return blocked("execution_in_progress");busy=true;try{const state=await inspector.inspect(caller);return state.state==="ready"?await work():blocked(state.reason)}finally{busy=false}}function prepared(record){const draft=record.draft;if(draft?.schema!==schema)return null;if(record.reference.intentId!==marker(draft.operationId)||draft.deployment!==deployment||JSON.stringify(draft.connection)!==JSON.stringify(binding)||!["prepared","attempt_started"].includes(draft.phase)||!validIds(draft.outputs?.map((output)=>output.id)))throw Error("recovery_binding_conflict");return draft}function matching(draft,tx){return draft.outputs.every((output)=>tx.inputs.filter((input)=>`${input.sourceTXID??input.sourceTransaction?.id("hex")}.${input.sourceOutputIndex}`===output.outpoint&&input.sequence!==undefined&&input.sequence!==4294967295).length===1)&&tx.lockTime>=Math.max(...draft.outputs.map((output)=>output.unlockHeight))}function result(kind,draft,evidence){const tx=evidence?Transaction3.fromAtomicBEEF(evidence.atomicBeef):null;const inputValues=tx?.inputs.map((input)=>input.sourceTransaction?.outputs[input.sourceOutputIndex]?.satoshis);const fee=tx&&inputValues?.every((value)=>Number.isSafeInteger(value))?inputValues.reduce((sum,value)=>sum+value,0)-tx.outputs.reduce((sum,output)=>sum+(output.satoshis??0),0):null;const selectedSats=draft.outputs.reduce((sum,output)=>sum+output.satoshis,0);return{kind,operationId:draft.operationId,phase:draft.phase,outputs:draft.outputs,selectedSats,reclaimedSats:evidence&&draft.relay?.accepted?selectedSats:null,feeSats:fee,...evidence?{txid:evidence.txid}:{},...draft.relay?{relay:draft.relay}:{}}}async function recover(draft,record){if(draft.phase==="prepared")return blocked("operation_not_started");try{let evidence=record.returnedEvidence;if(!evidence&&options.recoverEvidence){const history=await wallet.listActions({labels:[label(draft.operationId)],labelQueryMode:"all",limit:2});const txid=history.totalActions===1&&history.actions.length===1?history.actions[0]?.txid:undefined;if(txid){const bytes=await options.recoverEvidence(txid),tx2=Transaction3.fromBEEF(bytes,txid);if(tx2.id("hex")!==txid||!matching(draft,tx2))throw Error("lock_evidence_mismatch");await options.store.persistEvidence(marker(draft.operationId),txid,tx2.toAtomicBEEFUint8Array(true));evidence=(await options.store.list(marker(draft.operationId))).find((row)=>row.reference.intentId===marker(draft.operationId))?.returnedEvidence}}if(!evidence)return{kind:"recovery_required",operationId:draft.operationId,reason:"original_lock_evidence_unavailable"};const tx=Transaction3.fromAtomicBEEF(evidence.atomicBeef);if(evidence.originator!==binding.originator||tx.id("hex")!==evidence.txid||!matching(draft,tx))return blocked("lock_evidence_mismatch");const filed=await verifyWalletActionEvidence(wallet,tx,label(draft.operationId));if(!filed.ok)return{kind:"recovery_required",operationId:draft.operationId,reason:filed.code};const relay=await options.relay(evidence.txid,Uint8Array.from(evidence.atomicBeef));const next={...draft,relay:{accepted:relay.accepted,status:relay.relayStatus}};await options.store.updateDraft(marker(draft.operationId),next);return result("reconciled",next,evidence)}catch{return{kind:"recovery_required",operationId:draft.operationId,reason:"original_lock_evidence_unavailable"}}}return{list:(caller,page={})=>run(caller,async()=>{const locks=await readWalletLocks(options.context,{limit:Math.min(page.limit??AGENT_LOCK_LIMIT,AGENT_LOCK_LIMIT),offset:page.offset});return{kind:"locks",locks:{...locks,message:null}}}),prepare:(caller,request)=>run(caller,async()=>{if(!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/u.test(request.operationId)||!validIds(request.ids))return blocked("lock_selection_invalid");const records=await options.store.list(),original=records.find((record)=>record.reference.clientIntentId===request.operationId);if(original){const draft2=prepared(original);if(!draft2||JSON.stringify(draft2.outputs.map((output)=>output.id).sort())!==JSON.stringify([...request.ids].sort()))return blocked("operation_input_conflict");return draft2.phase==="prepared"?result("prepared",draft2):blocked("operation_already_started")}const selected=await inspectSelectedLocks(options.context,request.ids).catch(()=>null);if(!selected||"error"in selected)return blocked("lock_selection_invalid");if(selected.outputs.some((output)=>output.state!=="matured"))return blocked("locks_not_matured");const draft={schema,operationId:request.operationId,connection:binding,deployment,outputs:selected.outputs,phase:"prepared"};await options.store.persistReference({intentId:marker(request.operationId),clientIntentId:request.operationId,nonce:marker(request.operationId),correlationTag:`intent:${marker(request.operationId)}`},draft);return result("prepared",draft)}),execute:(caller,operationId,signal)=>run(caller,async()=>{const record=(await options.store.list(marker(operationId))).find((row)=>row.reference.intentId===marker(operationId)),draft=record&&prepared(record);if(!record||!draft)return blocked("operation_not_prepared");if(draft.phase==="attempt_started")return recover(draft,record);if(signal?.aborted)return blocked("request_cancelled");const selected=await inspectSelectedLocks(options.context,draft.outputs.map((output)=>output.id)).catch(()=>null);if(!selected||"error"in selected||JSON.stringify(selected.outputs)!==JSON.stringify(draft.outputs))return blocked("lock_selection_changed");const attempted={...draft,phase:"attempt_started"};await options.store.updateDraft(marker(operationId),attempted);try{const returned=await executeBoundedLockUnlock(options.context,draft.outputs.map((output)=>output.id),()=>{if(signal?.aborted)throw Error("request_cancelled")},{labels:[label(operationId)],expectedOutpoints:draft.outputs.map((output)=>output.outpoint)});const exact=normalizePaidPostActionOutcome("agent-wallet-node",returned);if(exact.kind!=="creation_evidence"||exact.anomaly)return{kind:"recovery_required",operationId,reason:"original_lock_evidence_unavailable"};await options.store.persistEvidence(marker(operationId),exact.txid,exact.atomicBeef);const current=(await options.store.list(marker(operationId))).find((row)=>row.reference.intentId===marker(operationId));const recovered=await recover(attempted,current);return recovered.kind==="reconciled"?{...recovered,kind:"execution"}:recovered}catch{return{kind:"recovery_required",operationId,reason:"original_lock_evidence_unavailable"}}}),status:(caller,operationId)=>run(caller,async()=>{const record=(await options.store.list(marker(operationId))).find((row)=>row.reference.intentId===marker(operationId)),draft=record&&prepared(record);return record&&draft?result("status",draft,record.returnedEvidence):blocked("operation_not_prepared")}),reconcile:(caller,operationId)=>run(caller,async()=>{const record=(await options.store.list(marker(operationId))).find((row)=>row.reference.intentId===marker(operationId)),draft=record&&prepared(record);return record&&draft?recover(draft,record):blocked("operation_not_prepared")})}}function validIds(ids){return Array.isArray(ids)&&ids.length>0&&ids.length<=AGENT_LOCK_LIMIT&&new Set(ids).size===ids.length&&ids.every((id)=>typeof id==="string"&&id.length>0&&id.length<300)}import{Hash,Utils as Utils2}from"@bsv/sdk";var MESSAGING_IDENTITY_VERSION="mapapp-messaging-identity-v1";var MESSAGING_IDENTITY_MUTATION_VERSION="mapapp-messaging-identity-mutation-v1";var MAPAPP_MESSAGE_VERSION="mapapp-message-v1";var MAPAPP_MESSAGE_BOX_NAME="mapapp-messaging-v1";var MESSAGEBOX_PROTOCOL=[1,"messagebox"];var MESSAGEBOX_KEY_ID="1";var DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES=8*1024;var MAPAPP_MESSAGE_ID_MAX_BYTES=256;function serializeMessagingIdentityMutationV1(input){const mutation=assertMessagingIdentityMutationV1(input);return new TextEncoder().encode(JSON.stringify({version:mutation.version,operation:mutation.operation,bapId:mutation.bapId,walletIdentityKey:mutation.walletIdentityKey,messageBoxHost:mutation.messageBoxHost,deployment:mutation.deployment,canonicalOrigin:mutation.canonicalOrigin,network:mutation.network,expectedProfileOutpoint:mutation.expectedProfileOutpoint,expectedEvidenceHash:mutation.expectedEvidenceHash,acceptedSequence:mutation.acceptedSequence,projectionVersion:mutation.projectionVersion,clientOperationId:mutation.clientOperationId}))}function serializeMapAppMessageV1(input,maxPlaintextBytes=DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES){const message=assertMapAppMessageV1(input,maxPlaintextBytes);return JSON.stringify({version:message.version,messageId:message.messageId,senderIdentityKey:message.senderIdentityKey,recipientIdentityKey:message.recipientIdentityKey,conversationId:message.conversationId,sentAt:message.sentAt,text:message.text})}function conversationIdForIdentityKeys(first,second){assertCompressedIdentityKey(first,"first identity key");assertCompressedIdentityKey(second,"second identity key");if(first.toLowerCase()===second.toLowerCase())throw new TypeError("Self-messaging is not allowed.");const[left,right]=[first.toLowerCase(),second.toLowerCase()].sort();return Utils2.toHex(Hash.sha256(Array.from(new TextEncoder().encode(`mapapp-messaging/conversation/v1\\0${left}\\0${right}`))))}function assertMapAppMessageV1(value,maxPlaintextBytes=DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES){const record=strictRecord(value,["version","messageId","senderIdentityKey","recipientIdentityKey","conversationId","sentAt","text"],"MapAppMessageV1");if(record.version!==MAPAPP_MESSAGE_VERSION)throw new TypeError("Unsupported MapApp message version.");const messageId=stringField(record,"messageId");if(messageId.trim()===""||new TextEncoder().encode(messageId).byteLength>MAPAPP_MESSAGE_ID_MAX_BYTES)throw new TypeError("messageId must be a bounded non-empty string.");assertCanonicalIsoTimestamp(stringField(record,"sentAt"),"sentAt");const senderIdentityKey=stringField(record,"senderIdentityKey");const recipientIdentityKey=stringField(record,"recipientIdentityKey");assertCompressedIdentityKey(senderIdentityKey,"sender identity key");assertCompressedIdentityKey(recipientIdentityKey,"recipient identity key");if(senderIdentityKey.toLowerCase()===recipientIdentityKey.toLowerCase())throw new TypeError("Self-messaging is not allowed.");const expectedConversationId=conversationIdForIdentityKeys(senderIdentityKey,recipientIdentityKey);if(stringField(record,"conversationId")!==expectedConversationId)throw new TypeError("Message conversation ID does not match its participants.");if(!Number.isSafeInteger(maxPlaintextBytes)||maxPlaintextBytes<=0)throw new TypeError("Plaintext maximum must be a positive safe integer.");const text=stringField(record,"text");if(text.trim()==="")throw new TypeError("Message text must not be blank.");if(new TextEncoder().encode(text).byteLength>maxPlaintextBytes)throw new RangeError("Message text exceeds the plaintext maximum.");return record}function assertMessagingIdentityMutationV1(value){const record=strictRecord(value,["version","operation","bapId","walletIdentityKey","messageBoxHost","deployment","canonicalOrigin","network","expectedProfileOutpoint","expectedEvidenceHash","acceptedSequence","projectionVersion","clientOperationId"],"MessagingIdentityMutationV1");if(record.version!==MESSAGING_IDENTITY_MUTATION_VERSION)throw new TypeError("Unsupported messaging identity mutation version.");if(record.operation!=="register"&&record.operation!=="rotate"&&record.operation!=="revoke")throw new TypeError("Unsupported messaging identity operation.");for(const key of["bapId","messageBoxHost","deployment","canonicalOrigin","clientOperationId"])assertNonEmptyString(record[key],key);assertCompressedIdentityKey(stringField(record,"walletIdentityKey"),"wallet identity key");if(record.network!=="mainnet"&&record.network!=="testnet")throw new TypeError("Unsupported messaging network.");assertProfileEvidenceGroup(record);assertHttpsUrl(stringField(record,"messageBoxHost"),"messageBoxHost");assertHttpsUrl(stringField(record,"canonicalOrigin"),"canonicalOrigin");return record}function assertMessagingIdentityV1(value){const record=strictRecord(value,["version","bapId","walletIdentityKey","messageBoxHost","deployment","canonicalOrigin","network","expectedProfileOutpoint","expectedEvidenceHash","acceptedSequence","projectionVersion"],"MessagingIdentityV1");if(record.version!==MESSAGING_IDENTITY_VERSION)throw new TypeError("Unsupported messaging identity version.");for(const key of["bapId","messageBoxHost","deployment","canonicalOrigin"])assertNonEmptyString(record[key],key);assertCompressedIdentityKey(stringField(record,"walletIdentityKey"),"wallet identity key");if(record.network!=="mainnet"&&record.network!=="testnet")throw new TypeError("Unsupported messaging network.");assertProfileEvidenceGroup(record);assertHttpsUrl(stringField(record,"messageBoxHost"),"messageBoxHost");assertHttpsUrl(stringField(record,"canonicalOrigin"),"canonicalOrigin");return record}function assertCompressedIdentityKey(value,field="identity key"){if(!/^(02|03)[0-9a-fA-F]{64}$/.test(value))throw new TypeError(`${field} must be a compressed public key.`)}function strictRecord(value,keys,name){if(!value||typeof value!=="object"||Array.isArray(value))throw new TypeError(`${name} must be an object.`);const record=value;if(Object.keys(record).length!==keys.length||keys.some((key)=>!(key in record)))throw new TypeError(`${name} has unsupported or missing fields.`);return record}function stringField(record,key){const value=record[key];if(typeof value!=="string")throw new TypeError(`${key} must be a string.`);return value}function numberField(record,key){const value=record[key];if(typeof value!=="number"||!Number.isSafeInteger(value))throw new TypeError(`${key} must be a non-negative safe integer.`);return value}function assertProfileEvidenceGroup(record){const fields=[record.expectedProfileOutpoint,record.expectedEvidenceHash,record.acceptedSequence,record.projectionVersion];if(fields.every((value)=>value===null))return;if(fields.some((value)=>value===null))throw new TypeError("Profile evidence must be entirely present or absent.");assertNonEmptyString(record.expectedProfileOutpoint,"expectedProfileOutpoint");assertNonEmptyString(record.expectedEvidenceHash,"expectedEvidenceHash");if(numberField(record,"acceptedSequence")<1)throw new TypeError("acceptedSequence must be positive.");if(numberField(record,"projectionVersion")<0)throw new TypeError("projectionVersion must be non-negative.")}function assertNonEmptyString(value,field){if(typeof value!=="string"||value.trim()==="")throw new TypeError(`${field} must be a non-empty string.`)}function assertHttpsUrl(value,field){try{const parsed=new URL(String(value));if(parsed.protocol!=="https:"||parsed.username||parsed.password||parsed.pathname!=="/"||parsed.search||parsed.hash)throw new Error}catch{throw new TypeError(`${field} must be an HTTPS origin without a path.`)}}function assertCanonicalIsoTimestamp(value,field="timestamp"){if(!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)||!Number.isFinite(Date.parse(value))||new Date(value).toISOString()!==value)throw new TypeError(`${field} must be a canonical ISO-8601 UTC timestamp.`)}
|
|
3
3
|
export{createAgentWalletConnectionInspector,trustedHTTPEndpoint,POST_GEOHASH_MIN_PRECISION,POST_GEOHASH_MAX_PRECISION,POST_GEOHASH_DEFAULT_PRECISION,POST_GEOHASH_PATTERN,encodeGeohash,geohashBounds,MEDIA_RELAY_SAFE_MAX_BYTES,AGENT_MEDIA_MAX_BASE64_LENGTH,AgentMediaError,validAgentMediaInput,inspectAgentMedia,MAPAPP_CATEGORY_TOKENS,MAX_DIRECT_BSV_SEND_SATOSHIS,validateDirectBsvInput,inspectDirectBsvEvidence,recoverNativeActionEvidence,AGENT_LOCK_LIMIT,createAgentLockExecutor,MESSAGING_IDENTITY_MUTATION_VERSION,MAPAPP_MESSAGE_VERSION,MAPAPP_MESSAGE_BOX_NAME,MESSAGEBOX_PROTOCOL,MESSAGEBOX_KEY_ID,DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES,MAPAPP_MESSAGE_ID_MAX_BYTES,serializeMessagingIdentityMutationV1,serializeMapAppMessageV1,conversationIdForIdentityKeys,assertMapAppMessageV1,assertMessagingIdentityV1,assertCompressedIdentityKey,assertCanonicalIsoTimestamp};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{openAgentParticipantRuntime,parseParticipantConnection,participantExternalMetadataSchema,participantMetadataSchema,readParticipantConnection}from"./chunk-
|
|
2
|
+
import{openAgentParticipantRuntime,parseParticipantConnection,participantExternalMetadataSchema,participantMetadataSchema,readParticipantConnection}from"./chunk-tssaj9jc.js";import"./chunk-mb8a3fs5.js";import"./chunk-e6y2yzbj.js";import"./chunk-btwmey1h.js";export{readParticipantConnection,participantMetadataSchema,participantExternalMetadataSchema,parseParticipantConnection,openAgentParticipantRuntime};
|