@jdr377/mapapp-agent-connector 0.1.0-pre.1 → 0.1.0-pre.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -21
- package/bun.lock +1 -1
- package/dist/chunk-9d4kh0mm.js +3 -0
- package/dist/chunk-axqpywa6.js +3 -0
- package/dist/chunk-er6bkfzk.js +2 -0
- package/dist/{chunk-k75c97va.js → chunk-nmac0vha.js} +4 -4
- package/dist/chunk-nyj9k76w.js +2 -0
- package/dist/chunk-w2ke2pqg.js +19 -0
- package/dist/participant-mcp-server.js +6 -3
- package/distribution.json +19 -18
- package/package.json +1 -1
- package/dist/chunk-0033d0wt.js +0 -2
- package/dist/chunk-ajs19nj9.js +0 -3
- package/dist/chunk-r4m45n3d.js +0 -4
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# MapApp participant connector
|
|
2
2
|
|
|
3
|
-
Package: **`@jdr377/mapapp-agent-connector@0.1.0-pre.
|
|
4
|
-
License: proprietary (`UNLICENSED`). Obtain the exact version from the public
|
|
5
|
-
|
|
3
|
+
Package: **`@jdr377/mapapp-agent-connector@0.1.0-pre.3`**.
|
|
4
|
+
License: proprietary (`UNLICENSED`). Obtain the exact version from the public npm
|
|
5
|
+
registry. Check that version rather than inferring availability from a preview
|
|
6
|
+
tag. If the exact requested version is unavailable, report the missing release.
|
|
7
|
+
This version includes host-access verification guidance, explicit setup reporting,
|
|
8
|
+
the policy schema resource/command and structured missing-grant diagnostics.
|
|
6
9
|
|
|
7
10
|
The connector runs locally in the participant's persistent environment and
|
|
8
11
|
exposes MapApp application tools over stdio MCP. MapApp does not host the
|
|
@@ -18,11 +21,15 @@ connector's redirect checks for app intake and external-wallet requests do not
|
|
|
18
21
|
protect that separate messaging transport. See the upstream
|
|
19
22
|
[redirect advisory](https://github.com/bsv-blockchain/ts-stack/security/advisories/GHSA-qp3j-h5xf-p2p7).
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
Before wallet setup, check executable installation, private files retained across
|
|
25
|
+
sessions, **Bun 1.3.11**, HTTPS access to Townspace,
|
|
22
26
|
and an MCP host that launches local stdio processes. Use the
|
|
23
27
|
[Bun installation documentation](https://bun.com/docs/installation) to choose an
|
|
24
28
|
installation method for your environment. The package installs its pinned wallet
|
|
25
29
|
and application dependencies; check each wallet provider's required methods and grants.
|
|
30
|
+
Report actual restrictions. A browser interface does not establish whether the
|
|
31
|
+
agent has terminal, installation or persistence capabilities. An observed trial
|
|
32
|
+
on a different Bun version does not change the exact runtime pin.
|
|
26
33
|
|
|
27
34
|
## Install
|
|
28
35
|
|
|
@@ -34,14 +41,18 @@ installation workspace with this host manifest:
|
|
|
34
41
|
"private": true,
|
|
35
42
|
"type": "module",
|
|
36
43
|
"dependencies": {
|
|
37
|
-
"@jdr377/mapapp-agent-connector": "0.1.0-pre.
|
|
44
|
+
"@jdr377/mapapp-agent-connector": "0.1.0-pre.3"
|
|
38
45
|
},
|
|
39
46
|
"overrides": { "@bsv/sdk": "2.7.1", "engine.io-client": "6.6.6" }
|
|
40
47
|
}
|
|
41
48
|
```
|
|
42
49
|
|
|
43
|
-
Run `bun --no-env-file install --production --ignore-scripts
|
|
44
|
-
host
|
|
50
|
+
Run `bun --no-env-file install --production --ignore-scripts`. Check for `bun.lock`
|
|
51
|
+
in this host workspace: the first production install can leave it absent. If
|
|
52
|
+
absent, run `bun --no-env-file install --lockfile-only --ignore-scripts` in the same
|
|
53
|
+
workspace. Retain the manifest and lock, then verify with
|
|
54
|
+
`bun --no-env-file install --production --ignore-scripts --frozen-lockfile`.
|
|
55
|
+
Use that frozen command for subsequent installations. Host overrides
|
|
45
56
|
preserve the pinned SDK graph; dependency packages cannot impose root overrides.
|
|
46
57
|
No dependency lifecycle script, private registry or private source checkout is
|
|
47
58
|
required. `distribution.json` lists compiled client inputs and byte hashes.
|
|
@@ -53,7 +64,30 @@ Replace angle-bracket placeholders before running commands.
|
|
|
53
64
|
|
|
54
65
|
## First run
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
Store wallet or external connector state outside installed package files in a
|
|
68
|
+
participant-owned persistent location. Respect the participant's selected location.
|
|
69
|
+
Exclude this state from version control, publication and unintended sharing or
|
|
70
|
+
synchronization.
|
|
71
|
+
|
|
72
|
+
Before creating or importing a root, restrict the parent directory with the host's
|
|
73
|
+
native access controls. Permit the participant's authorized OS accounts and trusted
|
|
74
|
+
host administration. Retain the read, write and signing access required by the user
|
|
75
|
+
and their authorized agent.
|
|
76
|
+
|
|
77
|
+
Before setup, inspect the parent's ownership, effective permissions and inherited
|
|
78
|
+
access rules. Use a harmless disposable file to verify the access that new files
|
|
79
|
+
inherit. Unrelated OS accounts must not read private state or modify, replace or
|
|
80
|
+
delete it. Record the inspection method, permitted accounts or groups, and result
|
|
81
|
+
without reading or displaying secrets. A directory name, successful write or
|
|
82
|
+
requested numeric mode does not prove private access. If you cannot establish or
|
|
83
|
+
verify the required access, report `SETUP_UNAVAILABLE` with the host prerequisite.
|
|
84
|
+
Continue independent public discovery.
|
|
85
|
+
|
|
86
|
+
For first setup, connect or restore, the final `--wallet-dir` destination **must not
|
|
87
|
+
already exist**, even as an empty directory. Restrict and inspect only its parent.
|
|
88
|
+
Let the command create the final directory. Preserve existing wallets and
|
|
89
|
+
interrupted setup state. Do not silently change shared-directory permissions,
|
|
90
|
+
move an existing wallet or replace its root.
|
|
57
91
|
|
|
58
92
|
```sh
|
|
59
93
|
bun --no-env-file <connector> setup --wallet-dir <new-private-wallet-directory> --deployment https://dev.town.space
|
|
@@ -69,10 +103,17 @@ a root to repair startup.
|
|
|
69
103
|
|
|
70
104
|
The wallet directory contains `wallet.json`, `root.wif`, `wallet.sqlite`,
|
|
71
105
|
`agent-intents.sqlite`, `participant-authority.json`, `setup.json` and its named
|
|
72
|
-
clean wallet ZIP.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
106
|
+
clean wallet ZIP. Setup requests private file modes where supported. It does not
|
|
107
|
+
inspect host access. Its `persistenceAccess: "host_verification_required"` result
|
|
108
|
+
also applies to reuse, restore and external connector state. `wallet_ready` and
|
|
109
|
+
`provider_bound` describe wallet or connection readiness.
|
|
110
|
+
|
|
111
|
+
After setup, connect or restore, inspect the actual directory and every persisted
|
|
112
|
+
file. Include the root where present, databases, database sidecars, authority,
|
|
113
|
+
operation store and recovery ZIP. Verify access before funding, identity publication
|
|
114
|
+
or actions. Repeat verification after restore, relocation or host permission
|
|
115
|
+
changes. Report the evidence before describing persistence as private. Keep roots
|
|
116
|
+
out of transcripts, commands, tool arguments, logs and MapApp requests.
|
|
76
117
|
|
|
77
118
|
Restore to a new directory with the exact separate root, stock ZIP, original
|
|
78
119
|
participant authority and a closed/checkpointed operation database:
|
|
@@ -114,7 +155,8 @@ Never replace a dispatch after an ambiguous response.
|
|
|
114
155
|
|
|
115
156
|
## Local MCP configuration
|
|
116
157
|
|
|
117
|
-
|
|
158
|
+
Prefer the agent host's normal MCP server configuration. Use the actual Bun
|
|
159
|
+
1.3.11 executable as the MCP command and these arguments, with absolute paths:
|
|
118
160
|
|
|
119
161
|
```text
|
|
120
162
|
--no-env-file
|
|
@@ -129,6 +171,14 @@ Add `--confirm-mainnet` only for an authorized Bitcoin operation. The flag alone
|
|
|
129
171
|
grants no authority. Read `mapapp://onboarding/v0.1` at initialization; it is the
|
|
130
172
|
same canonical manual as `/developers?guide=agent-setup` on the deployment.
|
|
131
173
|
Check package availability and deployment readiness rather than assuming either.
|
|
174
|
+
Published versions retain their own bundled manual; check that the website guide
|
|
175
|
+
matches your installed version. Follow your host's configuration format/location. Keep its
|
|
176
|
+
session open through initialization and awaited calls; stdin EOF can terminate
|
|
177
|
+
the connector before a response. When normal host configuration is unavailable,
|
|
178
|
+
use the official `@modelcontextprotocol/client` 2.3.1 `Client` and
|
|
179
|
+
`StdioClientTransport`. `Client.connect` handles initialize/initialized and
|
|
180
|
+
response matching. Close in `finally` after awaited calls. The canonical guide
|
|
181
|
+
includes host JSON and official-client examples.
|
|
132
182
|
|
|
133
183
|
The connector exposes **24 tools**: readiness, reference receive address/sync,
|
|
134
184
|
sponsored identity prepare/execute/status/reconcile, paid and sponsored
|
|
@@ -148,6 +198,10 @@ mainnet confirmation. Evidence is retained before stock author internalization.
|
|
|
148
198
|
After uncertainty, use status/reconcile with the same ID: recovery queries the
|
|
149
199
|
original reservation and never asks the sponsor to spend again. Local filing
|
|
150
200
|
and public observation are reported separately.
|
|
201
|
+
Successful identity execute can return `kind=reconciled`: it uses the same
|
|
202
|
+
original-evidence filing/readback path as recovery. Check `authorInternalized`,
|
|
203
|
+
`publicIdentityObserved`, the original `txid` and `retryAllowed=false` separately.
|
|
204
|
+
The label and local `attempt_started` phase do not authorize another dispatch.
|
|
151
205
|
|
|
152
206
|
The stock reference receive address uses the SDK's default derivation. Explicit
|
|
153
207
|
receive sync requires `receiveSync` and mainnet confirmation and may construct
|
|
@@ -158,21 +212,60 @@ a sweep. External providers own their receive/sync workflow.
|
|
|
158
212
|
`participant-authority.json` uses `mapapp-participant-authority/v1`. Retain fixed
|
|
159
213
|
`connectionId`, `callerId` and `originator`; change `revision` when policy changes.
|
|
160
214
|
Setup initially denies actions. Optional omitted grants also deny access.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
215
|
+
Required `publishExactText` and `fullRootSpendingAuthorized` fields remain present
|
|
216
|
+
as false when denied. Changing policy revision after preparation can block the
|
|
217
|
+
saved action with `authority_changed`; read its original status and preserve the
|
|
218
|
+
journal rather than editing checkpoints or replacing an attempted operation.
|
|
219
|
+
|
|
220
|
+
- `publishIdentity`: sponsored BAP preparation/execution and original reconciliation; no root-action acknowledgement gate.
|
|
221
|
+
- `publishExactText`: paid root text; media additionally needs `publishExactMedia`.
|
|
222
|
+
- `publishSponsoredText`: sponsored roots and replies; media additionally needs `publishSponsoredMedia`.
|
|
223
|
+
- `grow`: grow/ungrow; `follow`: follow/unfollow; `publishExactReply`: paid text replies.
|
|
166
224
|
- `enableMessaging`, `sendPrivateMessages`, `readPrivateMessages`: independent messaging grants.
|
|
167
225
|
- `receiveSync`: one explicit stock reference receive sync.
|
|
168
226
|
|
|
169
|
-
Direct actions additionally require
|
|
170
|
-
|
|
227
|
+
Direct paid/sponsored/social actions additionally require
|
|
228
|
+
`fullRootSpendingAuthorized`. That acknowledges the process's full root signing
|
|
229
|
+
power; it does not select the payer. Sponsored posts still return `payer=mapapp`
|
|
230
|
+
and `authorSats=0`. Zero participant cost does not isolate a process holding the
|
|
231
|
+
root. App grants are not wallet permission isolation.
|
|
232
|
+
Filesystem permissions restrict other OS accounts. They do not isolate arbitrary
|
|
233
|
+
processes running as the same authorized account. The direct-root agent environment
|
|
234
|
+
and trusted host administration remain trusted.
|
|
171
235
|
The external route instead requires `walletActionsAuthorized` and the provider's
|
|
172
236
|
own permissions. MapApp does not enforce per-action financial caps for either
|
|
173
237
|
route; a provider's monthly spending budget is a different mechanism.
|
|
174
238
|
|
|
239
|
+
Version 0.1.0-pre.3 exposes a read-only JSON Schema from the actual parser at
|
|
240
|
+
`mapapp://participant-authority/v1`, also printed by
|
|
241
|
+
`bun --no-env-file <connector> --authority-schema` without opening a wallet.
|
|
242
|
+
The canonical guide includes the same schema and example. This example denies
|
|
243
|
+
every action. Keep your existing binding
|
|
244
|
+
values; do not substitute the illustrative values:
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"schema": "mapapp-participant-authority/v1",
|
|
249
|
+
"connectionId": "retain-original-connection",
|
|
250
|
+
"callerId": "retain-original-caller",
|
|
251
|
+
"originator": "retain.original.originator",
|
|
252
|
+
"revision": "owner-1",
|
|
253
|
+
"publishExactText": false,
|
|
254
|
+
"fullRootSpendingAuthorized": false
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Within user delegation, identity-only authority adds `publishIdentity=true` and
|
|
259
|
+
a new revision. Direct sponsored text preparation needs `publishSponsoredText`
|
|
260
|
+
and `fullRootSpendingAuthorized`; external actions use `walletActionsAuthorized`
|
|
261
|
+
instead of the root acknowledgement. Keep unrelated grants denied. Sponsored
|
|
262
|
+
denials include `missingGrants` listing only absent fields, with a
|
|
263
|
+
schema pointer and authorized-edit guidance. No tool grants itself authority.
|
|
264
|
+
|
|
175
265
|
Original operation status/recovery does not create replacement transactions.
|
|
176
266
|
Preserve encrypted journals and exact evidence after cancellation, lost responses
|
|
177
267
|
or backup failure. Keep the wallet outside package installations across upgrades.
|
|
178
|
-
|
|
268
|
+
A request to prepare stops at readiness and a saved preparation. Execute only
|
|
269
|
+
when explicit or standing user authority covers that action and its grants and
|
|
270
|
+
runtime gates pass. Valid standing authority does not require another human
|
|
271
|
+
confirmation for each action. Tool configuration cannot expand that delegation.
|
package/bun.lock
CHANGED
|
@@ -256,7 +256,7 @@
|
|
|
256
256
|
|
|
257
257
|
"proxy-addr": ["proxy-addr@2.0.8", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ=="],
|
|
258
258
|
|
|
259
|
-
"qs": ["qs@6.16.
|
|
259
|
+
"qs": ["qs@6.16.1", "", { "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" } }, "sha512-5Px6J7rfHBAGUhNQ3es4YzcOdBBw0SDcVtThJml4RdnKw4tKs2epA0kPZ+K8X+WiHktT93RHVcQ/3ym5aTCgtg=="],
|
|
260
260
|
|
|
261
261
|
"range-parser": ["range-parser@1.3.0", "", {}, "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw=="],
|
|
262
262
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import*as z from"zod/v4";var label=z.string().min(1).max(128).regex(/^[a-zA-Z0-9.:_-]+$/u);var participantAuthoritySchema=z.strictObject({schema:z.literal("mapapp-participant-authority/v1"),connectionId:label.describe("Retain the original connectionId created by setup/connect/restore."),callerId:label.describe("Retain the original trusted callerId."),originator:z.string().min(1).max(128).regex(/^[a-zA-Z0-9.-]+$/u).describe("Retain the original wallet originator."),revision:label.describe("Use a new revision whenever authority changes. Prepared actions bind to their original revision."),publishExactText:z.boolean().describe("Paid root text; paid media also requires publishExactMedia."),fullRootSpendingAuthorized:z.boolean().describe("Acknowledge direct process root signing authority for paid/sponsored/social actions. Does not set the payer or cap costs."),publishExactMedia:z.boolean().optional().describe("Paid root media, in addition to publishExactText."),publishSponsoredText:z.boolean().optional().describe("Sponsored root or reply text; sponsored media also requires publishSponsoredMedia."),publishSponsoredMedia:z.boolean().optional().describe("Sponsored root or reply media, in addition to publishSponsoredText."),grow:z.boolean().optional().describe("Grow and ungrow."),follow:z.boolean().optional().describe("Follow and unfollow."),publishExactReply:z.boolean().optional().describe("Paid text replies. Sponsored replies use publishSponsoredText."),publishIdentity:z.boolean().optional().describe("Sponsored BAP identity prepare/execute and original identity reconciliation."),receiveSync:z.boolean().optional().describe("Explicit stock direct-wallet receive sync, which can construct a sweep."),walletActionsAuthorized:z.boolean().optional().describe("External BRC-100 paid/sponsored/social action gate; provider permissions are also required."),enableMessaging:z.boolean().optional().describe("Register this wallet's messaging binding."),sendPrivateMessages:z.boolean().optional().describe("Send exact authorized private messages."),readPrivateMessages:z.boolean().optional().describe("Sync and read this wallet's private history.")});var PARTICIPANT_AUTHORITY_RESOURCE="mapapp://participant-authority/v1";var PARTICIPANT_AUTHORITY_EDIT_GUIDANCE="Review the user's delegation and participant-authority.json against mapapp://participant-authority/v1. Retain binding fields; change revision only for an authorized policy change. MapApp remains the sponsored payer; app grants do not isolate root authority or cap spending.";var SPONSORED_AUTHORITY_GRANTS=["publishSponsoredText","fullRootSpendingAuthorized","walletActionsAuthorized","publishSponsoredMedia"];var PARTICIPANT_AUTHORITY_JSON_SCHEMA=z.toJSONSchema(participantAuthoritySchema);var PARTICIPANT_AUTHORITY_EXAMPLE={schema:"mapapp-participant-authority/v1",connectionId:"retain-original-connection",callerId:"retain-original-caller",originator:"retain.original.originator",revision:"owner-1",publishExactText:false,fullRootSpendingAuthorized:false};function supportedParticipantBinding(binding){return binding.route==="agent_environment"&&binding.declaredAuthority==="full_root_authority"||binding.route==="existing_brc100"&&binding.declaredAuthority==="provider"}function participantActionAuthorized(binding,authority){return binding.route==="agent_environment"?authority.fullRootSpendingAuthorized===true:binding.route==="existing_brc100"&&authority.walletActionsAuthorized===true}function missingSponsoredActionGrants(binding,authority,media){const required=["publishSponsoredText",binding.route==="agent_environment"?"fullRootSpendingAuthorized":"walletActionsAuthorized",...media?["publishSponsoredMedia"]:[]];return required.filter((grant)=>authority[grant]!==true)}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"))}
|
|
3
|
+
export{participantAuthoritySchema,PARTICIPANT_AUTHORITY_RESOURCE,PARTICIPANT_AUTHORITY_EDIT_GUIDANCE,SPONSORED_AUTHORITY_GRANTS,PARTICIPANT_AUTHORITY_JSON_SCHEMA,PARTICIPANT_AUTHORITY_EXAMPLE,supportedParticipantBinding,participantActionAuthorized,missingSponsoredActionGrants,participantAuthorityName,participantProfileMatches};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{createAgentWalletConnectionInspector,createParticipantHTTPWallet,exportWalletDataZip,inspectWalletDataZip,openAgentLocalIntentRepository,parseParticipantAuthority,participantMetadataSchema,restoreWalletDataZip}from"./chunk-nmac0vha.js";import"./chunk-e6y2yzbj.js";import"./chunk-wy5sgkmh.js";import"./chunk-9d4kh0mm.js";import"./chunk-btwmey1h.js";import{mkdir,open,readFile,rename,stat,copyFile}from"fs/promises";import{basename,join,resolve}from"path";import{constants}from"fs";import{createContext,computeBapId,resolveBapId}from"@1sat/actions";import{createNodeWallet}from"@1sat/wallet-node";import{PrivateKey}from"@bsv/sdk";var schema="mapapp-participant-setup/v1";class ParticipantSetupError extends Error{code;constructor(code){super(code);this.code=code}}function participantDeployment(value){try{const url=new URL(value);if(url.protocol!=="https:"||url.username||url.password||url.search||url.hash||url.pathname!=="/")throw new Error;return url.origin}catch{throw new ParticipantSetupError("setup_deployment_invalid")}}async function protectedWrite(filename,bytes,replace=false){const temporary=replace?`${filename}.${crypto.randomUUID()}.pending`:filename;const file=await open(temporary,"wx",384);try{await file.writeFile(bytes);await file.sync()}finally{await file.close()}if(replace)await rename(temporary,filename)}async function readParticipantSetup(directory){const path=join(resolve(directory),"setup.json");if((await stat(path)).size>4096)throw new ParticipantSetupError("setup_state_invalid");const value=JSON.parse(await readFile(path,"utf8"));if(value.schema!==schema||!["creating","restore_started","wallet_ready"].includes(value.phase)||!/^(02|03)[0-9a-f]{64}$/u.test(value.identityKey))throw new ParticipantSetupError("setup_state_invalid");return value}async function setupParticipantWallet(options){const directory=resolve(options.walletDirectory);const deployment=participantDeployment(options.deployment);let created=false;try{await mkdir(directory,{mode:448});created=true}catch(error){if(error.code!=="EEXIST")throw error}if(!created&&options.restore)throw new ParticipantSetupError("restore_requires_new_directory");if(created){const suppliedRoot=options.restore?(await boundedFile(options.restore.rootFile,128)).toString().trim():null;const key=suppliedRoot?PrivateKey.fromWif(suppliedRoot):PrivateKey.fromRandom();const meta2={chain:"main",identityKey:key.toPublicKey().toString(),storageIdentityKey:crypto.randomUUID(),servicesBaseUrl:`${deployment}/api/bitcoin/wallet-services`};const restoredAuthority=options.restore?parseParticipantAuthority(JSON.parse((await boundedFile(options.restore.authorityFile,4096)).toString())):null;if(options.restore){await inspectWalletDataZip(new Uint8Array(await boundedFile(options.restore.backupFile,512*1024*1024)),meta2);const operations=await boundedFile(options.restore.operationsFile,256*1024*1024);if(!operations.subarray(0,16).equals(Buffer.from("SQLite format 3\x00")))throw new ParticipantSetupError("restore_operations_invalid");if(await stat(options.restore.operationsFile+"-wal").then((info)=>info.size>0,()=>false))throw new ParticipantSetupError("restore_operations_not_checkpointed")}await protectedWrite(join(directory,"setup.json"),JSON.stringify({schema,phase:"creating",identityKey:meta2.identityKey,servicesBaseUrl:meta2.servicesBaseUrl}));await protectedWrite(join(directory,"wallet.json"),JSON.stringify(meta2));await protectedWrite(join(directory,"root.wif"),(suppliedRoot??key.toWif())+`
|
|
3
|
+
`);await protectedWrite(join(directory,"participant-authority.json"),JSON.stringify(restoredAuthority??{schema:"mapapp-participant-authority/v1",connectionId:`participant-${crypto.randomUUID()}`,callerId:`owner-${crypto.randomUUID()}`,originator:new URL(deployment).hostname,revision:"initial-denied",publishExactText:false,fullRootSpendingAuthorized:false}));if(options.restore)await copyFile(options.restore.operationsFile,join(directory,"agent-intents.sqlite"),constants.COPYFILE_EXCL)}const state=await readParticipantSetup(directory).catch(()=>{throw new ParticipantSetupError("setup_existing_directory_unrecognized")});if(state.servicesBaseUrl!==`${deployment}/api/bitcoin/wallet-services`)throw new ParticipantSetupError("setup_deployment_changed");if(state.phase==="restore_started")throw new ParticipantSetupError("restore_outcome_unknown");const meta=participantMetadataSchema.parse(JSON.parse((await boundedFile(join(directory,"wallet.json"),4096)).toString()));if(meta.identityKey!==state.identityKey||meta.servicesBaseUrl!==state.servicesBaseUrl)throw new ParticipantSetupError("setup_identity_changed");const root=PrivateKey.fromWif((await boundedFile(join(directory,"root.wif"),128)).toString().trim());if(root.toPublicKey().toString()!==meta.identityKey)throw new ParticipantSetupError("setup_identity_changed");const authority=parseParticipantAuthority(JSON.parse((await boundedFile(join(directory,"participant-authority.json"),4096)).toString()));const owned=openAgentLocalIntentRepository(join(directory,"agent-intents.sqlite"));let runtime;try{runtime=await createNodeWallet({privateKey:root,chain:"main",storageIdentityKey:meta.storageIdentityKey,storage:{provider:"bun-sqlite",filename:join(directory,"wallet.sqlite")},servicesBaseUrl:meta.servicesBaseUrl,skipInitialMonitor:true,backups:[],feeModel:{model:"sat/kb",value:100}});if((await runtime.wallet.getPublicKey({identityKey:true})).publicKey!==meta.identityKey||(await runtime.wallet.getNetwork({})).network!=="mainnet")throw new ParticipantSetupError("setup_wallet_binding_changed");if(options.restore){await protectedWrite(join(directory,"setup.json"),JSON.stringify({...state,phase:"restore_started"}),true);await restoreWalletDataZip(runtime.storage,new Uint8Array(await boundedFile(options.restore.backupFile,512*1024*1024)),meta,{assertTargetFresh:async()=>{if(!created)throw new ParticipantSetupError("restore_requires_new_directory")}})}const context=createContext(runtime.wallet,{services:runtime.services,dataDir:directory,chain:"main"});const bapId=await computeBapId(context),published=await resolveBapId(context);let recoveryArchive=state.recoveryArchive;if(state.phase==="wallet_ready"){if(!recoveryArchive||basename(recoveryArchive)!==recoveryArchive)throw new ParticipantSetupError("setup_recovery_archive_invalid");await inspectWalletDataZip(new Uint8Array(await boundedFile(join(directory,recoveryArchive),512*1024*1024)),meta)}if(state.phase!=="wallet_ready"){const archive=await exportWalletDataZip(runtime.storage,meta,{maxChunks:20});recoveryArchive=`wallet-data-setup-${crypto.randomUUID()}.zip`;await protectedWrite(join(directory,recoveryArchive),archive.bytes);await protectedWrite(join(directory,"setup.json"),JSON.stringify({...state,phase:"wallet_ready",recoveryArchive}),true)}return{schema,state:"wallet_ready",reused:!created,network:"mainnet",identityKey:meta.identityKey,bapId,persistenceAccess:"host_verification_required",identityPublication:published?"wallet_observed":"not_published",publicIdentityObservation:"not_checked",recovery:{rootFile:"root.wif",walletDataZip:recoveryArchive,operationStore:"agent-intents.sqlite"},authorityFile:"participant-authority.json",actionAuthority:created&&!options.restore?"denied_by_default":"retained_participant_policy",authorityRevision:authority.revision,next:published?"check_readiness":"authorize_sponsored_identity"}}finally{try{await runtime?.destroy()}finally{owned.close()}}}async function connectParticipantWallet(options){const directory=resolve(options.walletDirectory),deployment=participantDeployment(options.deployment);const originator=new URL(deployment).hostname;const authority={schema:"mapapp-participant-authority/v1",connectionId:`participant-${crypto.randomUUID()}`,callerId:`owner-${crypto.randomUUID()}`,originator,revision:"initial-denied",publishExactText:false,fullRootSpendingAuthorized:false,walletActionsAuthorized:false};const wallet=createParticipantHTTPWallet(options.walletEndpoint,originator);const inspector=createAgentWalletConnectionInspector({wallet,binding:{connectionId:authority.connectionId,callerId:authority.callerId,originator,expectedIdentityKey:options.identityKey,expectedNetwork:"mainnet",route:"existing_brc100",declaredAuthority:"provider"}});const observed=await inspector.inspect(authority.callerId);if(observed.state!=="ready")throw new ParticipantSetupError(`setup_provider_${observed.state}`);await mkdir(directory,{mode:448});await protectedWrite(join(directory,"wallet.json"),JSON.stringify({transport:"brc100_http",chain:"main",identityKey:options.identityKey,servicesBaseUrl:`${deployment}/api/bitcoin/wallet-services`,walletEndpoint:options.walletEndpoint}));await protectedWrite(join(directory,"participant-authority.json"),JSON.stringify(authority));const owned=openAgentLocalIntentRepository(join(directory,"agent-intents.sqlite"));owned.close();return{schema,state:"provider_bound",route:"existing_brc100",identityKey:options.identityKey,network:"mainnet",persistenceAccess:"host_verification_required",actionAuthority:"denied_by_default",backup:"provider_owned",authorityFile:"participant-authority.json",next:"check_readiness"}}async function boundedFile(filename,maximum){const info=await stat(filename);if(!info.isFile()||info.size<1||info.size>maximum)throw new ParticipantSetupError("setup_file_invalid");const bytes=await readFile(filename);if(bytes.length>maximum)throw new ParticipantSetupError("setup_file_invalid");return bytes}export{setupParticipantWallet,readParticipantSetup,participantDeployment,connectParticipantWallet,ParticipantSetupError};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{createParticipantAuthorityReader,openAgentParticipantRuntime,parseParticipantAuthority,participantExternalMetadataSchema,participantMetadataSchema}from"./chunk-nmac0vha.js";import"./chunk-e6y2yzbj.js";import"./chunk-wy5sgkmh.js";import"./chunk-9d4kh0mm.js";import"./chunk-btwmey1h.js";export{participantMetadataSchema,participantExternalMetadataSchema,parseParticipantAuthority,openAgentParticipantRuntime,createParticipantAuthorityReader};
|