402-announce 1.10.0 → 1.11.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/README.md +39 -6
- package/build/announce.js +31 -10
- package/build/announce.js.map +1 -1
- package/build/event.js +22 -7
- package/build/event.js.map +1 -1
- package/build/types.d.ts +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Announce HTTP 402 services on Nostr for decentralised discovery. Supports both L
|
|
|
6
6
|
|
|
7
7
|
Publishes **kind 31402** parameterised replaceable events so that AI agents (and any Nostr client) can discover paid APIs without a central registry.
|
|
8
8
|
|
|
9
|
-
**[Live Dashboard](https://
|
|
9
|
+
**[Live Dashboard](https://402.pub)** — see every service announcing on the network right now.
|
|
10
10
|
|
|
11
11
|
## How it works
|
|
12
12
|
|
|
@@ -38,7 +38,7 @@ const handle = await announceService({
|
|
|
38
38
|
relays: ['wss://relay.damus.io', 'wss://relay.primal.net'],
|
|
39
39
|
identifier: 'jokes-api',
|
|
40
40
|
name: 'Jokes API',
|
|
41
|
-
|
|
41
|
+
urls: ['https://jokes.example.com'],
|
|
42
42
|
about: 'A joke-telling service behind an L402 paywall',
|
|
43
43
|
pricing: [
|
|
44
44
|
{ capability: 'get_joke', price: 1, currency: 'sats' },
|
|
@@ -58,6 +58,28 @@ console.log('From pubkey:', handle.pubkey)
|
|
|
58
58
|
handle.close()
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
**Multi-transport example** (clearnet + Tor + Handshake — same service, different access paths):
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const handle = await announceService({
|
|
65
|
+
secretKey: '64-char-hex-nostr-secret-key',
|
|
66
|
+
relays: ['wss://relay.damus.io', 'wss://relay.primal.net'],
|
|
67
|
+
identifier: 'jokes-api',
|
|
68
|
+
name: 'Jokes API',
|
|
69
|
+
urls: [
|
|
70
|
+
'https://jokes.example.com', // clearnet
|
|
71
|
+
'http://jokesxyz...onion', // Tor hidden service
|
|
72
|
+
'https://jokes.example.hns', // Handshake domain
|
|
73
|
+
],
|
|
74
|
+
about: 'A joke-telling service behind an L402 paywall',
|
|
75
|
+
pricing: [{ capability: 'get_joke', price: 1, currency: 'sats' }],
|
|
76
|
+
paymentMethods: ['bitcoin-lightning-bolt11'],
|
|
77
|
+
topics: ['comedy', 'ai'],
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Each URL becomes a separate `url` tag in the kind 31402 event. Clients try them in order and use whichever they can reach. `urls` accepts 1–10 entries; any parseable URL is valid.
|
|
82
|
+
|
|
61
83
|
See [`examples/`](./examples) for runnable scripts.
|
|
62
84
|
|
|
63
85
|
## How it fits together
|
|
@@ -133,7 +155,7 @@ Lower-level function that builds and signs the event without publishing. Useful
|
|
|
133
155
|
| `relays` | `string[]` | yes | Relay URLs (`wss://` or `ws://`) |
|
|
134
156
|
| `identifier` | `string` | yes | Unique listing ID (Nostr `d` tag) |
|
|
135
157
|
| `name` | `string` | yes | Human-readable service name |
|
|
136
|
-
| `
|
|
158
|
+
| `urls` | `string[]` | yes | HTTP endpoints for the service (1–10 entries, any parseable URL) |
|
|
137
159
|
| `about` | `string` | yes | Short description |
|
|
138
160
|
| `pricing` | `PricingDef[]` | yes | Per-capability pricing |
|
|
139
161
|
| `paymentMethods` | `string[]` | yes | Accepted payment methods |
|
|
@@ -171,7 +193,8 @@ graph TB
|
|
|
171
193
|
subgraph Tags
|
|
172
194
|
D["d: jokes-api"]
|
|
173
195
|
N["name: Jokes API"]
|
|
174
|
-
|
|
196
|
+
U1["url: https://jokes.example.com"]
|
|
197
|
+
U2["url: https://jokesapi.example.onion (optional)"]
|
|
175
198
|
AB["about: A joke-telling service"]
|
|
176
199
|
PMI1["pmi: bitcoin-lightning-bolt11"]
|
|
177
200
|
PMI2["pmi: bitcoin-cashu"]
|
|
@@ -194,7 +217,7 @@ graph TB
|
|
|
194
217
|
|-----------|----------|----------------------------------------------|-----------------------------------|
|
|
195
218
|
| `d` | yes | Unique identifier for this listing | `jokes-api` |
|
|
196
219
|
| `name` | yes | Human-readable service name | `Jokes API` |
|
|
197
|
-
| `url` | yes | HTTP endpoint
|
|
220
|
+
| `url` | yes | HTTP endpoint (one tag per URL; repeatable) | `https://jokes.example.com` |
|
|
198
221
|
| `about` | yes | Short description | `A joke-telling service` |
|
|
199
222
|
| `pmi` | yes | Payment method identifier (repeatable) | `bitcoin-lightning-bolt11` |
|
|
200
223
|
| `price` | yes | Capability pricing (repeatable) | `get_joke`, `1`, `sats` |
|
|
@@ -223,6 +246,16 @@ The event content is a JSON object with optional fields:
|
|
|
223
246
|
}
|
|
224
247
|
```
|
|
225
248
|
|
|
249
|
+
## Multiple URLs vs multiple events
|
|
250
|
+
|
|
251
|
+
This distinction is important for operators:
|
|
252
|
+
|
|
253
|
+
**Multiple URLs in one event** — use `urls: ['...', '...']` when the URLs represent the **same service** on different transports (clearnet, Tor, Handshake). The pricing, credentials, and macaroon signing key are identical. Clients pick whichever URL they can reach. This is for censorship resistance and redundancy.
|
|
254
|
+
|
|
255
|
+
**Separate kind 31402 events** — publish a new event (different `identifier`) when you have **genuinely different services**: different pricing tiers per transport, different capabilities, or services that operate independently. A single event should describe one logical service.
|
|
256
|
+
|
|
257
|
+
In short: same service + different network paths → one event with multiple `url` tags. Different services → separate events.
|
|
258
|
+
|
|
226
259
|
## Security
|
|
227
260
|
|
|
228
261
|
- Secret key bytes are zeroised immediately after signing (in both `announceService` and `buildAnnounceEvent`)
|
|
@@ -238,7 +271,7 @@ The event content is a JSON object with optional fields:
|
|
|
238
271
|
| [toll-booth-announce](https://github.com/TheCryptoDonkey/toll-booth-announce) | Bridge — announce toll-booth services with one function call |
|
|
239
272
|
| [satgate](https://github.com/TheCryptoDonkey/satsgate) | Production L402 gateway with Lightning and Cashu support |
|
|
240
273
|
| [402-mcp](https://github.com/TheCryptoDonkey/402-mcp) | MCP server for AI agents to discover, pay, and consume 402 APIs |
|
|
241
|
-
| [Live Dashboard](https://
|
|
274
|
+
| [Live Dashboard](https://402.pub) | See every service announcing on the network |
|
|
242
275
|
|
|
243
276
|
## Licence
|
|
244
277
|
|
package/build/announce.js
CHANGED
|
@@ -52,18 +52,39 @@ export async function announceService(config) {
|
|
|
52
52
|
console.warn(`[402-announce] Insecure WebSocket (ws://) relay: ${url} — use wss:// in production`);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
// Reject
|
|
56
|
-
// to remote clients.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
// Reject events where ALL service URLs are private/loopback — announcing only
|
|
56
|
+
// localhost URLs is never useful to remote clients. At least one public URL is required.
|
|
57
|
+
// .onion URLs skip SSRF checks (can't resolve server-side) and count as public.
|
|
58
|
+
// Non-http/https schemes also skip SSRF checks and count as public.
|
|
59
|
+
// (Note: event.ts intentionally allows private hosts for pure serialisation.)
|
|
60
|
+
let hasPublicUrl = false;
|
|
61
|
+
for (const serviceUrlStr of config.urls) {
|
|
62
|
+
let parsed;
|
|
63
|
+
try {
|
|
64
|
+
parsed = new URL(serviceUrlStr);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Already validated by buildAnnounceEvent — should not reach here
|
|
68
|
+
throw new Error(`Invalid service URL: ${serviceUrlStr}`);
|
|
69
|
+
}
|
|
70
|
+
const scheme = parsed.protocol; // includes trailing colon
|
|
71
|
+
if (scheme !== 'http:' && scheme !== 'https:') {
|
|
72
|
+
// Non-http/https schemes (hyper://, .onion via custom schemes, etc.) skip SSRF
|
|
73
|
+
hasPublicUrl = true;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const hostname = parsed.hostname;
|
|
77
|
+
if (hostname.endsWith('.onion')) {
|
|
78
|
+
// .onion addresses cannot be resolved server-side — treat as public
|
|
79
|
+
hasPublicUrl = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (!isPrivateHost(hostname)) {
|
|
83
|
+
hasPublicUrl = true;
|
|
61
84
|
}
|
|
62
85
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
throw e;
|
|
66
|
-
throw new Error(`Invalid service URL: ${config.url}`);
|
|
86
|
+
if (!hasPublicUrl) {
|
|
87
|
+
throw new Error(`All service URLs point to private/loopback addresses — use at least one public URL or set --public-url`);
|
|
67
88
|
}
|
|
68
89
|
// Build and sign the event (H2: no redundant key decode — pubkey comes from the event)
|
|
69
90
|
const event = buildAnnounceEvent(secretKey, config);
|
package/build/announce.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"announce.js","sourceRoot":"","sources":["../src/announce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAG1C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAsB;IAC1D,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM,CAAA;IAC/C,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAA;IAEtC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACvD,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IACjD,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,oCAAoC,CAAC,CAAA;QAChF,CAAC;QAED,2DAA2D;QAC3D,IAAI,MAAW,CAAA;QACf,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAA;QAC9C,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,2CAA2C,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC/F,CAAC;QACD,IAAI,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,mDAAmD,GAAG,EAAE,CAAC,CAAA;QAC3E,CAAC;QAED,mCAAmC;QACnC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CACV,oDAAoD,GAAG,6BAA6B,CACrF,CAAA;QACH,CAAC;IACH,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"announce.js","sourceRoot":"","sources":["../src/announce.ts"],"names":[],"mappings":"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"}
|
package/build/event.js
CHANGED
|
@@ -15,14 +15,29 @@ export function buildAnnounceEvent(secretKeyHex, config) {
|
|
|
15
15
|
if (!/^[0-9a-f]{64}$/i.test(secretKeyHex)) {
|
|
16
16
|
throw new Error('secretKey must be a 64-character hex string');
|
|
17
17
|
}
|
|
18
|
-
// M1: Validate
|
|
18
|
+
// M1: Validate urls array (scheme-agnostic — this function serialises URLs
|
|
19
19
|
// into event tags without performing network I/O, so private hosts are allowed)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
throw new Error('config.url must start with http:// or https://');
|
|
20
|
+
if (config.urls.length === 0) {
|
|
21
|
+
throw new Error('config.urls must contain at least one entry');
|
|
23
22
|
}
|
|
24
|
-
if (config.
|
|
25
|
-
throw new Error('config.
|
|
23
|
+
if (config.urls.length > 10) {
|
|
24
|
+
throw new Error('config.urls must not exceed 10 entries');
|
|
25
|
+
}
|
|
26
|
+
const seenUrls = new Set();
|
|
27
|
+
for (const u of config.urls) {
|
|
28
|
+
if (u.length > 2048) {
|
|
29
|
+
throw new Error('config.urls entry must not exceed 2048 characters');
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
new URL(u);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error(`config.urls entry is not a valid URL: ${u}`);
|
|
36
|
+
}
|
|
37
|
+
if (seenUrls.has(u)) {
|
|
38
|
+
throw new Error('config.urls must not contain duplicate entries');
|
|
39
|
+
}
|
|
40
|
+
seenUrls.add(u);
|
|
26
41
|
}
|
|
27
42
|
// M1: Validate picture field when present
|
|
28
43
|
if (config.picture !== undefined) {
|
|
@@ -112,7 +127,7 @@ export function buildAnnounceEvent(secretKeyHex, config) {
|
|
|
112
127
|
const tags = [
|
|
113
128
|
['d', config.identifier],
|
|
114
129
|
['name', config.name],
|
|
115
|
-
['url',
|
|
130
|
+
...config.urls.map(u => ['url', u]),
|
|
116
131
|
['about', config.about],
|
|
117
132
|
];
|
|
118
133
|
if (config.picture) {
|
package/build/event.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event.js","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAIvC;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,YAAoB,EACpB,MAAsC;IAEtC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"event.js","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
CHANGED
|
@@ -28,8 +28,8 @@ export interface AnnounceConfig {
|
|
|
28
28
|
identifier: string;
|
|
29
29
|
/** Human-readable service name */
|
|
30
30
|
name: string;
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/** Transport endpoint URLs (1-10, each max 2048 characters). */
|
|
32
|
+
urls: string[];
|
|
33
33
|
/** Short description of what the service does */
|
|
34
34
|
about: string;
|
|
35
35
|
/** Optional icon URL */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "402-announce",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Announce HTTP 402 services (L402 and x402) on Nostr for decentralised discovery. Kind 31402 parameterised replaceable events.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"machine-payments",
|
|
51
51
|
"http-402"
|
|
52
52
|
],
|
|
53
|
-
"homepage": "https://
|
|
53
|
+
"homepage": "https://402.pub",
|
|
54
54
|
"repository": {
|
|
55
55
|
"type": "git",
|
|
56
56
|
"url": "https://github.com/TheCryptoDonkey/402-announce.git"
|