vestauth 0.22.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
- [Unreleased](https://github.com/vestauth/vestauth/compare/v0.22.1...main)
5
+ [Unreleased](https://github.com/vestauth/vestauth/compare/v0.23.0...main)
6
+
7
+ ## [0.23.0](https://github.com/vestauth/vestauth/compare/v0.22.1...v0.23.0) (2026-03-03)
8
+
9
+ ### Added
10
+
11
+ * `vestauth tool init` preparing the way for 402 payments ([#46](https://github.com/vestauth/vestauth/pull/46))
6
12
 
7
13
  ## [0.22.1](https://github.com/vestauth/vestauth/compare/v0.22.0...v0.22.1) (2026-03-02)
8
14
 
package/README.md CHANGED
@@ -21,6 +21,9 @@ npm i -g vestauth
21
21
  ```sh
22
22
  vestauth agent init
23
23
  vestauth agent curl https://api.vestauth.com/whoami --pp
24
+ vestauth agent curl https://sfs.vestauth.com/write -d '{"filepath":"/hello.md", "content":"hello"}'
25
+ vestauth agent curl https://sfs.vestauth.com/list
26
+ vestauth agent curl https://sam.vestauth.com/send -d '{"to":"you@email.com", "text":"hello from agent"}'
24
27
  ```
25
28
 
26
29
  <details><summary>with curl 🌐 </summary><br>
@@ -128,15 +131,29 @@ vestauth agent curl https://sfs.vestauth.com/read -d '{"filepath":"/hello.md"}'
128
131
  &nbsp;
129
132
 
130
133
  </details>
131
- <details><summary>`GEO` geo.vestauth.com</summary><br/>
134
+ <details><summary>`SAM` Simple Agent Mail</summary><br/>
135
+
136
+ > SAM is a simple way to send email for vestauth agents.
137
+ >
138
+ > [sam.vestauth.com](https://sam.vestauth.com)
139
+
140
+ ```sh
141
+ # send an email
142
+ vestauth agent curl https://sam.vestauth.com/send -d '{"to":"you@email.com", "text":"i am agent"}'
143
+ ```
144
+
145
+ &nbsp;
146
+
147
+ </details>
148
+ <details><summary>`GEO` Latitude and Longitude</summary><br/>
132
149
 
133
- > GEO returns the current geo-coordinates of a vestauth agent.
150
+ > GEO returns the current latitude and longitude of a vestauth agent.
134
151
  >
135
152
  > [geo.vestauth.com](https://geo.vestauth.com)
136
153
 
137
154
  ```sh
138
- # make a ping
139
- vestauth agent curl https://ping.vestauth.com/ping
155
+ # return latitude and longitude
156
+ vestauth agent curl https://geo.vestauth.com/geo
140
157
  ```
141
158
 
142
159
  &nbsp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vestauth",
3
- "version": "0.22.1",
3
+ "version": "0.23.0",
4
4
  "description": "web-bot-auth for agents–from the creator of dotenvx",
5
5
  "keywords": [
6
6
  "vestauth",
@@ -25,9 +25,13 @@ async function verify (httpMethod, uri) {
25
25
  'Signature-Agent': options.signatureAgent
26
26
  }
27
27
 
28
+ const meter = {
29
+ cost: options.meterCost
30
+ }
31
+
28
32
  const publicJwk = options.publicJwk ? JSON.parse(options.publicJwk) : undefined
29
33
 
30
- const output = await primitives.verify(httpMethod, uri, headers, publicJwk)
34
+ const output = await primitives.verify(httpMethod, uri, headers, meter, publicJwk)
31
35
 
32
36
  let space = 0
33
37
  if (options.prettyPrint) {
@@ -0,0 +1,26 @@
1
+ const { logger } = require('./../../../shared/logger')
2
+ const catchAndLog = require('./../../../lib/helpers/catchAndLog')
3
+
4
+ const tool = require('./../../../lib/tool')
5
+
6
+ async function init () {
7
+ try {
8
+ const options = this.opts()
9
+ logger.debug(`options: ${JSON.stringify(options)}`)
10
+
11
+ const output = await tool.init(options.hostname)
12
+
13
+ if (output.isNew) {
14
+ logger.success(`✔ tool created (${output.path}/TOOL_UID=${output.TOOL_UID})`)
15
+ } else {
16
+ logger.info(`• tool exists (${output.path}/TOOL_UID=${output.TOOL_UID})`)
17
+ }
18
+
19
+ logger.help(`⮕ next run: [vestauth agent curl ${output.TOOL_HOSTNAME}/whoami]`)
20
+ } catch (error) {
21
+ catchAndLog(error)
22
+ process.exit(1)
23
+ }
24
+ }
25
+
26
+ module.exports = init
@@ -17,7 +17,11 @@ async function verify (httpMethod, uri) {
17
17
  'Signature-Agent': options.signatureAgent
18
18
  }
19
19
 
20
- const output = await tool.verify(httpMethod, uri, headers)
20
+ const meter = {
21
+ cost: options.meterCost
22
+ }
23
+
24
+ const output = await tool.verify(httpMethod, uri, headers, meter)
21
25
 
22
26
  let space = 0
23
27
  if (options.prettyPrint) {
@@ -39,6 +39,7 @@ primitives.command('verify')
39
39
  .requiredOption('--signature-input <signatureInput>', '')
40
40
  .option('--signature-agent <signatureAgent>', '')
41
41
  .option('--public-jwk <publicJwk>', 'public JWK (json string)', env('AGENT_PUBLIC_JWK'))
42
+ .option('--meter-cost <meterCost>', 'vesties per invocation', '0')
42
43
  .option('--pp, --pretty-print', 'pretty print output')
43
44
  .action(verifyAction)
44
45
 
@@ -1,4 +1,5 @@
1
1
  const { Command } = require('commander')
2
+ const env = require('./../../lib/helpers/env')
2
3
 
3
4
  const tool = new Command('tool')
4
5
 
@@ -6,6 +7,13 @@ tool
6
7
  .description('🔨 tool')
7
8
  .allowUnknownOption()
8
9
 
10
+ // vestauth tool init
11
+ const initAction = require('./../actions/tool/init')
12
+ tool.command('init')
13
+ .description('create tool')
14
+ .option('--hostname <hostname>', 'tool API hostname', env('TOOL_HOSTNAME'))
15
+ .action(initAction)
16
+
9
17
  // vestauth tool verify
10
18
  const verifyAction = require('./../actions/tool/verify')
11
19
  tool.command('verify')
@@ -15,6 +23,7 @@ tool.command('verify')
15
23
  .requiredOption('--signature <signature>', '')
16
24
  .requiredOption('--signature-input <signatureInput>', '')
17
25
  .requiredOption('--signature-agent <signatureAgent>', '')
26
+ .option('--meter-cost <meterCost>', 'vesties per invocation', '0')
18
27
  .option('--pp, --pretty-print', 'pretty print output')
19
28
  .action(verifyAction)
20
29
 
@@ -0,0 +1,42 @@
1
+ const { http } = require('../helpers/http')
2
+ const buildApiError = require('../helpers/buildApiError')
3
+ const agentHeaders = require('../helpers/agentHeaders')
4
+
5
+ class PostToolRegister {
6
+ constructor (hostname, publicJwk, privateJwk) {
7
+ this.hostname = hostname || 'https://api.vestauth.com'
8
+ this.publicJwk = publicJwk
9
+ this.privateJwk = privateJwk
10
+ }
11
+
12
+ async run () {
13
+ const hostname = this.hostname
14
+ const url = `${hostname}/tool/register`
15
+ const publicJwk = this.publicJwk
16
+ const privateJwk = this.privateJwk
17
+
18
+ const httpMethod = 'POST'
19
+ const headers = await agentHeaders(httpMethod, url, 'REGISTERING', JSON.stringify(privateJwk), null, null, hostname)
20
+ headers['Content-Type'] = 'application/json'
21
+ delete headers['Signature-Agent'] // don't send Signature-Agent on registration. nothing to discover yet.
22
+ delete headers['signature-agent']
23
+
24
+ const resp = await http(url, {
25
+ method: httpMethod,
26
+ headers,
27
+ body: JSON.stringify({
28
+ public_jwk: publicJwk
29
+ })
30
+ })
31
+
32
+ if (resp.statusCode >= 400) {
33
+ const json = await resp.body.json()
34
+ throw buildApiError(resp.statusCode, json)
35
+ }
36
+
37
+ const json = await resp.body.json()
38
+ return json
39
+ }
40
+ }
41
+
42
+ module.exports = PostToolRegister
@@ -0,0 +1,16 @@
1
+ const env = require('./env')
2
+
3
+ function normalizeToolHostname (hostname = null) {
4
+ const envHostname = env('TOOL_HOSTNAME')
5
+ const value = (hostname || envHostname || 'api.vestauth.com').trim()
6
+ const candidate = /^https?:\/\//i.test(value) ? value : `https://${value}`
7
+ const url = new URL(candidate)
8
+
9
+ if (url.pathname !== '/' || url.search || url.hash) {
10
+ throw new Error('invalid --hostname. path/query/hash are not allowed')
11
+ }
12
+
13
+ return url.origin
14
+ }
15
+
16
+ module.exports = normalizeToolHostname
@@ -0,0 +1,33 @@
1
+ const dotenvx = require('@dotenvx/dotenvx')
2
+ const keypair = require('./keypair')
3
+ const touch = require('./touch')
4
+ const normalizeToolHostname = require('./normalizeToolHostname')
5
+ const PostToolRegister = require('../api/postToolRegister')
6
+
7
+ async function toolInit (hostname = null) {
8
+ const envPath = '.env'
9
+ const normalizedHostname = normalizeToolHostname(hostname)
10
+ const shouldPersistHostname = normalizedHostname !== 'https://api.vestauth.com'
11
+
12
+ const kp = keypair(null, 'tool')
13
+
14
+ touch(envPath)
15
+
16
+ const tool = await new PostToolRegister(normalizedHostname, kp.publicJwk, kp.privateJwk).run()
17
+ dotenvx.set('TOOL_UID', tool.uid, { path: envPath, plain: true, quiet: true })
18
+ dotenvx.set('TOOL_PUBLIC_JWK', JSON.stringify(kp.publicJwk), { path: envPath, plain: true, quiet: true })
19
+ dotenvx.set('TOOL_PRIVATE_JWK', JSON.stringify(kp.privateJwk), { path: envPath, plain: true, quiet: true })
20
+ if (shouldPersistHostname) {
21
+ dotenvx.set('TOOL_HOSTNAME', normalizedHostname, { path: envPath, plain: true, quiet: true })
22
+ }
23
+
24
+ return {
25
+ TOOL_UID: tool.uid,
26
+ TOOL_PUBLIC_JWK: kp.publicJwk,
27
+ TOOL_HOSTNAME: normalizedHostname,
28
+ path: envPath,
29
+ isNew: tool.is_new
30
+ }
31
+ }
32
+
33
+ module.exports = toolInit
@@ -4,7 +4,7 @@ const extractHostAndHostname = require('./extractHostAndHostname')
4
4
  const trustedFqdn = require('./trustedFqdn')
5
5
  const Errors = require('./errors')
6
6
 
7
- async function toolVerify (httpMethod, uri, headers = {}, serverHostname = null) {
7
+ async function toolVerify (httpMethod, uri, headers = {}, meter = {}, serverHostname = null) {
8
8
  if (!httpMethod) {
9
9
  throw new Errors().missingHttpMethod()
10
10
  }
@@ -33,7 +33,7 @@ async function toolVerify (httpMethod, uri, headers = {}, serverHostname = null)
33
33
  throw new Errors().untrustedSignatureAgent()
34
34
  }
35
35
 
36
- return verify(httpMethod, uri, headers)
36
+ return verify(httpMethod, uri, headers, meter)
37
37
  }
38
38
 
39
39
  module.exports = toolVerify
@@ -77,7 +77,7 @@ async function resolvePublicJwk ({ signatureInput, signatureAgent, publicJwk })
77
77
  }
78
78
  }
79
79
 
80
- async function verify (httpMethod, uri, headers = {}, publicJwk) {
80
+ async function verify (httpMethod, uri, headers = {}, meter = {}, publicJwk) {
81
81
  const signature = headers.Signature || headers.signature
82
82
  const signatureInput = headers['Signature-Input'] || headers['signature-input']
83
83
  const signatureAgent = headers['Signature-Agent'] || headers['signature-agent']
package/src/lib/main.d.ts CHANGED
@@ -46,6 +46,11 @@ export interface VerifyResult {
46
46
  well_known_url?: string
47
47
  }
48
48
 
49
+ export interface Meter {
50
+ cost?: string | number
51
+ [prop: string]: unknown
52
+ }
53
+
49
54
  export interface AgentApi {
50
55
  /**
51
56
  * Creates (or reuses) an Ed25519 keypair, registers the agent, and writes to `.env`.
@@ -93,6 +98,23 @@ export interface ProviderApi {
93
98
  verify(httpMethod: HttpMethod, uri: string, headers?: HeaderBag): Promise<VerifyResult>
94
99
  }
95
100
 
101
+ export interface ToolApi {
102
+ /**
103
+ * Creates (or reuses) an Ed25519 keypair, registers the tool, and writes to `.env`.
104
+ */
105
+ init(): Promise<{
106
+ TOOL_PUBLIC_JWK: PublicJwk
107
+ TOOL_UID: string
108
+ path: string
109
+ isNew: boolean
110
+ }>
111
+
112
+ /**
113
+ * Verifies a signed request (fetching the agent's discovery keys when needed).
114
+ */
115
+ verify(httpMethod: HttpMethod, uri: string, headers?: HeaderBag): Promise<VerifyResult>
116
+ }
117
+
96
118
  export interface PrimitivesApi {
97
119
  /**
98
120
  * Creates an Ed25519 keypair. If `existingPrivateJwk` is provided, it is reused.
@@ -121,16 +143,19 @@ export interface PrimitivesApi {
121
143
  httpMethod: HttpMethod,
122
144
  uri: string,
123
145
  headers?: HeaderBag,
146
+ meter?: Meter,
124
147
  publicJwk?: PublicJwk
125
148
  ): Promise<VerifyResult>
126
149
  }
127
150
 
128
151
  export const agent: AgentApi
152
+ export const tool: ToolApi
129
153
  export const provider: ProviderApi
130
154
  export const primitives: PrimitivesApi
131
155
 
132
156
  declare const _default: {
133
157
  agent: AgentApi
158
+ tool: ToolApi
134
159
  provider: ProviderApi
135
160
  primitives: PrimitivesApi
136
161
  }
package/src/lib/tool.js CHANGED
@@ -1,5 +1,7 @@
1
+ const toolInit = require('./helpers/toolInit')
1
2
  const toolVerify = require('./helpers/toolVerify')
2
3
 
3
4
  module.exports = {
5
+ init: toolInit,
4
6
  verify: toolVerify
5
7
  }
@@ -1,11 +1,12 @@
1
1
  const primitives = require('./../../lib/primitives')
2
2
 
3
3
  class RegisterService {
4
- constructor ({ models, httpMethod, uri, headers, publicJwk }) {
4
+ constructor ({ models, httpMethod, uri, headers, meter, publicJwk }) {
5
5
  this.models = models
6
6
  this.httpMethod = httpMethod
7
7
  this.uri = uri
8
8
  this.headers = headers
9
+ this.meter = meter
9
10
  this.publicJwk = publicJwk
10
11
  }
11
12
 
@@ -14,6 +15,7 @@ class RegisterService {
14
15
  this.httpMethod,
15
16
  this.uri,
16
17
  this.headers,
18
+ this.meter,
17
19
  this.publicJwk
18
20
  )
19
21
 
@@ -11,7 +11,7 @@ class RotateService {
11
11
  }
12
12
 
13
13
  async run () {
14
- const remoteAgent = await tool.verify(this.httpMethod, this.uri, this.headers, this.serverHostname)
14
+ const remoteAgent = await tool.verify(this.httpMethod, this.uri, this.headers, {}, this.serverHostname)
15
15
  // uid: 'agent-6d2140af72bcefcedd4b44ab',
16
16
  // kid: 'Tx3W50MU5wMQ5I77z5DUGtbcs3ZPLlxfWx14pzpo5Fo',
17
17
  // public_jwk: {
@@ -9,7 +9,7 @@ class WhoamiService {
9
9
  }
10
10
 
11
11
  async run () {
12
- return tool.verify(this.httpMethod, this.uri, this.headers, this.serverHostname)
12
+ return tool.verify(this.httpMethod, this.uri, this.headers, {}, this.serverHostname)
13
13
  }
14
14
  }
15
15