@jdr377/mapapp-agent-connector 0.1.0-pre.7 → 0.1.0-pre.8

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.
@@ -1,7 +1,7 @@
1
1
  // @bun
2
- import{executePaidPostAction,normalizePaidPostActionOutcome,recoverPaidPostEvidence}from"./chunk-e6y2yzbj.js";import{AgentMediaError,DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES,MAPAPP_CATEGORY_TOKENS,MAPAPP_MESSAGE_BOX_NAME,MAPAPP_MESSAGE_ID_MAX_BYTES,MAPAPP_MESSAGE_VERSION,MESSAGEBOX_KEY_ID,MESSAGEBOX_PROTOCOL,MESSAGING_IDENTITY_MUTATION_VERSION,assertCanonicalIsoTimestamp,assertCompressedIdentityKey,assertMapAppMessageV1,assertMessagingIdentityV1,conversationIdForIdentityKeys,inspectAgentMedia,serializeMapAppMessageV1,serializeMessagingIdentityMutationV1,validAgentMediaInput}from"./chunk-4tt14q1n.js";import{__callDispose,__require,__using}from"./chunk-btwmey1h.js";import{readFile,stat,writeFile}from"fs/promises";import{join as join2,resolve as resolve2}from"path";import{createNodeWallet}from"@1sat/wallet-node";import{createContext,resolveBapId as resolveBapId2,computeBapId,deriveDepositAddresses,syncAddresses}from"@1sat/actions";import{PrivateKey as PrivateKey2}from"@bsv/sdk";import*as z2 from"zod/v4";import{HTTPWalletJSON as HTTPWalletJSON2}from"@bsv/sdk";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_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("locked","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":if(typeof value.version!=="string"||!validVersion(value.version))throw new Error;versionObserved=true;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 validVersion(version){const bytes=new TextEncoder().encode(version).byteLength;return bytes>=7&&bytes<=30&&[...version].every((character)=>{const code=character.charCodeAt(0);return code>31&&code!==127})}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}}function createParticipantHTTPWallet(endpoint,originator){const baseUrl=trustedHTTPEndpoint(endpoint);const request=Object.assign(async(resource,init)=>{const url=new URL(typeof resource==="string"?resource:resource instanceof URL?resource.href:resource.url);const selected=new URL(baseUrl);if(url.origin!==selected.origin||!url.pathname.startsWith(selected.pathname.replace(/\/$/u,"")+"/")||url.username||url.password||url.search||url.hash)throw new Error("participant_wallet_target_invalid");const response=await fetch(url,{...init,redirect:"error",signal:AbortSignal.timeout(15000)});if(!response.body)throw new Error("participant_wallet_response_invalid");const reader=response.body.getReader(),chunks=[];let size=0;try{while(true){const{done,value}=await reader.read();if(done)break;size+=value.length;if(size>4*1024*1024){await reader.cancel();throw new Error("participant_wallet_response_too_large")}chunks.push(value)}}finally{reader.releaseLock()}const bytes=Buffer.concat(chunks);if(!response.ok){let failure={};try{failure=JSON.parse(bytes.toString())}catch{}const code=failure.code==="ERR_PERMISSION_DENIED"||typeof failure.error==="string"&&failure.error.startsWith("permission denied for ")?"ERR_PERMISSION_DENIED":response.status===503&&failure.error==="Wallet is locked"?"ERR_WALLET_LOCKED":response.status===404?"ERR_METHOD_NOT_SUPPORTED":"ERR_WALLET_HTTP";throw Object.assign(new Error("participant_wallet_request_failed"),{code})}return new Response(bytes,{status:response.status,headers:response.headers})},{preconnect:fetch.preconnect});return new HTTPWalletJSON2(originator,baseUrl,request)}var U12_SPONSOR_POLICY="mapapp-sponsored-v2";var U12_RESERVATION_TTL_MS=2*60*1000;var U12_CONTRIBUTION_WINDOW_MS=24*60*60*1000;var U12_BAP_IP_WINDOW_MS=7*24*60*60*1000;function canonicalSponsoredDraft(draft){assertSponsoredDraft(draft);const value=draft.kind==="post"?{category:draft.category,geohash:draft.geohash,kind:draft.kind,...draft.mediaSha256?{mediaSha256:draft.mediaSha256.toLowerCase()}:{},policy:U12_SPONSOR_POLICY,text:draft.text}:{kind:draft.kind,...draft.mediaSha256?{mediaSha256:draft.mediaSha256.toLowerCase()}:{},parentTxid:draft.parentTxid.toLowerCase(),policy:U12_SPONSOR_POLICY,text:draft.text};return JSON.stringify(value)}function assertSponsoredDraft(draft){if(draft.kind!=="post"&&draft.kind!=="comment")throw new Error("Unsupported sponsored contribution kind.");if(!draft.text.trim())throw new Error("Sponsored contribution text is required.");if(new TextEncoder().encode(draft.text).byteLength>280)throw new Error("Sponsored contribution text exceeds 280 UTF-8 bytes.");if(draft.mediaSha256!==undefined&&!/^[0-9a-f]{64}$/i.test(draft.mediaSha256)){throw new Error("Sponsored media hash must be SHA-256 hex.")}if(draft.kind==="post"){if(!/^[0123456789bcdefghjkmnpqrstuvwxyz]{8,16}$/.test(draft.geohash))throw new Error("Sponsored post geohash is invalid.");if(!draft.category.trim())throw new Error("Sponsored post category is required.")}else if(!/^[0-9a-f]{64}$/i.test(draft.parentTxid)){throw new Error("Sponsored reply parent txid is invalid.")}}async function solveSponsoredPow(input){for(let attempt=0;attempt<1e6;attempt+=1){const value={...input,nonce:attempt.toString(36)};const digest=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(["mapapp-freepost-pow-v1",value.payloadHash,value.challenge.challenge,value.challenge.recentBlockHash,value.challenge.timestampWindow,String(value.challenge.difficultyBits),value.nonce].join(`
3
- `))));if(leadingZeroBits(digest)>=value.challenge.difficultyBits)return value}throw new Error("Unable to solve sponsor proof-of-work.")}function leadingZeroBits(bytes){let total=0;for(const byte of bytes){if(byte===0){total+=8;continue}for(let bit=7;bit>=0;bit-=1){if((byte&1<<bit)===0)total+=1;else return total}}return total}async function sponsoredDraftHash(value){return[...new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(value)))].map((byte)=>byte.toString(16).padStart(2,"0")).join("")}var schema="mapapp-agent-identity-operation-v1";var uuid=(value)=>/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/u.test(value);var marker=(id)=>`agent-identity:${id}`;function createAgentIdentityExecutor(options){const binding=Object.freeze({...options.binding}),deployment=new URL(options.deployment).origin;if(!options.store.updateDraft||!options.store.persistEvidence)throw new Error("identity_retention_required");const inspector=createAgentWalletConnectionInspector({wallet:options.wallet,binding});let busy=false;const blocked=(reason)=>({kind:"blocked",reason});async function exclusive(work){if(busy)return blocked("execution_in_progress");busy=true;try{return await work()}finally{busy=false}}function prepared(record){const draft=record.draft;if(draft?.schema!==schema)return null;if(!uuid(draft.operationId)||record.reference.intentId!==marker(draft.operationId)||draft.deployment!==deployment||JSON.stringify(draft.connection)!==JSON.stringify(binding)||!["prepared","attempt_started"].includes(draft.phase))throw new Error("identity_binding_changed");return draft}async function admission(caller){const inspected=await inspector.inspect(caller);if(inspected.state!=="ready")return inspected.reason;return null}const save=(draft)=>options.store.updateDraft(marker(draft.operationId),draft);async function reservation(draft){const{reservation:current}=await options.client.authenticatedRequest("sponsorStatus",{version:2,intentId:draft.operationId},`${deployment}/api/freeposting/u12/status`);if(!current||!uuid(current.reservationId)||current.intentId!==draft.operationId||current.kind!=="bap"||current.bapId!==draft.bapId||draft.reservationId&&current.reservationId!==draft.reservationId||!["reserved","funding","submitted","outcome_unknown","failed","expired"].includes(current.status))throw new Error("identity_reservation_changed");return current}async function recover(draft,record){if(draft.phase==="prepared")return blocked("operation_not_started");try{const current=await reservation(draft);let evidence=record.returnedEvidence;if(!evidence&&current.tx){const returned=normalizePaidPostActionOutcome("agent-wallet-node",current);if(returned.kind!=="creation_evidence"||returned.anomaly)return blocked("identity_evidence_invalid");await options.store.persistEvidence(marker(draft.operationId),returned.txid,returned.atomicBeef);evidence={txid:returned.txid,atomicBeef:Array.from(returned.atomicBeef),originator:binding.originator}}if(!evidence)return{kind:"recovery_required",operationId:draft.operationId,reason:"original_sponsor_evidence_unavailable",sponsorState:current.status};const exact=normalizePaidPostActionOutcome("agent-wallet-node",{txid:evidence.txid,tx:evidence.atomicBeef});if(evidence.originator!==binding.originator||exact.kind!=="creation_evidence"||exact.anomaly||current.tx&&(current.txid!==evidence.txid||JSON.stringify(current.tx)!==JSON.stringify(evidence.atomicBeef)))return blocked("identity_evidence_conflict");if(!draft.authorInternalized){if(!draft.fundingArgs)return blocked("identity_filing_data_missing");const args=draft.fundingArgs;await options.wallet.internalizeAction({tx:[...evidence.atomicBeef],description:args.description,labels:args.labels,outputs:(args.outputs??[]).map((output,outputIndex)=>({outputIndex,protocol:"basket insertion",insertionRemittance:{basket:output.basket??"default",tags:output.tags??[],customInstructions:output.customInstructions}}))},binding.originator);await save({...draft,reservationId:current.reservationId,authorInternalized:true})}const local=await options.published(),observed=await options.observed(draft.bapId).catch(()=>false);return{kind:"reconciled",operationId:draft.operationId,bapId:draft.bapId,txid:evidence.txid,sponsorState:current.status,authorInternalized:local===draft.bapId,publicIdentityObserved:observed,retryAllowed:false,next:local===draft.bapId&&observed?"check_readiness":"check_original_identity_status"}}catch{return{kind:"recovery_required",operationId:draft.operationId,reason:"original_identity_unavailable",retryAllowed:false}}}return{prepare(caller,operationId){return exclusive(async()=>{if(!uuid(operationId))return blocked("invalid_operation_id");const denied=await admission(caller);if(denied)return blocked(denied);const records=await options.store.list(),drafts=records.map(prepared);const existing=drafts.find((draft)=>draft?.operationId===operationId);if(existing?.phase==="attempt_started")return blocked("operation_already_started");if(drafts.some((draft)=>draft?.phase==="attempt_started"))return blocked("original_identity_attempt_unresolved");if(await options.published())return blocked("identity_already_published");if(!await options.ready().catch(()=>false))return blocked("identity_sponsor_unavailable");if(!existing){if(records.some((record)=>record.reference.clientIntentId===operationId))return blocked("operation_input_conflict");const bapId=await options.bapId();const deniedAgain=await admission(caller);if(deniedAgain)return blocked(deniedAgain);await options.store.persistReference({intentId:marker(operationId),clientIntentId:operationId,nonce:`agent-identity:${operationId}`,correlationTag:`intent:agent-identity:${operationId}`},{schema,operationId,connection:binding,deployment,bapId,phase:"prepared"})}return{kind:"prepared",operationId,bapId:existing?.bapId??await options.bapId(),payer:"mapapp",authorSats:0,sponsorCost:"unknown"}})},execute(caller,operationId,signal){return exclusive(async()=>{const denied=await admission(caller);if(denied)return blocked(denied);const records=await options.store.list(),record=records.find((record2)=>prepared(record2)?.operationId===operationId);if(!record)return blocked("operation_not_prepared");const draft=prepared(record);if(draft.phase==="attempt_started")return recover(draft,record);if(records.some((value)=>{const other=prepared(value);return other?.operationId!==operationId&&other?.phase==="attempt_started"}))return blocked("original_identity_attempt_unresolved");const changed=await admission(caller);if(changed)return blocked(changed);if(signal?.aborted)return blocked("request_cancelled");if(await options.published())return blocked("identity_already_published");if(await options.bapId()!==draft.bapId||!await options.ready().catch(()=>false))return blocked("identity_prerequisite_changed");let durable={...draft,phase:"attempt_started"};await save(durable);try{const hash=await sponsoredDraftHash(`mapapp-sponsored-bap-v2
4
- ${draft.bapId}`);const pow=await solveSponsoredPow({challenge:await options.challenge(hash),payloadHash:hash});if(signal?.aborted||await admission(caller))throw new Error("identity_binding_changed");const{reservation:current}=await options.client.authenticatedRequest("sponsorReserve",{version:2,intentId:operationId,kind:"bap",bapId:draft.bapId,pow},`${deployment}/api/freeposting/u12/reserve`);if(!current||!uuid(current.reservationId)||current.intentId!==operationId||current.kind!=="bap"||current.bapId!==draft.bapId||current.status!=="reserved")throw new Error("identity_reservation_invalid");durable={...durable,reservationId:current.reservationId};await save(durable);let fundingCalled=false;await options.invoke({fund:async(args)=>{if(fundingCalled||signal?.aborted||await admission(caller))throw new Error("identity_funding_refused");fundingCalled=true;durable={...durable,fundingArgs:structuredClone(args)};await save(durable);const returned=await options.client.authenticatedRequest("sponsorFund",{version:2,reservationId:current.reservationId,args},`${deployment}/api/freeposting/u12/fund`);const exact=normalizePaidPostActionOutcome("agent-wallet-node",returned);if(exact.kind!=="creation_evidence"||exact.anomaly)throw new Error("identity_evidence_invalid");await options.store.persistEvidence(marker(operationId),exact.txid,exact.atomicBeef);return returned}});if(await options.published()===draft.bapId){durable={...durable,authorInternalized:true};await save(durable)}const saved=(await options.store.list()).find((value)=>value.reference.intentId===marker(operationId));return recover(durable,saved)}catch{return{kind:"recovery_required",operationId,reason:"original_identity_interrupted",retryAllowed:false}}})},status(caller,operationId){return exclusive(async()=>{const inspected=await inspector.inspect(caller);if(inspected.state!=="ready")return blocked(inspected.reason);const record=(await options.store.list()).find((record2)=>prepared(record2)?.operationId===operationId);if(!record)return blocked("operation_not_prepared");const draft=prepared(record);return{kind:"status",operationId,phase:draft.phase,bapId:draft.bapId,authorInternalized:await options.published()===draft.bapId,publicIdentityObserved:await options.observed(draft.bapId).catch(()=>false),retryAllowed:false}})},reconcile(caller,operationId){return exclusive(async()=>{const denied=await admission(caller);if(denied)return blocked(denied);const record=(await options.store.list()).find((record2)=>prepared(record2)?.operationId===operationId);return record?recover(prepared(record),record):blocked("operation_not_prepared")})}}}import*as z from"zod/v4";var participantConnectionSchema=z.object({connectionId:z.string().min(1).max(128).regex(/^[a-zA-Z0-9.:_-]+$/u),callerId:z.string().min(1).max(128).regex(/^[a-zA-Z0-9.:_-]+$/u),originator:z.string().min(1).max(128).regex(/^[a-zA-Z0-9.-]+$/u)});function supportedParticipantBinding(binding){return binding.route==="agent_environment"&&binding.declaredAuthority==="full_root_authority"||binding.route==="existing_brc100"&&binding.declaredAuthority==="provider"}function participantAuthorityName(binding){return binding.route==="existing_brc100"?"provider":"full_root_authority"}function participantProfileMatches(binding,profile){return supportedParticipantBinding(binding)&&(binding.route==="existing_brc100"?profile.transport==="brc100_http"&&profile.authority==="provider"&&profile.qualification==="participant_release"&&profile.connectionReceipt==="mapapp-705.32":profile.transport==="direct_wallet_node"&&profile.authority==="full_root_authority"&&(profile.qualification==="participant_release"&&profile.connectionReceipt==="mapapp-705.31"||["controlled_fixture","operator_authorized_proof"].includes(profile.qualification)&&profile.connectionReceipt==="mapapp-705.21"))}function createAgentPaidPostExecutor(options){const binding=Object.freeze({...options.binding});const profile=Object.freeze({...options.proofProfile});const deployment=new URL(options.deployment).origin;if(!participantProfileMatches(binding,profile)||!options.store.updateDraft||!options.store.persistEvidence)throw new Error("agent_executor_configuration_invalid");const inspector=createAgentWalletConnectionInspector({wallet:options.wallet,binding});let busy=false;const blocked=(reason)=>({kind:"blocked",reason});const marker2=(id)=>`agent-prepared:${id}`;async function records(){return await options.store.list()}function prepared(record){const draft=record.draft;if(draft?.schema!=="mapapp-agent-paid-root-operation-v1")return null;if(record.reference.intentId!==marker2(draft.operationId)||!uuid2(draft.intakeId)||!sameBinding(draft.connection,binding)||draft.deployment!==deployment||!["prepared","attempt_started"].includes(draft.phase))throw new Error("agent_operation_binding_invalid");return draft}async function admission(caller,input){const state=await inspector.inspect(caller);if(state.state!=="ready")return state.reason;const gates=await options.gates().catch(()=>null);if(!gates)return"prerequisite_unavailable";if(!gates.stackReady||!gates.intakeReady||!gates.paidRootEnabled||!gates.identityReady)return"prerequisite_blocked";if(input&&(gates.freshnessLockSats!==undefined&&input.freshnessLockSats!==gates.freshnessLockSats||gates.blockHeight!==undefined&&input.freshnessUnlockHeight<=gates.blockHeight))return"publication_policy_changed";return null}async function exclusive(work){if(busy)return blocked("execution_in_progress");busy=true;try{return await work()}finally{busy=false}}async function reconcilePrepared(draft,currentRecords){if(draft.phase==="prepared")return blocked("operation_not_started");const matches=currentRecords.filter((record)=>record.reference.intentId===draft.intakeId);if(matches.length>1)return{kind:"recovery_required",operationId:draft.operationId,reason:"reference_conflict"};let evidence=matches[0]?.returnedEvidence;try{if(!evidence&&matches[0]){const recovered=await recoverPaidPostEvidence({wallet:options.wallet,correlationTag:matches[0].reference.correlationTag,evidenceFormat:"mapapp_post_v2"});if(recovered.kind==="recovered"){await options.store.persistEvidence(draft.intakeId,recovered.txid,recovered.atomicBeef);evidence={txid:recovered.txid,atomicBeef:Array.from(recovered.atomicBeef),originator:binding.originator}}}if(evidence){if(evidence.originator!==binding.originator)return blocked("evidence_originator_changed");await options.client.submitEvidence(draft.intakeId,evidence.txid,new Uint8Array(evidence.atomicBeef))}return{kind:"reconciled",operationId:draft.operationId,intake:await options.client.statusIntent(draft.intakeId),evidenceResubmitted:!!evidence}}catch{return{kind:"recovery_required",operationId:draft.operationId,reason:"original_intake_unavailable"}}}return{prepare(caller,request){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");if(!uuid2(request.operationId)||!validInput(request.input))return blocked("invalid_text_post_input");if(request.maxTotalSats!==undefined)return blocked("spending_cap_unenforceable");const input=canonicalInput(request.input);const existing=(await records()).map(prepared).find((draft2)=>draft2?.operationId===request.operationId);if(existing){if(JSON.stringify(existing.input)!==JSON.stringify(input))return blocked("operation_input_conflict");if(existing.phase!=="prepared")return blocked("operation_already_started");const denied2=await admission(caller,input);if(denied2)return blocked(denied2);try{const media2=input.media?(await inspectAgentMedia(input.media)).summary:undefined;return{kind:"prepared",operationId:request.operationId,authority:participantAuthorityName(binding),spendingCap:"not_enforced",...media2?{media:media2}:{}}}catch(error){return blocked(error instanceof AgentMediaError?error.code:"media_inspection_unavailable")}}const denied=await admission(caller,input);if(denied)return blocked(denied);let media;try{if(input.media)media=(await inspectAgentMedia(input.media)).summary}catch(error){return blocked(error instanceof AgentMediaError?error.code:"media_inspection_unavailable")}const draft={schema:"mapapp-agent-paid-root-operation-v1",operationId:request.operationId,intakeId:crypto.randomUUID(),connection:binding,deployment,input,phase:"prepared"};const nonce=`agent-local:${request.operationId}`;await options.store.persistReference({intentId:marker2(request.operationId),nonce,correlationTag:`intent:${nonce}`,clientIntentId:request.operationId,evidenceFormat:"mapapp_post_v2"},draft);return{kind:"prepared",operationId:request.operationId,authority:participantAuthorityName(binding),spendingCap:"not_enforced",...media?{media}:{}}})},execute(caller,operationId,signal){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");if(signal?.aborted)return blocked("request_cancelled");const currentRecords=await records();const drafts=currentRecords.map(prepared).filter((value)=>!!value);const draft=drafts.find((value)=>value.operationId===operationId);if(!draft)return blocked("operation_not_prepared");const denied=await admission(caller,draft.input);if(denied)return blocked(denied);if(draft.phase==="attempt_started")return reconcilePrepared(draft,currentRecords);let publication;try{const{media,...fields}=draft.input;publication={...fields,...media?{media:(await inspectAgentMedia(media)).media}:{}}}catch(error){return blocked(error instanceof AgentMediaError?error.code:"media_inspection_unavailable")}for(const prior of drafts.filter((value)=>value.phase==="attempt_started")){const status=await options.client.statusIntent(prior.intakeId).catch(()=>null);if(!status||status.projectionState!=="live")return blocked("unresolved_operation")}for(const record of currentRecords){const prior=record.draft;if(!["mapapp-agent-sponsored-operation-v1","mapapp-agent-social-operation-v1"].includes(prior?.schema??"")||prior?.phase!=="attempt_started")continue;const status=await options.client.statusIntent(prior.intakeId).catch(()=>null);if(!status||status.projectionState!=="live")return blocked("unresolved_operation")}if(signal?.aborted)return blocked("request_cancelled");await options.store.updateDraft(marker2(operationId),{...draft,phase:"attempt_started"});try{const result=await executePaidPostAction({provider:"agent-wallet-node",providerAttested:false,agentProofProfile:profile,client:options.client,clientIntentId:operationId,intentId:draft.intakeId,tabId:binding.connectionId,localIntentStore:options.store,draft:{schema:"mapapp-agent-paid-root-intake-v1",operationId,input:draft.input},evidenceFormat:"mapapp_post_v2",actionKind:"post",actionLabelEnabled:true,invoke:async(metadata)=>{const changed=await admission(caller,draft.input);if(changed||signal?.aborted)throw new Error("agent_pre_dispatch_binding_or_prerequisite_changed");return options.invoke(publication,metadata)}});return{kind:"execution",operationId,result}}catch{return{kind:"recovery_required",operationId,reason:"original_operation_interrupted"}}})},status(caller,operationId){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");const state=await inspector.inspect(caller);if(state.state!=="ready")return blocked(state.reason);const draft=(await records()).map(prepared).find((value)=>value?.operationId===operationId);if(!draft)return blocked("operation_not_prepared");if(draft.phase==="prepared")return{kind:"status",operationId,phase:draft.phase};try{return{kind:"status",operationId,phase:draft.phase,intake:await options.client.statusIntent(draft.intakeId)}}catch{return{kind:"recovery_required",operationId,reason:"original_intake_unavailable"}}})},reconcile(caller,operationId){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");const state=await inspector.inspect(caller);if(state.state!=="ready")return blocked(state.reason);const currentRecords=await records();const draft=currentRecords.map(prepared).find((value)=>value?.operationId===operationId);return draft?reconcilePrepared(draft,currentRecords):blocked("operation_not_prepared")})}}}function uuid2(value){return typeof value==="string"&&/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(value)}function sameBinding(left,right){return!!left&&Object.keys(right).every((key)=>left[key]===right[key])}function canonicalInput(input){return{text:input.text,geohash:input.geohash,category:input.category,freshnessLockOutputsEnabled:true,freshnessLockSats:input.freshnessLockSats,freshnessUnlockHeight:input.freshnessUnlockHeight,freshnessDuration:input.freshnessDuration,...input.media?{media:{contentType:input.media.contentType,base64:input.media.base64,byteSize:input.media.byteSize,sha256:input.media.sha256}}:{}}}function validInput(input){return!!input&&(input.media===undefined||validAgentMediaInput(input.media))&&typeof input.text==="string"&&!!input.text.trim()&&new TextDecoder().decode(new TextEncoder().encode(input.text))===input.text&&Object.keys(input).every((key)=>["text","geohash","category","freshnessLockOutputsEnabled","freshnessLockSats","freshnessUnlockHeight","freshnessDuration","media"].includes(key))&&new TextEncoder().encode(input.text).length<=16384&&typeof input.geohash==="string"&&/^[0123456789bcdefghjkmnpqrstuvwxyz]{5,12}$/.test(input.geohash)&&MAPAPP_CATEGORY_TOKENS.includes(input.category)&&input.freshnessLockOutputsEnabled===true&&Number.isSafeInteger(input.freshnessLockSats)&&input.freshnessLockSats>0&&Number.isSafeInteger(input.freshnessUnlockHeight)&&input.freshnessUnlockHeight>0&&input.freshnessUnlockHeight<500000000&&["1D","7D","1M","3M"].includes(input.freshnessDuration)}var MAPAPP_LOCAL_INTENT_PROTOCOL=[2,"mapapp local intent index"];var LOCAL_INTENT_NAMESPACE_KEY_ID="mapapp local intent namespace v1";var LOCAL_INTENT_KEY_ID="mapapp local intent record v1";var LOCAL_INTENT_DATABASE_NAME="mapapp-local-intents";var DATABASE_VERSION=1;var RECORD_STORE="encrypted-intents";var ENVELOPE_VERSION=1;var CONTENT_VERSION=1;class LocalIntentStoreError extends Error{code;constructor(code,message,options){super(message,options);this.code=code;this.name="LocalIntentStoreError"}}function createLocalIntentStore(options){const originator=requireOriginator(options.originator);const repository=options.repository??createIndexedDbLocalIntentRepository(resolveIndexedDb(options.indexedDB));const now=options.now??(()=>new Date);const randomUUID=options.randomUUID??(()=>{if(typeof globalThis.crypto?.randomUUID!=="function"){throw new LocalIntentStoreError("secure_record_id_unavailable","Secure local intent record identifiers are unavailable.")}return globalThis.crypto.randomUUID()});async function namespaceId(){try{const result=await options.wallet.getPublicKey({protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_NAMESPACE_KEY_ID,counterparty:"self",forSelf:true},originator);if(typeof result.publicKey!=="string"||!result.publicKey.trim()){throw new Error("Wallet returned an empty namespace public key.")}return result.publicKey}catch(cause){throw wrapError("wallet_namespace_unavailable","The connected wallet could not open its local intent namespace.",cause)}}return{namespaceId,async persistReference(reference,draft){requireReference(reference);const walletNamespace=await namespaceId();const timestamp=now().toISOString();const record={version:CONTENT_VERSION,recordId:randomUUID(),namespaceId:walletNamespace,createdAt:timestamp,updatedAt:timestamp,reference:{...reference},...draft===undefined?{}:{draft}};let ciphertext;try{const encrypted=await options.wallet.encrypt({plaintext:[...new TextEncoder().encode(JSON.stringify(record))],protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);ciphertext=requireBytes(encrypted.ciphertext,"Wallet returned invalid local intent ciphertext.")}catch(cause){throw wrapError("wallet_encryption_failed","The connected wallet refused or failed local intent encryption.",cause)}const envelope={envelopeVersion:ENVELOPE_VERSION,recordId:record.recordId,namespaceId:walletNamespace,createdAt:timestamp,updatedAt:timestamp,ciphertext};try{await repository.put(envelope)}catch(cause){throw wrapError("local_intent_commit_failed","The encrypted local intent reference could not be committed to IndexedDB.",cause)}return record},async list(){const walletNamespace=await namespaceId();let envelopes;try{envelopes=await repository.list(walletNamespace)}catch(cause){throw wrapError("local_intent_read_failed","The encrypted local intent index could not be read from IndexedDB.",cause)}const records=[];for(const envelope of envelopes){requireEnvelope(envelope,walletNamespace);let plaintext;try{const decrypted=await options.wallet.decrypt({ciphertext:[...envelope.ciphertext],protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);plaintext=requireBytes(decrypted.plaintext,"Wallet returned invalid local intent plaintext.",true)}catch(cause){throw wrapError("wallet_decryption_failed","The connected wallet could not decrypt its local intent index.",cause)}const record=parseRecord(plaintext);if(record.recordId!==envelope.recordId||record.namespaceId!==envelope.namespaceId||record.createdAt!==envelope.createdAt){throw new LocalIntentStoreError("local_intent_envelope_mismatch","Encrypted local intent metadata does not match its authenticated content.")}records.push(record)}return records.sort((left,right)=>left.createdAt.localeCompare(right.createdAt)||left.recordId.localeCompare(right.recordId))},async persistEvidence(intentId,txid,atomicBeef){if(!/^[0-9a-f]{64}$/.test(txid)||!atomicBeef.length||atomicBeef.length>2*1024*1024){throw new LocalIntentStoreError("local_evidence_invalid","Exact returned transaction evidence is invalid.")}const matches=(await this.list()).filter((record2)=>record2.reference.intentId===intentId);if(matches.length!==1)throw new LocalIntentStoreError("local_evidence_reference_conflict","Exact evidence requires one wallet-owned intent reference.");const record=matches[0];if(record.returnedEvidence&&(record.returnedEvidence.txid!==txid||JSON.stringify(record.returnedEvidence.atomicBeef)!==JSON.stringify(Array.from(atomicBeef)))){throw new LocalIntentStoreError("local_evidence_conflict","The intent already retains different transaction evidence.")}const updated={...record,updatedAt:now().toISOString(),returnedEvidence:{txid,atomicBeef:Array.from(atomicBeef),originator}};const encrypted=await options.wallet.encrypt({plaintext:Array.from(new TextEncoder().encode(JSON.stringify(updated))),protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);await repository.put({envelopeVersion:ENVELOPE_VERSION,recordId:record.recordId,namespaceId:record.namespaceId,createdAt:record.createdAt,updatedAt:updated.updatedAt,ciphertext:requireBytes(encrypted.ciphertext,"Wallet returned invalid local intent ciphertext.")})},async updateDraft(intentId,draft){const matches=(await this.list()).filter((record2)=>record2.reference.intentId===intentId);if(matches.length!==1)throw new LocalIntentStoreError("local_draft_reference_conflict","Draft update requires one wallet-owned reference.");const record=matches[0];const updated={...record,updatedAt:now().toISOString(),draft};const encrypted=await options.wallet.encrypt({plaintext:Array.from(new TextEncoder().encode(JSON.stringify(updated))),protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);await repository.put({envelopeVersion:ENVELOPE_VERSION,recordId:record.recordId,namespaceId:record.namespaceId,createdAt:record.createdAt,updatedAt:updated.updatedAt,ciphertext:requireBytes(encrypted.ciphertext,"Wallet returned invalid local intent ciphertext.")})},async forgetCurrentWallet(){const walletNamespace=await namespaceId();try{await repository.deleteNamespace(walletNamespace)}catch(cause){throw wrapError("local_intent_forget_failed","The wallet's encrypted local intent index could not be removed.",cause)}}}}function createIndexedDbLocalIntentRepository(indexedDB){return{async put(record){requireEnvelope(record,record.namespaceId);const database=await openDatabase(indexedDB);try{await runTransaction(database,"readwrite",(store)=>store.put(cloneEnvelope(record)))}finally{database.close()}},async list(namespaceId){const database=await openDatabase(indexedDB);try{const records=await runTransaction(database,"readonly",(store)=>store.index("namespaceId").getAll(namespaceId));return records.map(cloneEnvelope)}finally{database.close()}},async deleteNamespace(namespaceId){const database=await openDatabase(indexedDB);try{await new Promise((resolve,reject)=>{const transaction=database.transaction(RECORD_STORE,"readwrite");const request=transaction.objectStore(RECORD_STORE).index("namespaceId").openKeyCursor(namespaceId);request.onsuccess=()=>{const cursor=request.result;if(!cursor)return;transaction.objectStore(RECORD_STORE).delete(cursor.primaryKey);cursor.continue()};transaction.oncomplete=()=>resolve();transaction.onerror=()=>reject(transaction.error??new Error("IndexedDB delete transaction failed."));transaction.onabort=()=>reject(transaction.error??new Error("IndexedDB delete transaction was aborted."))})}finally{database.close()}}}}function resolveIndexedDb(indexedDB){const resolved=indexedDB??(typeof globalThis.indexedDB==="undefined"?undefined:globalThis.indexedDB);if(!resolved)throw new LocalIntentStoreError("indexeddb_unavailable","IndexedDB is required for the encrypted local intent index.");return resolved}function openDatabase(indexedDB){return new Promise((resolve,reject)=>{const request=indexedDB.open(LOCAL_INTENT_DATABASE_NAME,DATABASE_VERSION);request.onupgradeneeded=()=>{const database=request.result;if(!database.objectStoreNames.contains(RECORD_STORE)){const store=database.createObjectStore(RECORD_STORE,{keyPath:"recordId"});store.createIndex("namespaceId","namespaceId",{unique:false})}};request.onsuccess=()=>resolve(request.result);request.onerror=()=>reject(request.error??new Error("Could not open the local intent IndexedDB database."));request.onblocked=()=>reject(new Error("Close other MapApp tabs before upgrading the local intent index."))})}function runTransaction(database,mode,operation){return new Promise((resolve,reject)=>{const transaction=database.transaction(RECORD_STORE,mode);const request=operation(transaction.objectStore(RECORD_STORE));let result;request.onsuccess=()=>{result=request.result};request.onerror=()=>reject(request.error??new Error("IndexedDB request failed."));transaction.oncomplete=()=>resolve(result);transaction.onerror=()=>reject(transaction.error??new Error("IndexedDB transaction failed."));transaction.onabort=()=>reject(transaction.error??new Error("IndexedDB transaction was aborted."))})}function parseRecord(bytes){let value;try{value=JSON.parse(new TextDecoder("utf-8",{fatal:true}).decode(new Uint8Array(bytes)))}catch(cause){throw wrapError("local_intent_content_corrupt","Decrypted local intent content is invalid.",cause)}if(!isRecord2(value)||value.version!==CONTENT_VERSION||!isNonEmptyString(value.recordId)||!isNonEmptyString(value.namespaceId)||!isIsoTimestamp(value.createdAt)||!isIsoTimestamp(value.updatedAt)||!isReference(value.reference)){throw new LocalIntentStoreError("local_intent_content_corrupt","Decrypted local intent content has an unsupported or corrupt shape.")}return value}function requireEnvelope(value,namespaceId){if(!isRecord2(value)||value.envelopeVersion!==ENVELOPE_VERSION||!isNonEmptyString(value.recordId)||value.namespaceId!==namespaceId||!isIsoTimestamp(value.createdAt)||!isIsoTimestamp(value.updatedAt)){throw new LocalIntentStoreError("local_intent_envelope_corrupt","Encrypted local intent metadata has an unsupported or corrupt shape.")}requireBytes(value.ciphertext,"Encrypted local intent ciphertext is invalid.")}function requireReference(value){if(!isReference(value)||value.correlationTag!==`intent:${value.nonce}`){throw new LocalIntentStoreError("local_intent_reference_invalid","The caller-known local intent reference is invalid.")}}function isReference(value){return isRecord2(value)&&isNonEmptyString(value.intentId)&&isNonEmptyString(value.nonce)&&isNonEmptyString(value.correlationTag)&&isNonEmptyString(value.clientIntentId)&&(value.evidenceFormat===undefined||value.evidenceFormat==="mapapp_post_v1"||value.evidenceFormat==="mapapp_post_v2"||value.evidenceFormat==="mapapp_social_v2"||value.evidenceFormat==="mapapp_sponsored_v2"||value.evidenceFormat==="mapapp_upgrade_v2"||value.evidenceFormat==="mapapp_direct_bsv_v1"||value.evidenceFormat==="mapapp_bap_alias_v1")}function requireBytes(value,message,allowEmpty=false){if(!Array.isArray(value)||!allowEmpty&&value.length===0||value.some((byte)=>!Number.isInteger(byte)||byte<0||byte>255)){throw new LocalIntentStoreError("local_intent_bytes_invalid",message)}return[...value]}function cloneEnvelope(value){return{...value,ciphertext:[...value.ciphertext]}}function requireOriginator(value){const originator=value.trim();if(!originator)throw new LocalIntentStoreError("originator_required","A MapApp originator is required for wallet-owned local encryption.");return originator}function isIsoTimestamp(value){return typeof value==="string"&&Number.isFinite(Date.parse(value))}function isNonEmptyString(value){return typeof value==="string"&&value.length>0}function isRecord2(value){return typeof value==="object"&&value!==null}function wrapError(code,message,cause){if(cause instanceof LocalIntentStoreError)return cause;const detail=cause instanceof Error&&cause.message?` ${cause.message}`:"";return new LocalIntentStoreError(code,`${message}${detail}`,{cause})}async function executePaidRootPost(actionContext,input,metadata,execute){if(!input.text.trim())return{error:"MapApp Post v2 requires non-empty text."};if(input.freshnessLockOutputsEnabled!==true||!input.freshnessUnlockHeight||!input.freshnessLockSats||!input.freshnessDuration){return{error:"MapApp Post v2 freshness output settings are incomplete."}}const[{applyBapAip,executeTrackedAction,P1SAT_PROTOCOL}]=await Promise.all([import("@1sat/actions")]);const unsignedRoot=await preparePaidRootPostScriptObject(input);const signedRoot=await applyBapAip(actionContext,unsignedRoot);const lockKey=await actionContext.wallet.getPublicKey({protocolID:P1SAT_PROTOCOL,keyID:"lock",counterparty:"self",forSelf:true});const args=await assemblePaidRootPostAction(input,metadata,signedRoot.toHex(),lockKey.publicKey);const result=await(execute??((args2)=>executeTrackedAction(actionContext.wallet,args2)))(args);if(result.error==="broadcast-success"){const{recoverPaidPostEvidence:recoverPaidPostEvidence2}=await import("./chunk-c74qq5ek.js");const recovered=await recoverPaidPostEvidence2({wallet:actionContext.wallet,correlationTag:metadata.outputTags[0],evidenceFormat:"mapapp_post_v2"});if(recovered.kind==="recovered"){return{txid:recovered.txid,tx:Array.from(recovered.atomicBeef)}}}return{txid:result.txid,tx:result.tx,error:result.error}}async function preparePaidRootPostScriptObject(input){const[{B,BitCom,MAP:MAPTemplate},{OP,Script}]=await Promise.all([import("@1sat/templates"),import("@bsv/sdk")]);const textProtocol=oneBitComProtocol(BitCom,B.text(input.text,"text/plain"));const mapProtocol=oneBitComProtocol(BitCom,MAPTemplate.set({app:"mapapp",type:"post",context:"geohash",contextValue:input.geohash,category:input.category}));const bareUnsignedRoot=new BitCom([{...textProtocol,pos:0},{...mapProtocol,pos:1}]).lock();return new Script([{op:OP.OP_FALSE},...bareUnsignedRoot.chunks])}async function assemblePaidRootPostAction(input,metadata,signedRootScriptHex,lockPublicKey){const[{BSOCIAL_BASKET,P1SAT_PROTOCOL},{B,BitCom,Lock},{OP,PublicKey:PublicKey2,Script},{LOCK_BASKET}]=await Promise.all([import("@1sat/actions"),import("@1sat/templates"),import("@bsv/sdk"),import("@1sat/types")]);const locker=PublicKey2.fromString(lockPublicKey).toAddress();const freshnessScript=Lock.lock(locker,input.freshnessUnlockHeight);const outputs=[{lockingScript:signedRootScriptHex,satoshis:0,outputDescription:"MapApp Post v2 social root",basket:BSOCIAL_BASKET,tags:[...metadata.outputTags]}];if(input.media){outputs.push({lockingScript:new Script([{op:OP.OP_FALSE},...new BitCom([{...oneBitComProtocol(BitCom,B.binary(input.media.bytes,input.media.contentType)),pos:0}]).lock().chunks]).toHex(),satoshis:0,outputDescription:`MapApp Post v2 ${input.media.kind} media`})}outputs.push({lockingScript:freshnessScript.toHex(),satoshis:input.freshnessLockSats,outputDescription:`Genesis freshness lock until block ${input.freshnessUnlockHeight}`,basket:LOCK_BASKET,tags:["app:mapapp","type:freshness","kind:genesis",`until:${input.freshnessUnlockHeight}`,`duration:${input.freshnessDuration}`],customInstructions:JSON.stringify({protocolID:P1SAT_PROTOCOL,keyID:"lock",app:"mapapp",kind:"genesis-freshness"})});return{description:input.media?`MapApp Post v2 with ${input.media.kind} media`:"MapApp Post v2 text post",outputs,labels:metadata.labels,options:{acceptDelayedBroadcast:false,randomizeOutputs:false}}}function oneBitComProtocol(BitComTemplate,script){const decoded=BitComTemplate.decode(script);if(!decoded||decoded.protocols.length!==1){throw new Error("Public protocol template did not produce one BitCom section.")}return decoded.protocols[0]}import{createAuthProof}from"@bsv/auth";var MAPAPP_AUTH_PROTOCOL=[2,"mapapp transaction intake"];var MAPAPP_AUTH_ACTIONS={create:"mapapp create transaction intent",claim:"mapapp claim wallet invocation",evidence:"mapapp submit transaction evidence",outcome:"mapapp record wallet outcome",terminate:"mapapp terminate unused transaction intent",status:"mapapp read transaction intent status",sponsorReserve:"mapapp reserve sponsored wallet action",sponsorFund:"mapapp fund sponsored wallet action",sponsorStatus:"mapapp read sponsored wallet action",thumbnailIssue:"mapapp issue thumbnail upload capability",thumbnailStage:"mapapp stage intent thumbnail",retainedMediaStage:"mapapp stage retained media"};function createTransactionIntakeClient(options){const fetcher=options.fetch??globalThis.fetch;const baseUrl=(options.baseUrl??"/api/transaction-intakes").replace(/\/$/,"");const requestTimeoutMs=options.requestTimeoutMs??1e4;let cachedConfig=null;let configRequest=null;async function readAuthConfig(){const now=Date.now();if(cachedConfig&&cachedConfig.expiresAt>now)return cachedConfig.value;if(!configRequest){const pending=(async()=>{const configResponse=await fetchWithDeadline(fetcher,`${baseUrl}/auth-config`,{headers:{accept:"application/json"}},requestTimeoutMs);const config=await readJson(configResponse);cachedConfig={value:config,expiresAt:Date.now()+Math.min(30000,Math.max(1000,config.proofLifetimeMs/4))};return config})().finally(()=>{if(configRequest===pending)configRequest=null});configRequest=pending}return configRequest}async function request(operation,body){const config=await readAuthConfig();requireEnabledConfig(config,operation);const rawBody=new TextEncoder().encode(JSON.stringify(body));const proof=await createAuthProof({wallet:options.wallet,counterparty:config.verifierIdentityKey,action:MAPAPP_AUTH_ACTIONS[operation],body:rawBody,protocol:MAPAPP_AUTH_PROTOCOL,windowMs:config.proofLifetimeMs});const response=await fetchWithDeadline(fetcher,`${baseUrl}/${operation}`,{method:"POST",headers:{"content-type":"application/json",accept:"application/json","x-mapapp-brc138-proof":encodeProof(proof)},body:rawBody},requestTimeoutMs);const result=await readJson(response);if(!response.ok){if(response.status===401||response.status===403){cachedConfig=null;configRequest=null}throw new TransactionIntakeClientError(response.status,result.code??"transaction_intake_request_failed",result.message??"Transaction intake request failed.")}return result}return{async createIntent(clientIntentId,intentId,actionKind="post",actionTarget){return request("create",{version:1,intentId,clientIntentId,actionKind,...actionTarget?{actionTarget}:{}})},async claimInvocation(intentId,tabId){return request("claim",{version:1,intentId,tabId})},async submitEvidence(intentId,subjectTxid,atomicBeef,profileControl,profileAliasOutpoint){return request("evidence",{version:1,intentId,subjectTxid,atomicBeefBase64:encodeBytes(atomicBeef),...profileControl?{profileControl}:{},...profileAliasOutpoint?{profileAliasOutpoint}:{}})},async recordOutcome(intentId,state,subjectTxid){await request("outcome",{version:1,intentId,state,...subjectTxid?{subjectTxid}:{}})},async terminateIntent(intentId,code){await request("terminate",{version:1,intentId,code})},async statusIntent(intentId){const result=await request("status",{version:1,intentId});return result.intake},async authenticatedRequest(operation,body,path){let target=path;if(/^https?:\/\//u.test(baseUrl)){const configured=new URL(baseUrl),selected=new URL(path,configured);if(selected.origin!==configured.origin)throw new TransactionIntakeClientError(400,"wallet_request_origin_mismatch","Authenticated requests must use the configured MapApp origin.");target=selected.toString()}else if(!path.startsWith("/api/")||path.startsWith("//")){throw new TransactionIntakeClientError(400,"wallet_request_origin_mismatch","Authenticated requests must use a same-origin MapApp API path.")}const config=await readAuthConfig();requireEnabledConfig(config,operation);const rawBody=new TextEncoder().encode(JSON.stringify(body));const proof=await createAuthProof({wallet:options.wallet,counterparty:config.verifierIdentityKey,action:MAPAPP_AUTH_ACTIONS[operation],body:rawBody,protocol:MAPAPP_AUTH_PROTOCOL,windowMs:config.proofLifetimeMs});const response=await fetchWithDeadline(fetcher,target,{method:"POST",headers:{"content-type":"application/json",accept:"application/json","x-mapapp-brc138-proof":encodeProof(proof)},body:rawBody},requestTimeoutMs);const result=await readJson(response);if(!response.ok){if(response.status===401||response.status===403){cachedConfig=null;configRequest=null}throw new TransactionIntakeClientError(response.status,result.code??"sponsor_request_failed",result.message??"Sponsor request failed.")}return result},async stageThumbnail(intentId,mediaSlot,sourceSha256,bytes){await this.authenticatedRequest("thumbnailStage",{version:1,intentId,mediaSlot,sourceSha256:sourceSha256.toLowerCase(),thumbnailBase64:encodeBytes(bytes)},`/api/media/thumbnail-stages/${encodeURIComponent(intentId)}`)},async stageRetainedMedia(intentId,media){return this.authenticatedRequest("retainedMediaStage",{version:1,intentId,media},"/api/media/freeposts")}}}class TransactionIntakeClientError extends Error{status;code;constructor(status,code,message){super(message);this.status=status;this.code=code;this.name="TransactionIntakeClientError"}}function requireEnabledConfig(config,operation){if(!config.enabled||!config.verifierIdentityKey){throw new TransactionIntakeClientError(503,"wallet_request_proof_disabled",`Transaction intake is disabled: ${config.disabledReasons?.join(", ")||"verifier unavailable"}.`)}if(JSON.stringify(config.protocol)!==JSON.stringify(MAPAPP_AUTH_PROTOCOL)||config.actions?.[operation]!==MAPAPP_AUTH_ACTIONS[operation]){throw new TransactionIntakeClientError(503,"wallet_request_proof_contract_mismatch","Transaction intake authentication does not match the pinned MapApp contract.")}}async function readJson(response){try{return await response.json()}catch{throw new TransactionIntakeClientError(response.status,"transaction_intake_invalid_response","Transaction intake returned an invalid response.")}}function encodeProof(proof){return encodeBytes(new TextEncoder().encode(JSON.stringify(proof)),true)}function encodeBytes(bytes,urlSafe=false){let binary="";for(let offset=0;offset<bytes.length;offset+=32768){binary+=String.fromCharCode(...bytes.subarray(offset,offset+32768))}const base64=btoa(binary);return urlSafe?base64.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""):base64}async function fetchWithDeadline(fetcher,resource,init,timeoutMs){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(new Error("Transaction intake request timed out.")),timeoutMs);try{return await fetcher(resource,{...init,signal:controller.signal})}catch(cause){if(controller.signal.aborted){throw new TransactionIntakeClientError(504,"transaction_intake_timeout","Transaction intake request timed out.")}throw cause}finally{clearTimeout(timer)}}import{FileBackupProvider,FileRestoreReader,Zip,ZipDeflate,unzip}from"@1sat/wallet";import{createSyncMap}from"@bsv/wallet-toolbox-client";import{PrivateKey,Utils}from"@bsv/sdk";var STORAGE_COUNT_METHODS=[{method:"countUsers",table:"users"},{method:"countProvenTxs",table:"provenTxs"},{method:"countProvenTxReqs",table:"provenTxReqs"},{method:"countOutputBaskets",table:"outputBaskets"},{method:"countTransactions",table:"transactions"},{method:"countCommissions",table:"commissions"},{method:"countOutputs",table:"outputs"},{method:"countOutputTags",table:"outputTags"},{method:"countOutputTagMaps",table:"outputTagMaps"},{method:"countTxLabels",table:"txLabels"},{method:"countTxLabelMaps",table:"txLabelMaps"},{method:"countCertificates",table:"certificates"},{method:"countCertificateFields",table:"certificateFields"},{method:"countSyncStates",table:"syncStates"},{method:"countMonitorEvents",table:"monitorEvents"},{method:"countChangeInputs",table:"changeInputs"}];async function inspectWalletStorageTarget(storage){if(storage===null||storage===undefined||typeof storage!=="object"&&typeof storage!=="function"){throw new Error("A public restore-target storage provider is required.")}try{const settings=readStorageSettings(storage);const counts={};for(const entry of STORAGE_COUNT_METHODS){const method=storage[entry.method];if(typeof method!=="function"){throw new Error(`Public restore-target count ${entry.method} is unavailable.`)}const count=entry.method==="countChangeInputs"?await readChangeInputCount(storage,method):await method.call(storage,{partial:{}});if(!Number.isSafeInteger(count)||count<0){throw new Error(`Public restore-target count ${entry.method} is malformed.`)}counts[entry.table]=count}const isEmpty=Object.values(counts).every((count)=>count===0);return{chain:settings.chain,identityKey:isEmpty?null:undefined,tableCounts:counts,isEmpty}}catch(error){if(error instanceof Error&&error.message.startsWith("Public restore-target"))throw error;const detail=error instanceof Error?error.message:String(error??"unknown error");throw new Error(`Public restore-target inspection failed: ${detail.slice(0,240)}`,{cause:error})}}async function readChangeInputCount(storage,countChangeInputs){const findUsers=storage.findUsers;const findOutputBaskets=storage.findOutputBaskets;if(typeof findUsers!=="function"||typeof findOutputBaskets!=="function"){throw new Error("Public user and basket enumeration is required to prove change-input emptiness.")}const users=await findUsers.call(storage,{partial:{}});const baskets=await findOutputBaskets.call(storage,{partial:{}});if(!Array.isArray(users)||!Array.isArray(baskets)){throw new Error("Public user or basket enumeration returned malformed rows.")}const count=countChangeInputs;let total=0;for(const user of users){const userId=isRecord3(user)?user.userId:undefined;if(!Number.isSafeInteger(userId)||userId<0){throw new Error("Public user enumeration returned a malformed row.")}for(const basket of baskets){const basketId=isRecord3(basket)?basket.basketId:undefined;if(!Number.isSafeInteger(basketId)||basketId<0){throw new Error("Public basket enumeration returned a malformed row.")}const pairCount=await count.call(storage,userId,basketId,false);if(!Number.isSafeInteger(pairCount)||pairCount<0||!Number.isSafeInteger(total+pairCount)){throw new Error("Public change-input count is malformed.")}total+=pairCount}}return total}function readStorageSettings(storage){const getter=storage.getSettings??storage.getActiveSettings;if(typeof getter!=="function")throw new Error("Public restore-target storage settings are unavailable.");const settings=getter.call(storage);const chain=settings?.chain;if(chain!=="main"&&chain!=="test")throw new Error("Public restore-target storage chain is unavailable or unsupported.");return{chain}}function isRecord3(value){return Boolean(value)&&typeof value==="object"&&!Array.isArray(value)}var WALLET_DATA_ZIP_MAX_COMPRESSED_BYTES=512*1024*1024;var WALLET_DATA_ZIP_MAX_ENTRIES=4096;var WALLET_DATA_ZIP_MAX_EXPANDED_ENTRY_BYTES=64*1024*1024;var WALLET_DATA_ZIP_MAX_EXPANDED_BYTES=512*1024*1024;var WALLET_DATA_ZIP_LIMITS=Object.freeze({maxCompressedBytes:WALLET_DATA_ZIP_MAX_COMPRESSED_BYTES,maxEntries:WALLET_DATA_ZIP_MAX_ENTRIES,maxExpandedEntryBytes:WALLET_DATA_ZIP_MAX_EXPANDED_ENTRY_BYTES,maxExpandedBytes:WALLET_DATA_ZIP_MAX_EXPANDED_BYTES});function resolveWalletDataZipLimits(overrides={}){const values={maxCompressedBytes:overrides.maxCompressedBytes??WALLET_DATA_ZIP_LIMITS.maxCompressedBytes,maxEntries:overrides.maxEntries??WALLET_DATA_ZIP_LIMITS.maxEntries,maxExpandedEntryBytes:overrides.maxExpandedEntryBytes??WALLET_DATA_ZIP_LIMITS.maxExpandedEntryBytes,maxExpandedBytes:overrides.maxExpandedBytes??WALLET_DATA_ZIP_LIMITS.maxExpandedBytes};for(const[name,value]of Object.entries(values)){const ceiling=WALLET_DATA_ZIP_LIMITS[name];if(!Number.isSafeInteger(value)||value<1||value>ceiling){throw new Error(`Wallet-data ZIP ${name} must be a positive safe integer no greater than its production ceiling.`)}}if(values.maxExpandedEntryBytes>values.maxExpandedBytes){throw new Error("Wallet-data ZIP per-entry expansion limit cannot exceed total expansion limit.")}return values}var ENTITY_MAPPINGS=[{name:"provenTx",property:"provenTxs"},{name:"outputBasket",property:"outputBaskets"},{name:"outputTag",property:"outputTags"},{name:"txLabel",property:"txLabels"},{name:"transaction",property:"transactions"},{name:"output",property:"outputs"},{name:"txLabelMap",property:"txLabelMaps"},{name:"outputTagMap",property:"outputTagMaps"},{name:"certificate",property:"certificates"},{name:"certificateField",property:"certificateFields"},{name:"commission",property:"commissions"},{name:"provenTxReq",property:"provenTxReqs"}];var DEFAULT_MAX_CHUNKS=1e5;var AMBIGUOUS_RESTORE_TARGETS=new WeakSet;function requireStorage(value){if(!value||typeof value!=="object"&&typeof value!=="function"){throw new Error("A WalletStorageManager is required for wallet-data ZIP portability.")}const candidate=value;if(typeof candidate.getSettings!=="function"||typeof candidate.getAuth!=="function"||typeof candidate.syncToWriter!=="function"||typeof candidate.syncFromReader!=="function"){throw new Error("The upstream WalletStorageManager does not expose the required wallet-data sync operations.")}return candidate}function requireRestoreStorage(value){if(!value||typeof value!=="object"&&typeof value!=="function"){throw new Error("A WalletStorageManager is required for wallet-data ZIP restore.")}const candidate=value;if(typeof candidate.syncFromReader!=="function"){throw new Error("The upstream WalletStorageManager does not expose syncFromReader for wallet-data ZIP restore.")}return candidate}function assertIdentityKey(identityKey){if(!/^(02|03)[0-9a-fA-F]{64}$/.test(identityKey)){throw new Error("The wallet-data ZIP identity key is invalid.")}}function assertManifest(value){if(!value||typeof value!=="object"){throw new Error("Wallet-data ZIP manifest is missing.")}const manifest=value;if(manifest.version!==1||!Number.isSafeInteger(manifest.chunkCount)||(manifest.chunkCount??-1)<1||manifest.chain!=="main"&&manifest.chain!=="test"||typeof manifest.createdAt!=="string"||typeof manifest.identityKey!=="string"){throw new Error("Wallet-data ZIP manifest is invalid.")}assertIdentityKey(manifest.identityKey);if(!Number.isFinite(Date.parse(manifest.createdAt))){throw new Error("Wallet-data ZIP manifest has an invalid creation timestamp.")}}function assertZipEntryInfo(file,limits){if(!Number.isSafeInteger(file.size)||file.size<0||!Number.isSafeInteger(file.originalSize)||file.originalSize<0){throw new Error("Wallet-data ZIP contains an unbounded entry size.")}if(file.originalSize>limits.maxExpandedEntryBytes){throw new Error("Wallet-data ZIP entry exceeds the expanded-size limit.")}if(file.compression!==0&&file.compression!==8){throw new Error("Wallet-data ZIP uses an unsupported compression method.")}}function assertZipResourceMetadata(file,count,expandedBytes,limits){if(count>limits.maxEntries){throw new Error("Wallet-data ZIP contains too many entries.")}assertZipEntryInfo(file,limits);const nextExpandedBytes=expandedBytes+file.originalSize;if(!Number.isSafeInteger(nextExpandedBytes)||nextExpandedBytes>limits.maxExpandedBytes){throw new Error("Wallet-data ZIP exceeds the total expanded-size limit.")}return nextExpandedBytes}function assertExpandedEntries(entries,limits){let total=0;let count=0;for(const value of Object.values(entries)){count+=1;if(count>limits.maxEntries||value.byteLength>limits.maxExpandedEntryBytes){throw new Error("Wallet-data ZIP expanded entry limits were exceeded.")}total+=value.byteLength;if(!Number.isSafeInteger(total)||total>limits.maxExpandedBytes){throw new Error("Wallet-data ZIP total expanded-size limit was exceeded.")}}}function safeRestoreErrorDetail(error){let detail=error instanceof Error?error.message:String(error??"");detail=detail.replace(/[5KLc9][1-9A-HJ-NP-Za-km-z]{50,51}/g,"[redacted]").replace(/\b(?:02|03)[0-9a-f]{64}\b/gi,"[redacted]");return detail.length>180?`${detail.slice(0,177)}...`:detail}function makeAmbiguousRestoreError(error){const detail=safeRestoreErrorDetail(error);return new Error(detail?`Wallet-data ZIP restore became ambiguous after syncFromReader began; the target may be partially restored (${detail}). Do not retry this target.`:"Wallet-data ZIP restore became ambiguous after syncFromReader began; the target may be partially restored. Do not retry this target.")}function unzipArchive(bytes,limits){if(bytes.byteLength>limits.maxCompressedBytes){throw new Error("Wallet-data ZIP exceeds the 512 MiB compressed-size limit.")}return new Promise((resolve,reject)=>{let count=0;let expandedBytes=0;const names=new Set;const inspectOnly=(file)=>{if(names.has(file.name)){throw new Error("Wallet-data ZIP contains duplicate entry names.")}names.add(file.name);count+=1;expandedBytes=assertZipResourceMetadata(file,count,expandedBytes,limits);return false};try{unzip(bytes,{filter:inspectOnly},(error)=>{if(error){reject(error);return}try{unzip(bytes,(expandError,entries)=>{if(expandError){reject(expandError);return}try{assertExpandedEntries(entries,limits);resolve(entries)}catch(entryError){reject(entryError)}})}catch(expandError){reject(expandError)}})}catch(metadataError){reject(metadataError)}})}function hasData(chunk){return ENTITY_MAPPINGS.some(({property})=>{const value=chunk[property];if(value===undefined)return false;if(!Array.isArray(value)){throw new Error(`Wallet-data sync chunk field ${property} is not an array.`)}return value.length>0})}function parseManifest(entries){const manifestBytes=entries["manifest.json"];if(!manifestBytes){throw new Error("Wallet-data ZIP has no manifest.json.")}let value;try{value=JSON.parse(new TextDecoder().decode(manifestBytes))}catch{throw new Error("Wallet-data ZIP manifest is not valid JSON.")}assertManifest(value);return value}function assertOnlyStandardEntries(entries,manifest){const names=Object.keys(entries).sort();const chunkIndexes=names.filter((name)=>name!=="manifest.json").map((name)=>{const match=/^chunk-(\d+)\.bin$/.exec(name);if(!match)return null;const index=Number(match[1]);return Number.isSafeInteger(index)&&String(index).padStart(4,"0")===match[1]?index:null});chunkIndexes.sort((left,right)=>(left??Number.MAX_SAFE_INTEGER)-(right??Number.MAX_SAFE_INTEGER));const exactChunkSequence=chunkIndexes.length===manifest.chunkCount&&chunkIndexes.every((index,expectedIndex)=>index===expectedIndex);if(names.length!==manifest.chunkCount+1||!exactChunkSequence){throw new Error("Wallet-data ZIP must contain only upstream manifest and sync chunks.")}}function assertFreshRestoreInspection(inspection,expectedChain){if(inspection===undefined)return;if(!inspection||typeof inspection!=="object"||Array.isArray(inspection)){throw new Error("Wallet-data ZIP restore target freshness proof is malformed.")}if(inspection.chain===null||inspection.chain===undefined){throw new Error("Wallet-data ZIP restore target chain could not be verified.")}if(inspection.chain!==expectedChain){throw new Error("Wallet-data ZIP restore target chain does not match the archive chain.")}if(inspection.identityKey!==undefined&&inspection.identityKey!==null&&inspection.identityKey!==""){throw new Error("Wallet-data ZIP restore target is not fresh; an existing wallet identity was found.")}let allCountsZero=false;if(inspection.tableCounts!==undefined){if(!inspection.tableCounts||typeof inspection.tableCounts!=="object"||Array.isArray(inspection.tableCounts)){throw new Error("Wallet-data ZIP restore target counts are malformed.")}allCountsZero=Object.keys(inspection.tableCounts).length>0;for(const count of Object.values(inspection.tableCounts)){if(!Number.isSafeInteger(count)||count<0){throw new Error("Wallet-data ZIP restore target counts are malformed.")}if(count!==0){throw new Error("Wallet-data ZIP restore target is not empty; no import was attempted.")}}}if(inspection.isEmpty===false||inspection.isEmpty!==true&&!allCountsZero){throw new Error("Wallet-data ZIP restore target did not prove whole-store emptiness.")}}async function proveFreshRestoreTarget(options,expectedChain){if(options.inspectTarget!==undefined&&options.assertTargetFresh!==undefined){throw new Error("Wallet-data ZIP restore accepts only one target freshness proof.")}if(options.inspectTarget!==undefined||options.assertTargetFresh!==undefined){const inspect=options.inspectTarget??options.assertTargetFresh;try{assertFreshRestoreInspection(await inspect(),expectedChain);return}catch(error){if(error instanceof Error&&error.message.includes("no import was attempted"))throw error;throw error instanceof Error?error:new Error("Wallet-data ZIP restore target freshness proof failed.")}}if(!options.targetStorage){throw new Error("Wallet-data ZIP restore requires a whole-store empty-target proof before syncFromReader.")}assertFreshRestoreInspection(await inspectWalletStorageTarget(options.targetStorage),expectedChain)}class MapAppFileBackupProvider extends FileBackupProvider{expectedIdentityKey;targetSettings;maxChunks;syncMap=createSyncMap();sourceIdentityKey;sourceName;sourceUserId;initialized=false;terminal=false;failed=false;constructor(zip,settings,identityKey,options={}){super(zip,settings,identityKey);assertIdentityKey(identityKey);const maxChunks=options.maxChunks??DEFAULT_MAX_CHUNKS;if(!Number.isSafeInteger(maxChunks)||maxChunks<1){throw new Error("The wallet-data ZIP chunk limit must be a positive safe integer.")}this.expectedIdentityKey=identityKey;this.targetSettings=settings;this.maxChunks=maxChunks}hasReachedTerminalChunk(){return this.terminal}async findOrInsertSyncStateAuth(auth,storageIdentityKey,storageName){if(this.failed){throw new Error("The wallet-data ZIP export already failed; create a new provider.")}if(auth.identityKey!==this.expectedIdentityKey){throw new Error("Wallet-data export identity does not match the authenticated wallet.")}if(this.terminal){throw new Error("The wallet-data ZIP provider cannot be reused after completion; create a new provider.")}if(typeof storageIdentityKey!=="string"||storageIdentityKey.length===0||typeof storageName!=="string"||storageName.length===0){throw new Error("The wallet-data source storage settings are invalid.")}const userId=auth.userId??1;if(!Number.isSafeInteger(userId)||userId<0){throw new Error("The wallet-data source user id is invalid.")}const sourceChanged=this.sourceIdentityKey!==storageIdentityKey||this.sourceName!==storageName||this.sourceUserId!==userId;if(this.initialized&&sourceChanged){throw new Error("Wallet-data source changed during export; create a new provider.")}const isNew=!this.initialized;if(isNew){this.syncMap=createSyncMap();this.sourceIdentityKey=storageIdentityKey;this.sourceName=storageName;this.sourceUserId=userId;this.initialized=true}const now=new Date;return{syncState:{syncStateId:0,created_at:now,updated_at:now,userId,storageIdentityKey,storageName,init:false,refNum:"file-backup",status:"unknown",syncMap:JSON.stringify(this.syncMap)},isNew}}requestOffsets(args){if(!Array.isArray(args.offsets)||args.offsets.length!==ENTITY_MAPPINGS.length){throw new Error("Wallet-data sync did not provide the complete upstream entity offset sequence.")}const offsets=new Map;for(const[index,expected]of ENTITY_MAPPINGS.entries()){const actual=args.offsets[index];if(!actual||actual.name!==expected.name||!Number.isSafeInteger(actual.offset)||actual.offset<0){throw new Error(`Wallet-data sync offsets are not in upstream entity order at ${expected.name}.`)}if(offsets.has(actual.name)){throw new Error(`Wallet-data sync offsets contain a duplicate ${actual.name} entity.`)}offsets.set(actual.name,actual.offset)}return offsets}validateChunk(args,chunk){if(!this.initialized||this.sourceIdentityKey===undefined||this.sourceName===undefined){throw new Error("Wallet-data sync state was not initialized before the first chunk.")}if(args.identityKey!==this.expectedIdentityKey||chunk.userIdentityKey!==this.expectedIdentityKey){throw new Error("Wallet-data sync chunk identity does not match the export identity.")}if(args.fromStorageIdentityKey!==this.sourceIdentityKey||chunk.fromStorageIdentityKey!==args.fromStorageIdentityKey){throw new Error("Wallet-data sync chunk source does not match the initialized source storage.")}if(chunk.toStorageIdentityKey!==args.toStorageIdentityKey){throw new Error("Wallet-data sync chunk destination does not match the requested destination.")}if(this.targetSettings.storageIdentityKey!==args.toStorageIdentityKey){throw new Error("Wallet-data sync destination does not match the writer settings.")}const offsets=this.requestOffsets(args);for(const{name}of ENTITY_MAPPINGS){const expectedOffset=this.syncMap[name].count;const requestedOffset=offsets.get(name);if(requestedOffset!==expectedOffset){throw new Error(`Wallet-data sync did not converge for ${name}: expected offset ${expectedOffset}, received ${requestedOffset}.`)}}return{offsets,data:hasData(chunk)}}async processSyncChunk(args,chunk){if(this.failed){throw new Error("The wallet-data ZIP export already failed; create a new provider.")}if(this.terminal){throw new Error("Wallet-data sync produced a chunk after the terminal chunk.")}if(this.getChunkCount()>=this.maxChunks){this.failed=true;throw new Error("Wallet-data sync did not converge before the ZIP chunk limit was reached.")}try{const{offsets,data}=this.validateChunk(args,chunk);const result=await super.processSyncChunk(args,chunk);if(result.done===data){throw new Error("Upstream FileBackupProvider returned an inconsistent sync completion result.")}for(const{name,property}of ENTITY_MAPPINGS){const rows=chunk[property];if(rows===undefined)continue;if(!Array.isArray(rows)){throw new Error(`Wallet-data sync chunk field ${property} is not an array.`)}if(rows.length>0){this.syncMap[name].count=(offsets.get(name)??0)+rows.length}}if(data&&this.syncMapProgressTotal()===0){throw new Error("Wallet-data sync did not advance any entity offset.")}if(!data)this.terminal=true;return result}catch(error){this.failed=true;throw error}}syncMapProgressTotal(){return ENTITY_MAPPINGS.reduce((total,{name})=>total+this.syncMap[name].count,0)}}async function inspectWalletDataZip(bytes,expected,options={}){if(!(bytes instanceof Uint8Array)||bytes.byteLength===0){throw new Error("Choose a non-empty wallet-data ZIP.")}assertIdentityKey(expected.identityKey);const limits=resolveWalletDataZipLimits(options.limits);const entries=await unzipArchive(bytes,limits);const manifest=parseManifest(entries);if(manifest.identityKey!==expected.identityKey){throw new Error("Wallet-data ZIP identity does not match the expected wallet identity.")}if(manifest.chain!==expected.chain){throw new Error("Wallet-data ZIP chain does not match the expected wallet chain.")}assertOnlyStandardEntries(entries,manifest);return{bytes:new Uint8Array(bytes),manifest}}function collectZip(){const pieces=[];let finish;let fail;const done=new Promise((resolve,reject)=>{finish=resolve;fail=reject});let settled=false;const zip=new Zip((error,data,final)=>{if(settled)return;if(error){settled=true;fail(error);return}if(data&&data.byteLength>0)pieces.push(data);if(final){settled=true;const size=pieces.reduce((total,piece)=>total+piece.byteLength,0);const bytes=new Uint8Array(size);let offset=0;for(const piece of pieces){bytes.set(piece,offset);offset+=piece.byteLength}finish(bytes)}});return{zip,done}}async function exportWalletDataZip(storageValue,expected,options={}){const storage=requireStorage(storageValue);assertIdentityKey(expected.identityKey);const settings=storage.getSettings();if(settings.chain!==expected.chain){throw new Error("Wallet storage chain does not match export chain.")}const limits=resolveWalletDataZipLimits(options.limits);const{zip,done}=collectZip();const writer=new MapAppFileBackupProvider(zip,settings,expected.identityKey,options);const auth=await storage.getAuth(true);if(auth.identityKey!==expected.identityKey){throw new Error("Wallet-data export identity does not match the authenticated wallet.")}await storage.syncToWriter(auth,writer);if(!writer.hasReachedTerminalChunk()){throw new Error("Wallet-data sync returned before a terminal empty chunk; export did not converge.")}const manifest={version:1,createdAt:new Date().toISOString(),chain:expected.chain,identityKey:expected.identityKey,chunkCount:writer.getChunkCount()};const entry=new ZipDeflate("manifest.json",{level:6});zip.add(entry);entry.push(new TextEncoder().encode(JSON.stringify(manifest)),true);zip.end();const bytes=await done;return await inspectWalletDataZip(bytes,expected,{limits})}async function preflightReader(entries,manifest,expectedIdentityKey){const reader=new FileRestoreReader(entries,manifest);const readerSettings=await reader.makeAvailable();for(let index=0;index<manifest.chunkCount;index++){const chunk=await reader.getSyncChunk({fromStorageIdentityKey:readerSettings.storageIdentityKey,toStorageIdentityKey:"wallet-data-validation",identityKey:expectedIdentityKey,maxRoughSize:1e7,maxItems:1000,offsets:[]});if(chunk.userIdentityKey!==expectedIdentityKey){throw new Error("Wallet-data ZIP chunk identity does not match the expected wallet identity.")}}reader.reset();return reader}async function restoreWalletDataZip(storageValue,bytes,expected,options={}){const storage=requireRestoreStorage(storageValue);const targetCandidate=options.targetStorage??storage;if(typeof targetCandidate!=="object"&&typeof targetCandidate!=="function"||targetCandidate===null){throw new Error("Wallet-data ZIP restore target freshness provider is invalid.")}const targetKey=targetCandidate;if(AMBIGUOUS_RESTORE_TARGETS.has(targetKey)){throw new Error("Wallet-data ZIP restore target has an ambiguous prior sync failure; do not retry this target.")}const limits=resolveWalletDataZipLimits(options.limits);const inspected=await inspectWalletDataZip(bytes,expected,{limits});await proveFreshRestoreTarget(options,expected.chain);const entries=await unzipArchive(inspected.bytes,limits);const reader=await preflightReader(entries,inspected.manifest,expected.identityKey);await options.beforeSync?.();await proveFreshRestoreTarget(options,expected.chain);AMBIGUOUS_RESTORE_TARGETS.add(targetKey);try{await storage.syncFromReader(expected.identityKey,reader)}catch(error){throw makeAmbiguousRestoreError(error)}AMBIGUOUS_RESTORE_TARGETS.delete(targetKey);return inspected.manifest}import{Database}from"bun:sqlite";import{resolve}from"path";var AGENT_LOCAL_INTENT_MAX_CIPHERTEXT_BYTES=16*1024*1024;var AGENT_LOCAL_INTENT_MAX_NAMESPACE_BYTES=64*1024*1024;var AGENT_LOCAL_INTENT_MAX_NAMESPACE_RECORDS=1000;var MAX_IDENTIFIER_LENGTH=512;var APPLICATION_ID=1296124238;var SCHEMA_VERSION=1;var ENVELOPE_KEYS=["envelopeVersion","recordId","namespaceId","createdAt","updatedAt","ciphertext"];class AgentLocalIntentRepositoryError extends Error{code;constructor(code,message,options){super(message,options);this.code=code;this.name="AgentLocalIntentRepositoryError"}}function openAgentLocalIntentRepository(filename){if(typeof filename!=="string"||!filename.trim()||filename.includes("\x00")||filename===":memory:"||filename.startsWith("file:")){throw error("local_intent_path_invalid","A dedicated persistent local intent database filename is required.")}let database;try{database=new Database(resolve(filename),{create:true,strict:true});database.exec("PRAGMA busy_timeout = 0; PRAGMA locking_mode = EXCLUSIVE;");const applicationId=getRow(database,"PRAGMA application_id").application_id;const version=getRow(database,"PRAGMA user_version").user_version;const objects=getRows(database,"SELECT name, type FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY name");const isNew=applicationId===0&&version===0&&objects.length===0;if(!isNew&&(applicationId!==APPLICATION_ID||version!==SCHEMA_VERSION||JSON.stringify(objects)!==JSON.stringify([{name:"encrypted_intents",type:"table"},{name:"encrypted_intents_namespace",type:"index"}]))){throw error("local_intent_database_incompatible","This file is not a supported participant local intent database.")}database.exec("PRAGMA journal_mode = DELETE; PRAGMA synchronous = EXTRA; PRAGMA temp_store = MEMORY; PRAGMA journal_size_limit = 0;");const db2=database;if(getRow(db2,"PRAGMA journal_mode")?.journal_mode!=="delete"||getRow(db2,"PRAGMA synchronous")?.synchronous!==3||getRow(db2,"PRAGMA locking_mode")?.locking_mode!=="exclusive"){throw error("local_intent_durability_unavailable","The local database could not enable durable exclusive execution.")}db2.transaction(()=>{if(isNew){db2.exec(`CREATE TABLE encrypted_intents (
2
+ import{executePaidPostAction,normalizePaidPostActionOutcome,recoverPaidPostEvidence}from"./chunk-e6y2yzbj.js";import{AgentMediaError,DEFAULT_MESSAGE_PLAINTEXT_MAX_BYTES,MAPAPP_CATEGORY_TOKENS,MAPAPP_MESSAGE_BOX_NAME,MAPAPP_MESSAGE_ID_MAX_BYTES,MAPAPP_MESSAGE_VERSION,MESSAGEBOX_KEY_ID,MESSAGEBOX_PROTOCOL,MESSAGING_IDENTITY_MUTATION_VERSION,POST_GEOHASH_PATTERN,assertCanonicalIsoTimestamp,assertCompressedIdentityKey,assertMapAppMessageV1,assertMessagingIdentityV1,conversationIdForIdentityKeys,inspectAgentMedia,serializeMapAppMessageV1,serializeMessagingIdentityMutationV1,validAgentMediaInput}from"./chunk-576jrq3v.js";import{__callDispose,__require,__using}from"./chunk-btwmey1h.js";import{readFile,stat,writeFile}from"fs/promises";import{join as join2,resolve as resolve2}from"path";import{createNodeWallet}from"@1sat/wallet-node";import{createContext,resolveBapId as resolveBapId2,computeBapId,deriveDepositAddresses,syncAddresses}from"@1sat/actions";import{PrivateKey as PrivateKey2}from"@bsv/sdk";import*as z2 from"zod/v4";import{HTTPWalletJSON as HTTPWalletJSON2}from"@bsv/sdk";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_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("locked","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":if(typeof value.version!=="string"||!validVersion(value.version))throw new Error;versionObserved=true;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 validVersion(version){const bytes=new TextEncoder().encode(version).byteLength;return bytes>=7&&bytes<=30&&[...version].every((character)=>{const code=character.charCodeAt(0);return code>31&&code!==127})}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}}function createParticipantHTTPWallet(endpoint,originator){const baseUrl=trustedHTTPEndpoint(endpoint);const request=Object.assign(async(resource,init)=>{const url=new URL(typeof resource==="string"?resource:resource instanceof URL?resource.href:resource.url);const selected=new URL(baseUrl);if(url.origin!==selected.origin||!url.pathname.startsWith(selected.pathname.replace(/\/$/u,"")+"/")||url.username||url.password||url.search||url.hash)throw new Error("participant_wallet_target_invalid");const response=await fetch(url,{...init,redirect:"error",signal:AbortSignal.timeout(15000)});if(!response.body)throw new Error("participant_wallet_response_invalid");const reader=response.body.getReader(),chunks=[];let size=0;try{while(true){const{done,value}=await reader.read();if(done)break;size+=value.length;if(size>4*1024*1024){await reader.cancel();throw new Error("participant_wallet_response_too_large")}chunks.push(value)}}finally{reader.releaseLock()}const bytes=Buffer.concat(chunks);if(!response.ok){let failure={};try{failure=JSON.parse(bytes.toString())}catch{}const code=failure.code==="ERR_PERMISSION_DENIED"||typeof failure.error==="string"&&failure.error.startsWith("permission denied for ")?"ERR_PERMISSION_DENIED":response.status===503&&failure.error==="Wallet is locked"?"ERR_WALLET_LOCKED":response.status===404?"ERR_METHOD_NOT_SUPPORTED":"ERR_WALLET_HTTP";throw Object.assign(new Error("participant_wallet_request_failed"),{code})}return new Response(bytes,{status:response.status,headers:response.headers})},{preconnect:fetch.preconnect});return new HTTPWalletJSON2(originator,baseUrl,request)}var U12_SPONSOR_POLICY="mapapp-sponsored-v2";var U12_RESERVATION_TTL_MS=2*60*1000;var U12_CONTRIBUTION_WINDOW_MS=24*60*60*1000;var U12_BAP_IP_WINDOW_MS=7*24*60*60*1000;function canonicalSponsoredDraft(draft){assertSponsoredDraft(draft);const value=draft.kind==="post"?{category:draft.category,geohash:draft.geohash,kind:draft.kind,...draft.mediaSha256?{mediaSha256:draft.mediaSha256.toLowerCase()}:{},policy:U12_SPONSOR_POLICY,text:draft.text}:{kind:draft.kind,...draft.mediaSha256?{mediaSha256:draft.mediaSha256.toLowerCase()}:{},parentTxid:draft.parentTxid.toLowerCase(),policy:U12_SPONSOR_POLICY,text:draft.text};return JSON.stringify(value)}function assertSponsoredDraft(draft){if(draft.kind!=="post"&&draft.kind!=="comment")throw new Error("Unsupported sponsored contribution kind.");if(!draft.text.trim())throw new Error("Sponsored contribution text is required.");if(new TextEncoder().encode(draft.text).byteLength>280)throw new Error("Sponsored contribution text exceeds 280 UTF-8 bytes.");if(draft.mediaSha256!==undefined&&!/^[0-9a-f]{64}$/i.test(draft.mediaSha256)){throw new Error("Sponsored media hash must be SHA-256 hex.")}if(draft.kind==="post"){if(!POST_GEOHASH_PATTERN.test(draft.geohash))throw new Error("Sponsored post geohash is invalid.");if(!draft.category.trim())throw new Error("Sponsored post category is required.")}else if(!/^[0-9a-f]{64}$/i.test(draft.parentTxid)){throw new Error("Sponsored reply parent txid is invalid.")}}async function solveSponsoredPow(input){for(let attempt=0;attempt<1e6;attempt+=1){const value={...input,nonce:attempt.toString(36)};const digest=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(["mapapp-freepost-pow-v1",value.payloadHash,value.challenge.challenge,value.challenge.recentBlockHash,value.challenge.timestampWindow,String(value.challenge.difficultyBits),value.nonce].join(`
3
+ `))));if(leadingZeroBits(digest)>=value.challenge.difficultyBits)return value}throw new Error("Unable to solve sponsor proof-of-work.")}function leadingZeroBits(bytes){let total=0;for(const byte of bytes){if(byte===0){total+=8;continue}for(let bit=7;bit>=0;bit-=1){if((byte&1<<bit)===0)total+=1;else return total}}return total}async function sponsoredDraftHash(value){return[...new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(value)))].map((byte)=>byte.toString(16).padStart(2,"0")).join("")}var schema="mapapp-agent-identity-operation-v1";var uuid=(value)=>/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/u.test(value);var marker=(id)=>`agent-identity:${id}`;function createAgentIdentityExecutor(options){const binding=Object.freeze({...options.binding}),deployment=new URL(options.deployment).origin;if(!options.store.updateDraft||!options.store.persistEvidence)throw new Error("identity_retention_required");const inspector=createAgentWalletConnectionInspector({wallet:options.wallet,binding});let busy=false;const blocked=(reason)=>({kind:"blocked",reason});async function exclusive(work){if(busy)return blocked("execution_in_progress");busy=true;try{return await work()}finally{busy=false}}function prepared(record){const draft=record.draft;if(draft?.schema!==schema)return null;if(!uuid(draft.operationId)||record.reference.intentId!==marker(draft.operationId)||draft.deployment!==deployment||JSON.stringify(draft.connection)!==JSON.stringify(binding)||!["prepared","attempt_started"].includes(draft.phase))throw new Error("identity_binding_changed");return draft}async function admission(caller){const inspected=await inspector.inspect(caller);if(inspected.state!=="ready")return inspected.reason;return null}const save=(draft)=>options.store.updateDraft(marker(draft.operationId),draft);async function observation(bapId){try{const observed=await options.observed(bapId);return{publicIdentityObserved:observed,publicIdentityObservation:observed?"observed":"not_observed"}}catch{return{publicIdentityObserved:false,publicIdentityObservation:"unavailable"}}}async function reservation(draft){const{reservation:current}=await options.client.authenticatedRequest("sponsorStatus",{version:2,intentId:draft.operationId},`${deployment}/api/freeposting/u12/status`);if(!current||!uuid(current.reservationId)||current.intentId!==draft.operationId||current.kind!=="bap"||current.bapId!==draft.bapId||draft.reservationId&&current.reservationId!==draft.reservationId||!["reserved","funding","submitted","outcome_unknown","failed","expired"].includes(current.status))throw new Error("identity_reservation_changed");return current}async function recover(draft,record){if(draft.phase==="prepared")return blocked("operation_not_started");try{const current=await reservation(draft);let evidence=record.returnedEvidence;if(!evidence&&current.tx){const returned=normalizePaidPostActionOutcome("agent-wallet-node",current);if(returned.kind!=="creation_evidence"||returned.anomaly)return blocked("identity_evidence_invalid");await options.store.persistEvidence(marker(draft.operationId),returned.txid,returned.atomicBeef);evidence={txid:returned.txid,atomicBeef:Array.from(returned.atomicBeef),originator:binding.originator}}if(!evidence)return{kind:"recovery_required",operationId:draft.operationId,reason:"original_sponsor_evidence_unavailable",sponsorState:current.status};const exact=normalizePaidPostActionOutcome("agent-wallet-node",{txid:evidence.txid,tx:evidence.atomicBeef});if(evidence.originator!==binding.originator||exact.kind!=="creation_evidence"||exact.anomaly||current.tx&&(current.txid!==evidence.txid||JSON.stringify(current.tx)!==JSON.stringify(evidence.atomicBeef)))return blocked("identity_evidence_conflict");if(!draft.authorInternalized){if(!draft.fundingArgs)return blocked("identity_filing_data_missing");const args=draft.fundingArgs;await options.wallet.internalizeAction({tx:[...evidence.atomicBeef],description:args.description,labels:args.labels,outputs:(args.outputs??[]).map((output,outputIndex)=>({outputIndex,protocol:"basket insertion",insertionRemittance:{basket:output.basket??"default",tags:output.tags??[],customInstructions:output.customInstructions}}))},binding.originator);await save({...draft,reservationId:current.reservationId,authorInternalized:true})}const local=await options.published(),observed=await observation(draft.bapId);return{kind:"reconciled",operationId:draft.operationId,bapId:draft.bapId,txid:evidence.txid,sponsorState:current.status,authorInternalized:local===draft.bapId,...observed,retryAllowed:false,next:local===draft.bapId&&observed.publicIdentityObserved?"check_readiness":"check_original_identity_status"}}catch{return{kind:"recovery_required",operationId:draft.operationId,reason:"original_identity_unavailable",retryAllowed:false}}}return{prepare(caller,operationId){return exclusive(async()=>{if(!uuid(operationId))return blocked("invalid_operation_id");const denied=await admission(caller);if(denied)return blocked(denied);const records=await options.store.list(),drafts=records.map(prepared);const existing=drafts.find((draft)=>draft?.operationId===operationId);if(existing?.phase==="attempt_started")return blocked("operation_already_started");if(drafts.some((draft)=>draft?.phase==="attempt_started"))return blocked("original_identity_attempt_unresolved");if(await options.published())return blocked("identity_already_published");if(!await options.ready().catch(()=>false))return blocked("identity_sponsor_unavailable");if(!existing){if(records.some((record)=>record.reference.clientIntentId===operationId))return blocked("operation_input_conflict");const bapId=await options.bapId();const deniedAgain=await admission(caller);if(deniedAgain)return blocked(deniedAgain);await options.store.persistReference({intentId:marker(operationId),clientIntentId:operationId,nonce:`agent-identity:${operationId}`,correlationTag:`intent:agent-identity:${operationId}`},{schema,operationId,connection:binding,deployment,bapId,phase:"prepared"})}return{kind:"prepared",operationId,bapId:existing?.bapId??await options.bapId(),payer:"mapapp",authorSats:0,sponsorCost:"unknown"}})},execute(caller,operationId,signal){return exclusive(async()=>{const denied=await admission(caller);if(denied)return blocked(denied);const records=await options.store.list(),record=records.find((record2)=>prepared(record2)?.operationId===operationId);if(!record)return blocked("operation_not_prepared");const draft=prepared(record);if(draft.phase==="attempt_started")return recover(draft,record);if(records.some((value)=>{const other=prepared(value);return other?.operationId!==operationId&&other?.phase==="attempt_started"}))return blocked("original_identity_attempt_unresolved");const changed=await admission(caller);if(changed)return blocked(changed);if(signal?.aborted)return blocked("request_cancelled");if(await options.published())return blocked("identity_already_published");if(await options.bapId()!==draft.bapId||!await options.ready().catch(()=>false))return blocked("identity_prerequisite_changed");let durable={...draft,phase:"attempt_started"};await save(durable);try{const hash=await sponsoredDraftHash(`mapapp-sponsored-bap-v2
4
+ ${draft.bapId}`);const pow=await solveSponsoredPow({challenge:await options.challenge(hash),payloadHash:hash});if(signal?.aborted||await admission(caller))throw new Error("identity_binding_changed");const{reservation:current}=await options.client.authenticatedRequest("sponsorReserve",{version:2,intentId:operationId,kind:"bap",bapId:draft.bapId,pow},`${deployment}/api/freeposting/u12/reserve`);if(!current||!uuid(current.reservationId)||current.intentId!==operationId||current.kind!=="bap"||current.bapId!==draft.bapId||current.status!=="reserved")throw new Error("identity_reservation_invalid");durable={...durable,reservationId:current.reservationId};await save(durable);let fundingCalled=false;await options.invoke({fund:async(args)=>{if(fundingCalled||signal?.aborted||await admission(caller))throw new Error("identity_funding_refused");fundingCalled=true;durable={...durable,fundingArgs:structuredClone(args)};await save(durable);const returned=await options.client.authenticatedRequest("sponsorFund",{version:2,reservationId:current.reservationId,args},`${deployment}/api/freeposting/u12/fund`);const exact=normalizePaidPostActionOutcome("agent-wallet-node",returned);if(exact.kind!=="creation_evidence"||exact.anomaly)throw new Error("identity_evidence_invalid");await options.store.persistEvidence(marker(operationId),exact.txid,exact.atomicBeef);return returned}});if(await options.published()===draft.bapId){durable={...durable,authorInternalized:true};await save(durable)}const saved=(await options.store.list()).find((value)=>value.reference.intentId===marker(operationId));return recover(durable,saved)}catch{return{kind:"recovery_required",operationId,reason:"original_identity_interrupted",retryAllowed:false}}})},status(caller,operationId){return exclusive(async()=>{const inspected=await inspector.inspect(caller);if(inspected.state!=="ready")return blocked(inspected.reason);const record=(await options.store.list()).find((record2)=>prepared(record2)?.operationId===operationId);if(!record)return blocked("operation_not_prepared");const draft=prepared(record);return{kind:"status",operationId,phase:draft.phase,bapId:draft.bapId,authorInternalized:await options.published()===draft.bapId,...await observation(draft.bapId),retryAllowed:false}})},reconcile(caller,operationId){return exclusive(async()=>{const denied=await admission(caller);if(denied)return blocked(denied);const record=(await options.store.list()).find((record2)=>prepared(record2)?.operationId===operationId);return record?recover(prepared(record),record):blocked("operation_not_prepared")})}}}import*as z from"zod/v4";var participantConnectionSchema=z.object({connectionId:z.string().min(1).max(128).regex(/^[a-zA-Z0-9.:_-]+$/u),callerId:z.string().min(1).max(128).regex(/^[a-zA-Z0-9.:_-]+$/u),originator:z.string().min(1).max(128).regex(/^[a-zA-Z0-9.-]+$/u)});function supportedParticipantBinding(binding){return binding.route==="agent_environment"&&binding.declaredAuthority==="full_root_authority"||binding.route==="existing_brc100"&&binding.declaredAuthority==="provider"}function participantAuthorityName(binding){return binding.route==="existing_brc100"?"provider":"full_root_authority"}function participantProfileMatches(binding,profile){return supportedParticipantBinding(binding)&&(binding.route==="existing_brc100"?profile.transport==="brc100_http"&&profile.authority==="provider"&&profile.qualification==="participant_release"&&profile.connectionReceipt==="mapapp-705.32":profile.transport==="direct_wallet_node"&&profile.authority==="full_root_authority"&&(profile.qualification==="participant_release"&&profile.connectionReceipt==="mapapp-705.31"||["controlled_fixture","operator_authorized_proof"].includes(profile.qualification)&&profile.connectionReceipt==="mapapp-705.21"))}function createAgentPaidPostExecutor(options){const binding=Object.freeze({...options.binding});const profile=Object.freeze({...options.proofProfile});const deployment=new URL(options.deployment).origin;if(!participantProfileMatches(binding,profile)||!options.store.updateDraft||!options.store.persistEvidence)throw new Error("agent_executor_configuration_invalid");const inspector=createAgentWalletConnectionInspector({wallet:options.wallet,binding});let busy=false;const blocked=(reason)=>({kind:"blocked",reason});const marker2=(id)=>`agent-prepared:${id}`;async function records(){return await options.store.list()}function prepared(record){const draft=record.draft;if(draft?.schema!=="mapapp-agent-paid-root-operation-v1")return null;if(record.reference.intentId!==marker2(draft.operationId)||!uuid2(draft.intakeId)||!sameBinding(draft.connection,binding)||draft.deployment!==deployment||!["prepared","attempt_started"].includes(draft.phase))throw new Error("agent_operation_binding_invalid");return draft}async function admission(caller,input){const state=await inspector.inspect(caller);if(state.state!=="ready")return state.reason;const gates=await options.gates().catch(()=>null);if(!gates)return"prerequisite_unavailable";if(!gates.stackReady||!gates.intakeReady||!gates.paidRootEnabled||!gates.identityReady)return"prerequisite_blocked";if(input&&(gates.freshnessLockSats!==undefined&&input.freshnessLockSats!==gates.freshnessLockSats||gates.blockHeight!==undefined&&input.freshnessUnlockHeight<=gates.blockHeight))return"publication_policy_changed";return null}async function exclusive(work){if(busy)return blocked("execution_in_progress");busy=true;try{return await work()}finally{busy=false}}async function reconcilePrepared(draft,currentRecords){if(draft.phase==="prepared")return blocked("operation_not_started");const matches=currentRecords.filter((record)=>record.reference.intentId===draft.intakeId);if(matches.length>1)return{kind:"recovery_required",operationId:draft.operationId,reason:"reference_conflict"};let evidence=matches[0]?.returnedEvidence;try{if(!evidence&&matches[0]){const recovered=await recoverPaidPostEvidence({wallet:options.wallet,correlationTag:matches[0].reference.correlationTag,evidenceFormat:"mapapp_post_v2"});if(recovered.kind==="recovered"){await options.store.persistEvidence(draft.intakeId,recovered.txid,recovered.atomicBeef);evidence={txid:recovered.txid,atomicBeef:Array.from(recovered.atomicBeef),originator:binding.originator}}}if(evidence){if(evidence.originator!==binding.originator)return blocked("evidence_originator_changed");await options.client.submitEvidence(draft.intakeId,evidence.txid,new Uint8Array(evidence.atomicBeef))}return{kind:"reconciled",operationId:draft.operationId,intake:await options.client.statusIntent(draft.intakeId),evidenceResubmitted:!!evidence}}catch{return{kind:"recovery_required",operationId:draft.operationId,reason:"original_intake_unavailable"}}}return{prepare(caller,request){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");if(!uuid2(request.operationId)||!validInput(request.input))return blocked("invalid_text_post_input");if(request.maxTotalSats!==undefined)return blocked("spending_cap_unenforceable");const input=canonicalInput(request.input);const existing=(await records()).map(prepared).find((draft2)=>draft2?.operationId===request.operationId);if(existing){if(JSON.stringify(existing.input)!==JSON.stringify(input))return blocked("operation_input_conflict");if(existing.phase!=="prepared")return blocked("operation_already_started");const denied2=await admission(caller,input);if(denied2)return blocked(denied2);try{const media2=input.media?(await inspectAgentMedia(input.media)).summary:undefined;return{kind:"prepared",operationId:request.operationId,authority:participantAuthorityName(binding),spendingCap:"not_enforced",...media2?{media:media2}:{}}}catch(error){return blocked(error instanceof AgentMediaError?error.code:"media_inspection_unavailable")}}const denied=await admission(caller,input);if(denied)return blocked(denied);let media;try{if(input.media)media=(await inspectAgentMedia(input.media)).summary}catch(error){return blocked(error instanceof AgentMediaError?error.code:"media_inspection_unavailable")}const draft={schema:"mapapp-agent-paid-root-operation-v1",operationId:request.operationId,intakeId:crypto.randomUUID(),connection:binding,deployment,input,phase:"prepared"};const nonce=`agent-local:${request.operationId}`;await options.store.persistReference({intentId:marker2(request.operationId),nonce,correlationTag:`intent:${nonce}`,clientIntentId:request.operationId,evidenceFormat:"mapapp_post_v2"},draft);return{kind:"prepared",operationId:request.operationId,authority:participantAuthorityName(binding),spendingCap:"not_enforced",...media?{media}:{}}})},execute(caller,operationId,signal){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");if(signal?.aborted)return blocked("request_cancelled");const currentRecords=await records();const drafts=currentRecords.map(prepared).filter((value)=>!!value);const draft=drafts.find((value)=>value.operationId===operationId);if(!draft)return blocked("operation_not_prepared");const denied=await admission(caller,draft.input);if(denied)return blocked(denied);if(draft.phase==="attempt_started")return reconcilePrepared(draft,currentRecords);let publication;try{const{media,...fields}=draft.input;publication={...fields,...media?{media:(await inspectAgentMedia(media)).media}:{}}}catch(error){return blocked(error instanceof AgentMediaError?error.code:"media_inspection_unavailable")}for(const prior of drafts.filter((value)=>value.phase==="attempt_started")){const status=await options.client.statusIntent(prior.intakeId).catch(()=>null);if(!status||status.projectionState!=="live")return blocked("unresolved_operation")}for(const record of currentRecords){const prior=record.draft;if(!["mapapp-agent-sponsored-operation-v1","mapapp-agent-social-operation-v1"].includes(prior?.schema??"")||prior?.phase!=="attempt_started")continue;const status=await options.client.statusIntent(prior.intakeId).catch(()=>null);if(!status||status.projectionState!=="live")return blocked("unresolved_operation")}if(signal?.aborted)return blocked("request_cancelled");await options.store.updateDraft(marker2(operationId),{...draft,phase:"attempt_started"});try{const result=await executePaidPostAction({provider:"agent-wallet-node",providerAttested:false,agentProofProfile:profile,client:options.client,clientIntentId:operationId,intentId:draft.intakeId,tabId:binding.connectionId,localIntentStore:options.store,draft:{schema:"mapapp-agent-paid-root-intake-v1",operationId,input:draft.input},evidenceFormat:"mapapp_post_v2",actionKind:"post",actionLabelEnabled:true,invoke:async(metadata)=>{const changed=await admission(caller,draft.input);if(changed||signal?.aborted)throw new Error("agent_pre_dispatch_binding_or_prerequisite_changed");return options.invoke(publication,metadata)}});return{kind:"execution",operationId,result}}catch{return{kind:"recovery_required",operationId,reason:"original_operation_interrupted"}}})},status(caller,operationId){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");const state=await inspector.inspect(caller);if(state.state!=="ready")return blocked(state.reason);const draft=(await records()).map(prepared).find((value)=>value?.operationId===operationId);if(!draft)return blocked("operation_not_prepared");if(draft.phase==="prepared")return{kind:"status",operationId,phase:draft.phase};try{return{kind:"status",operationId,phase:draft.phase,intake:await options.client.statusIntent(draft.intakeId)}}catch{return{kind:"recovery_required",operationId,reason:"original_intake_unavailable"}}})},reconcile(caller,operationId){return exclusive(async()=>{const connection=await inspector.inspect(caller);if(connection.state!=="ready")return blocked(connection.reason);if(caller!==binding.callerId)return blocked("caller_mismatch");const state=await inspector.inspect(caller);if(state.state!=="ready")return blocked(state.reason);const currentRecords=await records();const draft=currentRecords.map(prepared).find((value)=>value?.operationId===operationId);return draft?reconcilePrepared(draft,currentRecords):blocked("operation_not_prepared")})}}}function uuid2(value){return typeof value==="string"&&/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(value)}function sameBinding(left,right){return!!left&&Object.keys(right).every((key)=>left[key]===right[key])}function canonicalInput(input){return{text:input.text,geohash:input.geohash,category:input.category,freshnessLockOutputsEnabled:true,freshnessLockSats:input.freshnessLockSats,freshnessUnlockHeight:input.freshnessUnlockHeight,freshnessDuration:input.freshnessDuration,...input.media?{media:{contentType:input.media.contentType,base64:input.media.base64,byteSize:input.media.byteSize,sha256:input.media.sha256}}:{}}}function validInput(input){return!!input&&(input.media===undefined||validAgentMediaInput(input.media))&&typeof input.text==="string"&&!!input.text.trim()&&new TextDecoder().decode(new TextEncoder().encode(input.text))===input.text&&Object.keys(input).every((key)=>["text","geohash","category","freshnessLockOutputsEnabled","freshnessLockSats","freshnessUnlockHeight","freshnessDuration","media"].includes(key))&&new TextEncoder().encode(input.text).length<=16384&&typeof input.geohash==="string"&&POST_GEOHASH_PATTERN.test(input.geohash)&&MAPAPP_CATEGORY_TOKENS.includes(input.category)&&input.freshnessLockOutputsEnabled===true&&Number.isSafeInteger(input.freshnessLockSats)&&input.freshnessLockSats>0&&Number.isSafeInteger(input.freshnessUnlockHeight)&&input.freshnessUnlockHeight>0&&input.freshnessUnlockHeight<500000000&&["1D","7D","1M","3M"].includes(input.freshnessDuration)}var MAPAPP_LOCAL_INTENT_PROTOCOL=[2,"mapapp local intent index"];var LOCAL_INTENT_NAMESPACE_KEY_ID="mapapp local intent namespace v1";var LOCAL_INTENT_KEY_ID="mapapp local intent record v1";var LOCAL_INTENT_DATABASE_NAME="mapapp-local-intents";var DATABASE_VERSION=1;var RECORD_STORE="encrypted-intents";var ENVELOPE_VERSION=1;var CONTENT_VERSION=1;class LocalIntentStoreError extends Error{code;constructor(code,message,options){super(message,options);this.code=code;this.name="LocalIntentStoreError"}}function createLocalIntentStore(options){const originator=requireOriginator(options.originator);const repository=options.repository??createIndexedDbLocalIntentRepository(resolveIndexedDb(options.indexedDB));const now=options.now??(()=>new Date);const randomUUID=options.randomUUID??(()=>{if(typeof globalThis.crypto?.randomUUID!=="function"){throw new LocalIntentStoreError("secure_record_id_unavailable","Secure local intent record identifiers are unavailable.")}return globalThis.crypto.randomUUID()});async function namespaceId(){try{const result=await options.wallet.getPublicKey({protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_NAMESPACE_KEY_ID,counterparty:"self",forSelf:true},originator);if(typeof result.publicKey!=="string"||!result.publicKey.trim()){throw new Error("Wallet returned an empty namespace public key.")}return result.publicKey}catch(cause){throw wrapError("wallet_namespace_unavailable","The connected wallet could not open its local intent namespace.",cause)}}return{namespaceId,async persistReference(reference,draft){requireReference(reference);const walletNamespace=await namespaceId();const timestamp=now().toISOString();const record={version:CONTENT_VERSION,recordId:randomUUID(),namespaceId:walletNamespace,createdAt:timestamp,updatedAt:timestamp,reference:{...reference},...draft===undefined?{}:{draft}};let ciphertext;try{const encrypted=await options.wallet.encrypt({plaintext:[...new TextEncoder().encode(JSON.stringify(record))],protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);ciphertext=requireBytes(encrypted.ciphertext,"Wallet returned invalid local intent ciphertext.")}catch(cause){throw wrapError("wallet_encryption_failed","The connected wallet refused or failed local intent encryption.",cause)}const envelope={envelopeVersion:ENVELOPE_VERSION,recordId:record.recordId,namespaceId:walletNamespace,createdAt:timestamp,updatedAt:timestamp,ciphertext};try{await repository.put(envelope)}catch(cause){throw wrapError("local_intent_commit_failed","The encrypted local intent reference could not be committed to IndexedDB.",cause)}return record},async list(){const walletNamespace=await namespaceId();let envelopes;try{envelopes=await repository.list(walletNamespace)}catch(cause){throw wrapError("local_intent_read_failed","The encrypted local intent index could not be read from IndexedDB.",cause)}const records=[];for(const envelope of envelopes){requireEnvelope(envelope,walletNamespace);let plaintext;try{const decrypted=await options.wallet.decrypt({ciphertext:[...envelope.ciphertext],protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);plaintext=requireBytes(decrypted.plaintext,"Wallet returned invalid local intent plaintext.",true)}catch(cause){throw wrapError("wallet_decryption_failed","The connected wallet could not decrypt its local intent index.",cause)}const record=parseRecord(plaintext);if(record.recordId!==envelope.recordId||record.namespaceId!==envelope.namespaceId||record.createdAt!==envelope.createdAt){throw new LocalIntentStoreError("local_intent_envelope_mismatch","Encrypted local intent metadata does not match its authenticated content.")}records.push(record)}return records.sort((left,right)=>left.createdAt.localeCompare(right.createdAt)||left.recordId.localeCompare(right.recordId))},async persistEvidence(intentId,txid,atomicBeef){if(!/^[0-9a-f]{64}$/.test(txid)||!atomicBeef.length||atomicBeef.length>2*1024*1024){throw new LocalIntentStoreError("local_evidence_invalid","Exact returned transaction evidence is invalid.")}const matches=(await this.list()).filter((record2)=>record2.reference.intentId===intentId);if(matches.length!==1)throw new LocalIntentStoreError("local_evidence_reference_conflict","Exact evidence requires one wallet-owned intent reference.");const record=matches[0];if(record.returnedEvidence&&(record.returnedEvidence.txid!==txid||JSON.stringify(record.returnedEvidence.atomicBeef)!==JSON.stringify(Array.from(atomicBeef)))){throw new LocalIntentStoreError("local_evidence_conflict","The intent already retains different transaction evidence.")}const updated={...record,updatedAt:now().toISOString(),returnedEvidence:{txid,atomicBeef:Array.from(atomicBeef),originator}};const encrypted=await options.wallet.encrypt({plaintext:Array.from(new TextEncoder().encode(JSON.stringify(updated))),protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);await repository.put({envelopeVersion:ENVELOPE_VERSION,recordId:record.recordId,namespaceId:record.namespaceId,createdAt:record.createdAt,updatedAt:updated.updatedAt,ciphertext:requireBytes(encrypted.ciphertext,"Wallet returned invalid local intent ciphertext.")})},async updateDraft(intentId,draft){const matches=(await this.list()).filter((record2)=>record2.reference.intentId===intentId);if(matches.length!==1)throw new LocalIntentStoreError("local_draft_reference_conflict","Draft update requires one wallet-owned reference.");const record=matches[0];const updated={...record,updatedAt:now().toISOString(),draft};const encrypted=await options.wallet.encrypt({plaintext:Array.from(new TextEncoder().encode(JSON.stringify(updated))),protocolID:MAPAPP_LOCAL_INTENT_PROTOCOL,keyID:LOCAL_INTENT_KEY_ID,counterparty:"self"},originator);await repository.put({envelopeVersion:ENVELOPE_VERSION,recordId:record.recordId,namespaceId:record.namespaceId,createdAt:record.createdAt,updatedAt:updated.updatedAt,ciphertext:requireBytes(encrypted.ciphertext,"Wallet returned invalid local intent ciphertext.")})},async forgetCurrentWallet(){const walletNamespace=await namespaceId();try{await repository.deleteNamespace(walletNamespace)}catch(cause){throw wrapError("local_intent_forget_failed","The wallet's encrypted local intent index could not be removed.",cause)}}}}function createIndexedDbLocalIntentRepository(indexedDB){return{async put(record){requireEnvelope(record,record.namespaceId);const database=await openDatabase(indexedDB);try{await runTransaction(database,"readwrite",(store)=>store.put(cloneEnvelope(record)))}finally{database.close()}},async list(namespaceId){const database=await openDatabase(indexedDB);try{const records=await runTransaction(database,"readonly",(store)=>store.index("namespaceId").getAll(namespaceId));return records.map(cloneEnvelope)}finally{database.close()}},async deleteNamespace(namespaceId){const database=await openDatabase(indexedDB);try{await new Promise((resolve,reject)=>{const transaction=database.transaction(RECORD_STORE,"readwrite");const request=transaction.objectStore(RECORD_STORE).index("namespaceId").openKeyCursor(namespaceId);request.onsuccess=()=>{const cursor=request.result;if(!cursor)return;transaction.objectStore(RECORD_STORE).delete(cursor.primaryKey);cursor.continue()};transaction.oncomplete=()=>resolve();transaction.onerror=()=>reject(transaction.error??new Error("IndexedDB delete transaction failed."));transaction.onabort=()=>reject(transaction.error??new Error("IndexedDB delete transaction was aborted."))})}finally{database.close()}}}}function resolveIndexedDb(indexedDB){const resolved=indexedDB??(typeof globalThis.indexedDB==="undefined"?undefined:globalThis.indexedDB);if(!resolved)throw new LocalIntentStoreError("indexeddb_unavailable","IndexedDB is required for the encrypted local intent index.");return resolved}function openDatabase(indexedDB){return new Promise((resolve,reject)=>{const request=indexedDB.open(LOCAL_INTENT_DATABASE_NAME,DATABASE_VERSION);request.onupgradeneeded=()=>{const database=request.result;if(!database.objectStoreNames.contains(RECORD_STORE)){const store=database.createObjectStore(RECORD_STORE,{keyPath:"recordId"});store.createIndex("namespaceId","namespaceId",{unique:false})}};request.onsuccess=()=>resolve(request.result);request.onerror=()=>reject(request.error??new Error("Could not open the local intent IndexedDB database."));request.onblocked=()=>reject(new Error("Close other MapApp tabs before upgrading the local intent index."))})}function runTransaction(database,mode,operation){return new Promise((resolve,reject)=>{const transaction=database.transaction(RECORD_STORE,mode);const request=operation(transaction.objectStore(RECORD_STORE));let result;request.onsuccess=()=>{result=request.result};request.onerror=()=>reject(request.error??new Error("IndexedDB request failed."));transaction.oncomplete=()=>resolve(result);transaction.onerror=()=>reject(transaction.error??new Error("IndexedDB transaction failed."));transaction.onabort=()=>reject(transaction.error??new Error("IndexedDB transaction was aborted."))})}function parseRecord(bytes){let value;try{value=JSON.parse(new TextDecoder("utf-8",{fatal:true}).decode(new Uint8Array(bytes)))}catch(cause){throw wrapError("local_intent_content_corrupt","Decrypted local intent content is invalid.",cause)}if(!isRecord2(value)||value.version!==CONTENT_VERSION||!isNonEmptyString(value.recordId)||!isNonEmptyString(value.namespaceId)||!isIsoTimestamp(value.createdAt)||!isIsoTimestamp(value.updatedAt)||!isReference(value.reference)){throw new LocalIntentStoreError("local_intent_content_corrupt","Decrypted local intent content has an unsupported or corrupt shape.")}return value}function requireEnvelope(value,namespaceId){if(!isRecord2(value)||value.envelopeVersion!==ENVELOPE_VERSION||!isNonEmptyString(value.recordId)||value.namespaceId!==namespaceId||!isIsoTimestamp(value.createdAt)||!isIsoTimestamp(value.updatedAt)){throw new LocalIntentStoreError("local_intent_envelope_corrupt","Encrypted local intent metadata has an unsupported or corrupt shape.")}requireBytes(value.ciphertext,"Encrypted local intent ciphertext is invalid.")}function requireReference(value){if(!isReference(value)||value.correlationTag!==`intent:${value.nonce}`){throw new LocalIntentStoreError("local_intent_reference_invalid","The caller-known local intent reference is invalid.")}}function isReference(value){return isRecord2(value)&&isNonEmptyString(value.intentId)&&isNonEmptyString(value.nonce)&&isNonEmptyString(value.correlationTag)&&isNonEmptyString(value.clientIntentId)&&(value.evidenceFormat===undefined||value.evidenceFormat==="mapapp_post_v1"||value.evidenceFormat==="mapapp_post_v2"||value.evidenceFormat==="mapapp_social_v2"||value.evidenceFormat==="mapapp_sponsored_v2"||value.evidenceFormat==="mapapp_upgrade_v2"||value.evidenceFormat==="mapapp_direct_bsv_v1"||value.evidenceFormat==="mapapp_bap_alias_v1")}function requireBytes(value,message,allowEmpty=false){if(!Array.isArray(value)||!allowEmpty&&value.length===0||value.some((byte)=>!Number.isInteger(byte)||byte<0||byte>255)){throw new LocalIntentStoreError("local_intent_bytes_invalid",message)}return[...value]}function cloneEnvelope(value){return{...value,ciphertext:[...value.ciphertext]}}function requireOriginator(value){const originator=value.trim();if(!originator)throw new LocalIntentStoreError("originator_required","A MapApp originator is required for wallet-owned local encryption.");return originator}function isIsoTimestamp(value){return typeof value==="string"&&Number.isFinite(Date.parse(value))}function isNonEmptyString(value){return typeof value==="string"&&value.length>0}function isRecord2(value){return typeof value==="object"&&value!==null}function wrapError(code,message,cause){if(cause instanceof LocalIntentStoreError)return cause;const detail=cause instanceof Error&&cause.message?` ${cause.message}`:"";return new LocalIntentStoreError(code,`${message}${detail}`,{cause})}async function executePaidRootPost(actionContext,input,metadata,execute){if(!input.text.trim())return{error:"MapApp Post v2 requires non-empty text."};if(input.freshnessLockOutputsEnabled!==true||!input.freshnessUnlockHeight||!input.freshnessLockSats||!input.freshnessDuration){return{error:"MapApp Post v2 freshness output settings are incomplete."}}const[{applyBapAip,executeTrackedAction,P1SAT_PROTOCOL}]=await Promise.all([import("@1sat/actions")]);const unsignedRoot=await preparePaidRootPostScriptObject(input);const signedRoot=await applyBapAip(actionContext,unsignedRoot);const lockKey=await actionContext.wallet.getPublicKey({protocolID:P1SAT_PROTOCOL,keyID:"lock",counterparty:"self",forSelf:true});const args=await assemblePaidRootPostAction(input,metadata,signedRoot.toHex(),lockKey.publicKey);const result=await(execute??((args2)=>executeTrackedAction(actionContext.wallet,args2)))(args);if(result.error==="broadcast-success"){const{recoverPaidPostEvidence:recoverPaidPostEvidence2}=await import("./chunk-c74qq5ek.js");const recovered=await recoverPaidPostEvidence2({wallet:actionContext.wallet,correlationTag:metadata.outputTags[0],evidenceFormat:"mapapp_post_v2"});if(recovered.kind==="recovered"){return{txid:recovered.txid,tx:Array.from(recovered.atomicBeef)}}}return{txid:result.txid,tx:result.tx,error:result.error}}async function preparePaidRootPostScriptObject(input){const[{B,BitCom,MAP:MAPTemplate},{OP,Script}]=await Promise.all([import("@1sat/templates"),import("@bsv/sdk")]);const textProtocol=oneBitComProtocol(BitCom,B.text(input.text,"text/plain"));const mapProtocol=oneBitComProtocol(BitCom,MAPTemplate.set({app:"mapapp",type:"post",context:"geohash",contextValue:input.geohash,category:input.category}));const bareUnsignedRoot=new BitCom([{...textProtocol,pos:0},{...mapProtocol,pos:1}]).lock();return new Script([{op:OP.OP_FALSE},...bareUnsignedRoot.chunks])}async function assemblePaidRootPostAction(input,metadata,signedRootScriptHex,lockPublicKey){const[{BSOCIAL_BASKET,P1SAT_PROTOCOL},{B,BitCom,Lock},{OP,PublicKey:PublicKey2,Script},{LOCK_BASKET}]=await Promise.all([import("@1sat/actions"),import("@1sat/templates"),import("@bsv/sdk"),import("@1sat/types")]);const locker=PublicKey2.fromString(lockPublicKey).toAddress();const freshnessScript=Lock.lock(locker,input.freshnessUnlockHeight);const outputs=[{lockingScript:signedRootScriptHex,satoshis:0,outputDescription:"MapApp Post v2 social root",basket:BSOCIAL_BASKET,tags:[...metadata.outputTags]}];if(input.media){outputs.push({lockingScript:new Script([{op:OP.OP_FALSE},...new BitCom([{...oneBitComProtocol(BitCom,B.binary(input.media.bytes,input.media.contentType)),pos:0}]).lock().chunks]).toHex(),satoshis:0,outputDescription:`MapApp Post v2 ${input.media.kind} media`})}outputs.push({lockingScript:freshnessScript.toHex(),satoshis:input.freshnessLockSats,outputDescription:`Genesis freshness lock until block ${input.freshnessUnlockHeight}`,basket:LOCK_BASKET,tags:["app:mapapp","type:freshness","kind:genesis",`until:${input.freshnessUnlockHeight}`,`duration:${input.freshnessDuration}`],customInstructions:JSON.stringify({protocolID:P1SAT_PROTOCOL,keyID:"lock",app:"mapapp",kind:"genesis-freshness"})});return{description:input.media?`MapApp Post v2 with ${input.media.kind} media`:"MapApp Post v2 text post",outputs,labels:metadata.labels,options:{acceptDelayedBroadcast:false,randomizeOutputs:false}}}function oneBitComProtocol(BitComTemplate,script){const decoded=BitComTemplate.decode(script);if(!decoded||decoded.protocols.length!==1){throw new Error("Public protocol template did not produce one BitCom section.")}return decoded.protocols[0]}import{createAuthProof}from"@bsv/auth";var MAPAPP_AUTH_PROTOCOL=[2,"mapapp transaction intake"];var MAPAPP_AUTH_ACTIONS={create:"mapapp create transaction intent",claim:"mapapp claim wallet invocation",evidence:"mapapp submit transaction evidence",outcome:"mapapp record wallet outcome",terminate:"mapapp terminate unused transaction intent",status:"mapapp read transaction intent status",sponsorReserve:"mapapp reserve sponsored wallet action",sponsorFund:"mapapp fund sponsored wallet action",sponsorStatus:"mapapp read sponsored wallet action",thumbnailIssue:"mapapp issue thumbnail upload capability",thumbnailStage:"mapapp stage intent thumbnail",retainedMediaStage:"mapapp stage retained media"};function createTransactionIntakeClient(options){const fetcher=options.fetch??globalThis.fetch;const baseUrl=(options.baseUrl??"/api/transaction-intakes").replace(/\/$/,"");const requestTimeoutMs=options.requestTimeoutMs??1e4;let cachedConfig=null;let configRequest=null;async function readAuthConfig(){const now=Date.now();if(cachedConfig&&cachedConfig.expiresAt>now)return cachedConfig.value;if(!configRequest){const pending=(async()=>{const configResponse=await fetchWithDeadline(fetcher,`${baseUrl}/auth-config`,{headers:{accept:"application/json"}},requestTimeoutMs);const config=await readJson(configResponse);cachedConfig={value:config,expiresAt:Date.now()+Math.min(30000,Math.max(1000,config.proofLifetimeMs/4))};return config})().finally(()=>{if(configRequest===pending)configRequest=null});configRequest=pending}return configRequest}async function request(operation,body){const config=await readAuthConfig();requireEnabledConfig(config,operation);const rawBody=new TextEncoder().encode(JSON.stringify(body));const proof=await createAuthProof({wallet:options.wallet,counterparty:config.verifierIdentityKey,action:MAPAPP_AUTH_ACTIONS[operation],body:rawBody,protocol:MAPAPP_AUTH_PROTOCOL,windowMs:config.proofLifetimeMs});const response=await fetchWithDeadline(fetcher,`${baseUrl}/${operation}`,{method:"POST",headers:{"content-type":"application/json",accept:"application/json","x-mapapp-brc138-proof":encodeProof(proof)},body:rawBody},requestTimeoutMs);const result=await readJson(response);if(!response.ok){if(response.status===401||response.status===403){cachedConfig=null;configRequest=null}throw new TransactionIntakeClientError(response.status,result.code??"transaction_intake_request_failed",result.message??"Transaction intake request failed.")}return result}return{async createIntent(clientIntentId,intentId,actionKind="post",actionTarget){return request("create",{version:1,intentId,clientIntentId,actionKind,...actionTarget?{actionTarget}:{}})},async claimInvocation(intentId,tabId){return request("claim",{version:1,intentId,tabId})},async submitEvidence(intentId,subjectTxid,atomicBeef,profileControl,profileAliasOutpoint){return request("evidence",{version:1,intentId,subjectTxid,atomicBeefBase64:encodeBytes(atomicBeef),...profileControl?{profileControl}:{},...profileAliasOutpoint?{profileAliasOutpoint}:{}})},async recordOutcome(intentId,state,subjectTxid){await request("outcome",{version:1,intentId,state,...subjectTxid?{subjectTxid}:{}})},async terminateIntent(intentId,code){await request("terminate",{version:1,intentId,code})},async statusIntent(intentId){const result=await request("status",{version:1,intentId});return result.intake},async authenticatedRequest(operation,body,path){let target=path;if(/^https?:\/\//u.test(baseUrl)){const configured=new URL(baseUrl),selected=new URL(path,configured);if(selected.origin!==configured.origin)throw new TransactionIntakeClientError(400,"wallet_request_origin_mismatch","Authenticated requests must use the configured MapApp origin.");target=selected.toString()}else if(!path.startsWith("/api/")||path.startsWith("//")){throw new TransactionIntakeClientError(400,"wallet_request_origin_mismatch","Authenticated requests must use a same-origin MapApp API path.")}const config=await readAuthConfig();requireEnabledConfig(config,operation);const rawBody=new TextEncoder().encode(JSON.stringify(body));const proof=await createAuthProof({wallet:options.wallet,counterparty:config.verifierIdentityKey,action:MAPAPP_AUTH_ACTIONS[operation],body:rawBody,protocol:MAPAPP_AUTH_PROTOCOL,windowMs:config.proofLifetimeMs});const response=await fetchWithDeadline(fetcher,target,{method:"POST",headers:{"content-type":"application/json",accept:"application/json","x-mapapp-brc138-proof":encodeProof(proof)},body:rawBody},requestTimeoutMs);const result=await readJson(response);if(!response.ok){if(response.status===401||response.status===403){cachedConfig=null;configRequest=null}throw new TransactionIntakeClientError(response.status,result.code??"sponsor_request_failed",result.message??"Sponsor request failed.")}return result},async stageThumbnail(intentId,mediaSlot,sourceSha256,bytes){await this.authenticatedRequest("thumbnailStage",{version:1,intentId,mediaSlot,sourceSha256:sourceSha256.toLowerCase(),thumbnailBase64:encodeBytes(bytes)},`/api/media/thumbnail-stages/${encodeURIComponent(intentId)}`)},async stageRetainedMedia(intentId,media){return this.authenticatedRequest("retainedMediaStage",{version:1,intentId,media},"/api/media/freeposts")}}}class TransactionIntakeClientError extends Error{status;code;constructor(status,code,message){super(message);this.status=status;this.code=code;this.name="TransactionIntakeClientError"}}function requireEnabledConfig(config,operation){if(!config.enabled||!config.verifierIdentityKey){throw new TransactionIntakeClientError(503,"wallet_request_proof_disabled",`Transaction intake is disabled: ${config.disabledReasons?.join(", ")||"verifier unavailable"}.`)}if(JSON.stringify(config.protocol)!==JSON.stringify(MAPAPP_AUTH_PROTOCOL)||config.actions?.[operation]!==MAPAPP_AUTH_ACTIONS[operation]){throw new TransactionIntakeClientError(503,"wallet_request_proof_contract_mismatch","Transaction intake authentication does not match the pinned MapApp contract.")}}async function readJson(response){try{return await response.json()}catch{throw new TransactionIntakeClientError(response.status,"transaction_intake_invalid_response","Transaction intake returned an invalid response.")}}function encodeProof(proof){return encodeBytes(new TextEncoder().encode(JSON.stringify(proof)),true)}function encodeBytes(bytes,urlSafe=false){let binary="";for(let offset=0;offset<bytes.length;offset+=32768){binary+=String.fromCharCode(...bytes.subarray(offset,offset+32768))}const base64=btoa(binary);return urlSafe?base64.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""):base64}async function fetchWithDeadline(fetcher,resource,init,timeoutMs){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(new Error("Transaction intake request timed out.")),timeoutMs);try{return await fetcher(resource,{...init,signal:controller.signal})}catch(cause){if(controller.signal.aborted){throw new TransactionIntakeClientError(504,"transaction_intake_timeout","Transaction intake request timed out.")}throw cause}finally{clearTimeout(timer)}}import{FileBackupProvider,FileRestoreReader,Zip,ZipDeflate,unzip}from"@1sat/wallet";import{createSyncMap}from"@bsv/wallet-toolbox-client";import{PrivateKey,Utils}from"@bsv/sdk";var STORAGE_COUNT_METHODS=[{method:"countUsers",table:"users"},{method:"countProvenTxs",table:"provenTxs"},{method:"countProvenTxReqs",table:"provenTxReqs"},{method:"countOutputBaskets",table:"outputBaskets"},{method:"countTransactions",table:"transactions"},{method:"countCommissions",table:"commissions"},{method:"countOutputs",table:"outputs"},{method:"countOutputTags",table:"outputTags"},{method:"countOutputTagMaps",table:"outputTagMaps"},{method:"countTxLabels",table:"txLabels"},{method:"countTxLabelMaps",table:"txLabelMaps"},{method:"countCertificates",table:"certificates"},{method:"countCertificateFields",table:"certificateFields"},{method:"countSyncStates",table:"syncStates"},{method:"countMonitorEvents",table:"monitorEvents"},{method:"countChangeInputs",table:"changeInputs"}];async function inspectWalletStorageTarget(storage){if(storage===null||storage===undefined||typeof storage!=="object"&&typeof storage!=="function"){throw new Error("A public restore-target storage provider is required.")}try{const settings=readStorageSettings(storage);const counts={};for(const entry of STORAGE_COUNT_METHODS){const method=storage[entry.method];if(typeof method!=="function"){throw new Error(`Public restore-target count ${entry.method} is unavailable.`)}const count=entry.method==="countChangeInputs"?await readChangeInputCount(storage,method):await method.call(storage,{partial:{}});if(!Number.isSafeInteger(count)||count<0){throw new Error(`Public restore-target count ${entry.method} is malformed.`)}counts[entry.table]=count}const isEmpty=Object.values(counts).every((count)=>count===0);return{chain:settings.chain,identityKey:isEmpty?null:undefined,tableCounts:counts,isEmpty}}catch(error){if(error instanceof Error&&error.message.startsWith("Public restore-target"))throw error;const detail=error instanceof Error?error.message:String(error??"unknown error");throw new Error(`Public restore-target inspection failed: ${detail.slice(0,240)}`,{cause:error})}}async function readChangeInputCount(storage,countChangeInputs){const findUsers=storage.findUsers;const findOutputBaskets=storage.findOutputBaskets;if(typeof findUsers!=="function"||typeof findOutputBaskets!=="function"){throw new Error("Public user and basket enumeration is required to prove change-input emptiness.")}const users=await findUsers.call(storage,{partial:{}});const baskets=await findOutputBaskets.call(storage,{partial:{}});if(!Array.isArray(users)||!Array.isArray(baskets)){throw new Error("Public user or basket enumeration returned malformed rows.")}const count=countChangeInputs;let total=0;for(const user of users){const userId=isRecord3(user)?user.userId:undefined;if(!Number.isSafeInteger(userId)||userId<0){throw new Error("Public user enumeration returned a malformed row.")}for(const basket of baskets){const basketId=isRecord3(basket)?basket.basketId:undefined;if(!Number.isSafeInteger(basketId)||basketId<0){throw new Error("Public basket enumeration returned a malformed row.")}const pairCount=await count.call(storage,userId,basketId,false);if(!Number.isSafeInteger(pairCount)||pairCount<0||!Number.isSafeInteger(total+pairCount)){throw new Error("Public change-input count is malformed.")}total+=pairCount}}return total}function readStorageSettings(storage){const getter=storage.getSettings??storage.getActiveSettings;if(typeof getter!=="function")throw new Error("Public restore-target storage settings are unavailable.");const settings=getter.call(storage);const chain=settings?.chain;if(chain!=="main"&&chain!=="test")throw new Error("Public restore-target storage chain is unavailable or unsupported.");return{chain}}function isRecord3(value){return Boolean(value)&&typeof value==="object"&&!Array.isArray(value)}var WALLET_DATA_ZIP_MAX_COMPRESSED_BYTES=512*1024*1024;var WALLET_DATA_ZIP_MAX_ENTRIES=4096;var WALLET_DATA_ZIP_MAX_EXPANDED_ENTRY_BYTES=64*1024*1024;var WALLET_DATA_ZIP_MAX_EXPANDED_BYTES=512*1024*1024;var WALLET_DATA_ZIP_LIMITS=Object.freeze({maxCompressedBytes:WALLET_DATA_ZIP_MAX_COMPRESSED_BYTES,maxEntries:WALLET_DATA_ZIP_MAX_ENTRIES,maxExpandedEntryBytes:WALLET_DATA_ZIP_MAX_EXPANDED_ENTRY_BYTES,maxExpandedBytes:WALLET_DATA_ZIP_MAX_EXPANDED_BYTES});function resolveWalletDataZipLimits(overrides={}){const values={maxCompressedBytes:overrides.maxCompressedBytes??WALLET_DATA_ZIP_LIMITS.maxCompressedBytes,maxEntries:overrides.maxEntries??WALLET_DATA_ZIP_LIMITS.maxEntries,maxExpandedEntryBytes:overrides.maxExpandedEntryBytes??WALLET_DATA_ZIP_LIMITS.maxExpandedEntryBytes,maxExpandedBytes:overrides.maxExpandedBytes??WALLET_DATA_ZIP_LIMITS.maxExpandedBytes};for(const[name,value]of Object.entries(values)){const ceiling=WALLET_DATA_ZIP_LIMITS[name];if(!Number.isSafeInteger(value)||value<1||value>ceiling){throw new Error(`Wallet-data ZIP ${name} must be a positive safe integer no greater than its production ceiling.`)}}if(values.maxExpandedEntryBytes>values.maxExpandedBytes){throw new Error("Wallet-data ZIP per-entry expansion limit cannot exceed total expansion limit.")}return values}var ENTITY_MAPPINGS=[{name:"provenTx",property:"provenTxs"},{name:"outputBasket",property:"outputBaskets"},{name:"outputTag",property:"outputTags"},{name:"txLabel",property:"txLabels"},{name:"transaction",property:"transactions"},{name:"output",property:"outputs"},{name:"txLabelMap",property:"txLabelMaps"},{name:"outputTagMap",property:"outputTagMaps"},{name:"certificate",property:"certificates"},{name:"certificateField",property:"certificateFields"},{name:"commission",property:"commissions"},{name:"provenTxReq",property:"provenTxReqs"}];var DEFAULT_MAX_CHUNKS=1e5;var AMBIGUOUS_RESTORE_TARGETS=new WeakSet;function requireStorage(value){if(!value||typeof value!=="object"&&typeof value!=="function"){throw new Error("A WalletStorageManager is required for wallet-data ZIP portability.")}const candidate=value;if(typeof candidate.getSettings!=="function"||typeof candidate.getAuth!=="function"||typeof candidate.syncToWriter!=="function"||typeof candidate.syncFromReader!=="function"){throw new Error("The upstream WalletStorageManager does not expose the required wallet-data sync operations.")}return candidate}function requireRestoreStorage(value){if(!value||typeof value!=="object"&&typeof value!=="function"){throw new Error("A WalletStorageManager is required for wallet-data ZIP restore.")}const candidate=value;if(typeof candidate.syncFromReader!=="function"){throw new Error("The upstream WalletStorageManager does not expose syncFromReader for wallet-data ZIP restore.")}return candidate}function assertIdentityKey(identityKey){if(!/^(02|03)[0-9a-fA-F]{64}$/.test(identityKey)){throw new Error("The wallet-data ZIP identity key is invalid.")}}function assertManifest(value){if(!value||typeof value!=="object"){throw new Error("Wallet-data ZIP manifest is missing.")}const manifest=value;if(manifest.version!==1||!Number.isSafeInteger(manifest.chunkCount)||(manifest.chunkCount??-1)<1||manifest.chain!=="main"&&manifest.chain!=="test"||typeof manifest.createdAt!=="string"||typeof manifest.identityKey!=="string"){throw new Error("Wallet-data ZIP manifest is invalid.")}assertIdentityKey(manifest.identityKey);if(!Number.isFinite(Date.parse(manifest.createdAt))){throw new Error("Wallet-data ZIP manifest has an invalid creation timestamp.")}}function assertZipEntryInfo(file,limits){if(!Number.isSafeInteger(file.size)||file.size<0||!Number.isSafeInteger(file.originalSize)||file.originalSize<0){throw new Error("Wallet-data ZIP contains an unbounded entry size.")}if(file.originalSize>limits.maxExpandedEntryBytes){throw new Error("Wallet-data ZIP entry exceeds the expanded-size limit.")}if(file.compression!==0&&file.compression!==8){throw new Error("Wallet-data ZIP uses an unsupported compression method.")}}function assertZipResourceMetadata(file,count,expandedBytes,limits){if(count>limits.maxEntries){throw new Error("Wallet-data ZIP contains too many entries.")}assertZipEntryInfo(file,limits);const nextExpandedBytes=expandedBytes+file.originalSize;if(!Number.isSafeInteger(nextExpandedBytes)||nextExpandedBytes>limits.maxExpandedBytes){throw new Error("Wallet-data ZIP exceeds the total expanded-size limit.")}return nextExpandedBytes}function assertExpandedEntries(entries,limits){let total=0;let count=0;for(const value of Object.values(entries)){count+=1;if(count>limits.maxEntries||value.byteLength>limits.maxExpandedEntryBytes){throw new Error("Wallet-data ZIP expanded entry limits were exceeded.")}total+=value.byteLength;if(!Number.isSafeInteger(total)||total>limits.maxExpandedBytes){throw new Error("Wallet-data ZIP total expanded-size limit was exceeded.")}}}function safeRestoreErrorDetail(error){let detail=error instanceof Error?error.message:String(error??"");detail=detail.replace(/[5KLc9][1-9A-HJ-NP-Za-km-z]{50,51}/g,"[redacted]").replace(/\b(?:02|03)[0-9a-f]{64}\b/gi,"[redacted]");return detail.length>180?`${detail.slice(0,177)}...`:detail}function makeAmbiguousRestoreError(error){const detail=safeRestoreErrorDetail(error);return new Error(detail?`Wallet-data ZIP restore became ambiguous after syncFromReader began; the target may be partially restored (${detail}). Do not retry this target.`:"Wallet-data ZIP restore became ambiguous after syncFromReader began; the target may be partially restored. Do not retry this target.")}function unzipArchive(bytes,limits){if(bytes.byteLength>limits.maxCompressedBytes){throw new Error("Wallet-data ZIP exceeds the 512 MiB compressed-size limit.")}return new Promise((resolve,reject)=>{let count=0;let expandedBytes=0;const names=new Set;const inspectOnly=(file)=>{if(names.has(file.name)){throw new Error("Wallet-data ZIP contains duplicate entry names.")}names.add(file.name);count+=1;expandedBytes=assertZipResourceMetadata(file,count,expandedBytes,limits);return false};try{unzip(bytes,{filter:inspectOnly},(error)=>{if(error){reject(error);return}try{unzip(bytes,(expandError,entries)=>{if(expandError){reject(expandError);return}try{assertExpandedEntries(entries,limits);resolve(entries)}catch(entryError){reject(entryError)}})}catch(expandError){reject(expandError)}})}catch(metadataError){reject(metadataError)}})}function hasData(chunk){return ENTITY_MAPPINGS.some(({property})=>{const value=chunk[property];if(value===undefined)return false;if(!Array.isArray(value)){throw new Error(`Wallet-data sync chunk field ${property} is not an array.`)}return value.length>0})}function parseManifest(entries){const manifestBytes=entries["manifest.json"];if(!manifestBytes){throw new Error("Wallet-data ZIP has no manifest.json.")}let value;try{value=JSON.parse(new TextDecoder().decode(manifestBytes))}catch{throw new Error("Wallet-data ZIP manifest is not valid JSON.")}assertManifest(value);return value}function assertOnlyStandardEntries(entries,manifest){const names=Object.keys(entries).sort();const chunkIndexes=names.filter((name)=>name!=="manifest.json").map((name)=>{const match=/^chunk-(\d+)\.bin$/.exec(name);if(!match)return null;const index=Number(match[1]);return Number.isSafeInteger(index)&&String(index).padStart(4,"0")===match[1]?index:null});chunkIndexes.sort((left,right)=>(left??Number.MAX_SAFE_INTEGER)-(right??Number.MAX_SAFE_INTEGER));const exactChunkSequence=chunkIndexes.length===manifest.chunkCount&&chunkIndexes.every((index,expectedIndex)=>index===expectedIndex);if(names.length!==manifest.chunkCount+1||!exactChunkSequence){throw new Error("Wallet-data ZIP must contain only upstream manifest and sync chunks.")}}function assertFreshRestoreInspection(inspection,expectedChain){if(inspection===undefined)return;if(!inspection||typeof inspection!=="object"||Array.isArray(inspection)){throw new Error("Wallet-data ZIP restore target freshness proof is malformed.")}if(inspection.chain===null||inspection.chain===undefined){throw new Error("Wallet-data ZIP restore target chain could not be verified.")}if(inspection.chain!==expectedChain){throw new Error("Wallet-data ZIP restore target chain does not match the archive chain.")}if(inspection.identityKey!==undefined&&inspection.identityKey!==null&&inspection.identityKey!==""){throw new Error("Wallet-data ZIP restore target is not fresh; an existing wallet identity was found.")}let allCountsZero=false;if(inspection.tableCounts!==undefined){if(!inspection.tableCounts||typeof inspection.tableCounts!=="object"||Array.isArray(inspection.tableCounts)){throw new Error("Wallet-data ZIP restore target counts are malformed.")}allCountsZero=Object.keys(inspection.tableCounts).length>0;for(const count of Object.values(inspection.tableCounts)){if(!Number.isSafeInteger(count)||count<0){throw new Error("Wallet-data ZIP restore target counts are malformed.")}if(count!==0){throw new Error("Wallet-data ZIP restore target is not empty; no import was attempted.")}}}if(inspection.isEmpty===false||inspection.isEmpty!==true&&!allCountsZero){throw new Error("Wallet-data ZIP restore target did not prove whole-store emptiness.")}}async function proveFreshRestoreTarget(options,expectedChain){if(options.inspectTarget!==undefined&&options.assertTargetFresh!==undefined){throw new Error("Wallet-data ZIP restore accepts only one target freshness proof.")}if(options.inspectTarget!==undefined||options.assertTargetFresh!==undefined){const inspect=options.inspectTarget??options.assertTargetFresh;try{assertFreshRestoreInspection(await inspect(),expectedChain);return}catch(error){if(error instanceof Error&&error.message.includes("no import was attempted"))throw error;throw error instanceof Error?error:new Error("Wallet-data ZIP restore target freshness proof failed.")}}if(!options.targetStorage){throw new Error("Wallet-data ZIP restore requires a whole-store empty-target proof before syncFromReader.")}assertFreshRestoreInspection(await inspectWalletStorageTarget(options.targetStorage),expectedChain)}class MapAppFileBackupProvider extends FileBackupProvider{expectedIdentityKey;targetSettings;maxChunks;syncMap=createSyncMap();sourceIdentityKey;sourceName;sourceUserId;initialized=false;terminal=false;failed=false;constructor(zip,settings,identityKey,options={}){super(zip,settings,identityKey);assertIdentityKey(identityKey);const maxChunks=options.maxChunks??DEFAULT_MAX_CHUNKS;if(!Number.isSafeInteger(maxChunks)||maxChunks<1){throw new Error("The wallet-data ZIP chunk limit must be a positive safe integer.")}this.expectedIdentityKey=identityKey;this.targetSettings=settings;this.maxChunks=maxChunks}hasReachedTerminalChunk(){return this.terminal}async findOrInsertSyncStateAuth(auth,storageIdentityKey,storageName){if(this.failed){throw new Error("The wallet-data ZIP export already failed; create a new provider.")}if(auth.identityKey!==this.expectedIdentityKey){throw new Error("Wallet-data export identity does not match the authenticated wallet.")}if(this.terminal){throw new Error("The wallet-data ZIP provider cannot be reused after completion; create a new provider.")}if(typeof storageIdentityKey!=="string"||storageIdentityKey.length===0||typeof storageName!=="string"||storageName.length===0){throw new Error("The wallet-data source storage settings are invalid.")}const userId=auth.userId??1;if(!Number.isSafeInteger(userId)||userId<0){throw new Error("The wallet-data source user id is invalid.")}const sourceChanged=this.sourceIdentityKey!==storageIdentityKey||this.sourceName!==storageName||this.sourceUserId!==userId;if(this.initialized&&sourceChanged){throw new Error("Wallet-data source changed during export; create a new provider.")}const isNew=!this.initialized;if(isNew){this.syncMap=createSyncMap();this.sourceIdentityKey=storageIdentityKey;this.sourceName=storageName;this.sourceUserId=userId;this.initialized=true}const now=new Date;return{syncState:{syncStateId:0,created_at:now,updated_at:now,userId,storageIdentityKey,storageName,init:false,refNum:"file-backup",status:"unknown",syncMap:JSON.stringify(this.syncMap)},isNew}}requestOffsets(args){if(!Array.isArray(args.offsets)||args.offsets.length!==ENTITY_MAPPINGS.length){throw new Error("Wallet-data sync did not provide the complete upstream entity offset sequence.")}const offsets=new Map;for(const[index,expected]of ENTITY_MAPPINGS.entries()){const actual=args.offsets[index];if(!actual||actual.name!==expected.name||!Number.isSafeInteger(actual.offset)||actual.offset<0){throw new Error(`Wallet-data sync offsets are not in upstream entity order at ${expected.name}.`)}if(offsets.has(actual.name)){throw new Error(`Wallet-data sync offsets contain a duplicate ${actual.name} entity.`)}offsets.set(actual.name,actual.offset)}return offsets}validateChunk(args,chunk){if(!this.initialized||this.sourceIdentityKey===undefined||this.sourceName===undefined){throw new Error("Wallet-data sync state was not initialized before the first chunk.")}if(args.identityKey!==this.expectedIdentityKey||chunk.userIdentityKey!==this.expectedIdentityKey){throw new Error("Wallet-data sync chunk identity does not match the export identity.")}if(args.fromStorageIdentityKey!==this.sourceIdentityKey||chunk.fromStorageIdentityKey!==args.fromStorageIdentityKey){throw new Error("Wallet-data sync chunk source does not match the initialized source storage.")}if(chunk.toStorageIdentityKey!==args.toStorageIdentityKey){throw new Error("Wallet-data sync chunk destination does not match the requested destination.")}if(this.targetSettings.storageIdentityKey!==args.toStorageIdentityKey){throw new Error("Wallet-data sync destination does not match the writer settings.")}const offsets=this.requestOffsets(args);for(const{name}of ENTITY_MAPPINGS){const expectedOffset=this.syncMap[name].count;const requestedOffset=offsets.get(name);if(requestedOffset!==expectedOffset){throw new Error(`Wallet-data sync did not converge for ${name}: expected offset ${expectedOffset}, received ${requestedOffset}.`)}}return{offsets,data:hasData(chunk)}}async processSyncChunk(args,chunk){if(this.failed){throw new Error("The wallet-data ZIP export already failed; create a new provider.")}if(this.terminal){throw new Error("Wallet-data sync produced a chunk after the terminal chunk.")}if(this.getChunkCount()>=this.maxChunks){this.failed=true;throw new Error("Wallet-data sync did not converge before the ZIP chunk limit was reached.")}try{const{offsets,data}=this.validateChunk(args,chunk);const result=await super.processSyncChunk(args,chunk);if(result.done===data){throw new Error("Upstream FileBackupProvider returned an inconsistent sync completion result.")}for(const{name,property}of ENTITY_MAPPINGS){const rows=chunk[property];if(rows===undefined)continue;if(!Array.isArray(rows)){throw new Error(`Wallet-data sync chunk field ${property} is not an array.`)}if(rows.length>0){this.syncMap[name].count=(offsets.get(name)??0)+rows.length}}if(data&&this.syncMapProgressTotal()===0){throw new Error("Wallet-data sync did not advance any entity offset.")}if(!data)this.terminal=true;return result}catch(error){this.failed=true;throw error}}syncMapProgressTotal(){return ENTITY_MAPPINGS.reduce((total,{name})=>total+this.syncMap[name].count,0)}}async function inspectWalletDataZip(bytes,expected,options={}){if(!(bytes instanceof Uint8Array)||bytes.byteLength===0){throw new Error("Choose a non-empty wallet-data ZIP.")}assertIdentityKey(expected.identityKey);const limits=resolveWalletDataZipLimits(options.limits);const entries=await unzipArchive(bytes,limits);const manifest=parseManifest(entries);if(manifest.identityKey!==expected.identityKey){throw new Error("Wallet-data ZIP identity does not match the expected wallet identity.")}if(manifest.chain!==expected.chain){throw new Error("Wallet-data ZIP chain does not match the expected wallet chain.")}assertOnlyStandardEntries(entries,manifest);return{bytes:new Uint8Array(bytes),manifest}}function collectZip(){const pieces=[];let finish;let fail;const done=new Promise((resolve,reject)=>{finish=resolve;fail=reject});let settled=false;const zip=new Zip((error,data,final)=>{if(settled)return;if(error){settled=true;fail(error);return}if(data&&data.byteLength>0)pieces.push(data);if(final){settled=true;const size=pieces.reduce((total,piece)=>total+piece.byteLength,0);const bytes=new Uint8Array(size);let offset=0;for(const piece of pieces){bytes.set(piece,offset);offset+=piece.byteLength}finish(bytes)}});return{zip,done}}async function exportWalletDataZip(storageValue,expected,options={}){const storage=requireStorage(storageValue);assertIdentityKey(expected.identityKey);const settings=storage.getSettings();if(settings.chain!==expected.chain){throw new Error("Wallet storage chain does not match export chain.")}const limits=resolveWalletDataZipLimits(options.limits);const{zip,done}=collectZip();const writer=new MapAppFileBackupProvider(zip,settings,expected.identityKey,options);const auth=await storage.getAuth(true);if(auth.identityKey!==expected.identityKey){throw new Error("Wallet-data export identity does not match the authenticated wallet.")}await storage.syncToWriter(auth,writer);if(!writer.hasReachedTerminalChunk()){throw new Error("Wallet-data sync returned before a terminal empty chunk; export did not converge.")}const manifest={version:1,createdAt:new Date().toISOString(),chain:expected.chain,identityKey:expected.identityKey,chunkCount:writer.getChunkCount()};const entry=new ZipDeflate("manifest.json",{level:6});zip.add(entry);entry.push(new TextEncoder().encode(JSON.stringify(manifest)),true);zip.end();const bytes=await done;return await inspectWalletDataZip(bytes,expected,{limits})}async function preflightReader(entries,manifest,expectedIdentityKey){const reader=new FileRestoreReader(entries,manifest);const readerSettings=await reader.makeAvailable();for(let index=0;index<manifest.chunkCount;index++){const chunk=await reader.getSyncChunk({fromStorageIdentityKey:readerSettings.storageIdentityKey,toStorageIdentityKey:"wallet-data-validation",identityKey:expectedIdentityKey,maxRoughSize:1e7,maxItems:1000,offsets:[]});if(chunk.userIdentityKey!==expectedIdentityKey){throw new Error("Wallet-data ZIP chunk identity does not match the expected wallet identity.")}}reader.reset();return reader}async function restoreWalletDataZip(storageValue,bytes,expected,options={}){const storage=requireRestoreStorage(storageValue);const targetCandidate=options.targetStorage??storage;if(typeof targetCandidate!=="object"&&typeof targetCandidate!=="function"||targetCandidate===null){throw new Error("Wallet-data ZIP restore target freshness provider is invalid.")}const targetKey=targetCandidate;if(AMBIGUOUS_RESTORE_TARGETS.has(targetKey)){throw new Error("Wallet-data ZIP restore target has an ambiguous prior sync failure; do not retry this target.")}const limits=resolveWalletDataZipLimits(options.limits);const inspected=await inspectWalletDataZip(bytes,expected,{limits});await proveFreshRestoreTarget(options,expected.chain);const entries=await unzipArchive(inspected.bytes,limits);const reader=await preflightReader(entries,inspected.manifest,expected.identityKey);await options.beforeSync?.();await proveFreshRestoreTarget(options,expected.chain);AMBIGUOUS_RESTORE_TARGETS.add(targetKey);try{await storage.syncFromReader(expected.identityKey,reader)}catch(error){throw makeAmbiguousRestoreError(error)}AMBIGUOUS_RESTORE_TARGETS.delete(targetKey);return inspected.manifest}import{Database}from"bun:sqlite";import{resolve}from"path";var AGENT_LOCAL_INTENT_MAX_CIPHERTEXT_BYTES=16*1024*1024;var AGENT_LOCAL_INTENT_MAX_NAMESPACE_BYTES=64*1024*1024;var AGENT_LOCAL_INTENT_MAX_NAMESPACE_RECORDS=1000;var MAX_IDENTIFIER_LENGTH=512;var APPLICATION_ID=1296124238;var SCHEMA_VERSION=1;var ENVELOPE_KEYS=["envelopeVersion","recordId","namespaceId","createdAt","updatedAt","ciphertext"];class AgentLocalIntentRepositoryError extends Error{code;constructor(code,message,options){super(message,options);this.code=code;this.name="AgentLocalIntentRepositoryError"}}function openAgentLocalIntentRepository(filename){if(typeof filename!=="string"||!filename.trim()||filename.includes("\x00")||filename===":memory:"||filename.startsWith("file:")){throw error("local_intent_path_invalid","A dedicated persistent local intent database filename is required.")}let database;try{database=new Database(resolve(filename),{create:true,strict:true});database.exec("PRAGMA busy_timeout = 0; PRAGMA locking_mode = EXCLUSIVE;");const applicationId=getRow(database,"PRAGMA application_id").application_id;const version=getRow(database,"PRAGMA user_version").user_version;const objects=getRows(database,"SELECT name, type FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY name");const isNew=applicationId===0&&version===0&&objects.length===0;if(!isNew&&(applicationId!==APPLICATION_ID||version!==SCHEMA_VERSION||JSON.stringify(objects)!==JSON.stringify([{name:"encrypted_intents",type:"table"},{name:"encrypted_intents_namespace",type:"index"}]))){throw error("local_intent_database_incompatible","This file is not a supported participant local intent database.")}database.exec("PRAGMA journal_mode = DELETE; PRAGMA synchronous = EXTRA; PRAGMA temp_store = MEMORY; PRAGMA journal_size_limit = 0;");const db2=database;if(getRow(db2,"PRAGMA journal_mode")?.journal_mode!=="delete"||getRow(db2,"PRAGMA synchronous")?.synchronous!==3||getRow(db2,"PRAGMA locking_mode")?.locking_mode!=="exclusive"){throw error("local_intent_durability_unavailable","The local database could not enable durable exclusive execution.")}db2.transaction(()=>{if(isNew){db2.exec(`CREATE TABLE encrypted_intents (
5
5
  record_id TEXT PRIMARY KEY NOT NULL CHECK(length(record_id) BETWEEN 1 AND ${MAX_IDENTIFIER_LENGTH}),
6
6
  namespace_id TEXT NOT NULL CHECK(length(namespace_id) BETWEEN 1 AND ${MAX_IDENTIFIER_LENGTH}),
7
7
  envelope_version INTEGER NOT NULL CHECK(envelope_version = 1),