Add optional info field to offers

- Add info field to Offer and CreateOfferRequest types
- Validate info field: optional, max 128 characters
- Include info field in all public API responses
- Update README with info field documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-22 17:32:56 +01:00
parent 341d043358
commit 00499732c4
3 changed files with 24 additions and 4 deletions

View File

@@ -111,7 +111,8 @@ Find offers by topic with optional bloom filter exclusion
"topics": ["movie-xyz", "hd-content"], "topics": ["movie-xyz", "hd-content"],
"expiresAt": 1234567890, "expiresAt": 1234567890,
"lastSeen": 1234567890, "lastSeen": 1234567890,
"hasSecret": true // Indicates if secret is required to answer "hasSecret": true, // Indicates if secret is required to answer
"info": "Looking for peers in EU region" // Public info field (optional)
} }
], ],
"total": 42, "total": 42,
@@ -121,6 +122,7 @@ Find offers by topic with optional bloom filter exclusion
**Notes:** **Notes:**
- `hasSecret`: Boolean flag indicating whether a secret is required to answer this offer. The actual secret is never exposed in public endpoints. - `hasSecret`: Boolean flag indicating whether a secret is required to answer this offer. The actual secret is never exposed in public endpoints.
- `info`: Optional public metadata field (max 128 characters) visible to all peers.
#### `GET /peers/:peerId/offers` #### `GET /peers/:peerId/offers`
View all offers from a specific peer View all offers from a specific peer
@@ -140,7 +142,8 @@ Create one or more offers
"sdp": "v=0...", "sdp": "v=0...",
"topics": ["movie-xyz", "hd-content"], "topics": ["movie-xyz", "hd-content"],
"ttl": 300000, "ttl": 300000,
"secret": "my-secret-password" // Optional: protect offer (max 128 chars) "secret": "my-secret-password", // Optional: protect offer (max 128 chars)
"info": "Looking for peers in EU region" // Optional: public info (max 128 chars)
} }
] ]
} }
@@ -148,6 +151,7 @@ Create one or more offers
**Notes:** **Notes:**
- `secret` (optional): Protect the offer with a secret. Answerers must provide the correct secret to connect. - `secret` (optional): Protect the offer with a secret. Answerers must provide the correct secret to connect.
- `info` (optional): Public metadata visible to all peers (max 128 characters). Useful for describing the offer or connection requirements.
#### `GET /offers/mine` #### `GET /offers/mine`
List all offers owned by authenticated peer List all offers owned by authenticated peer

View File

@@ -151,6 +151,16 @@ export function createApp(storage: Storage, config: Config) {
} }
} }
// Validate info if provided
if (offer.info !== undefined) {
if (typeof offer.info !== 'string') {
return c.json({ error: 'Info must be a string' }, 400);
}
if (offer.info.length > 128) {
return c.json({ error: 'Info must be 128 characters or less' }, 400);
}
}
// Validate topics // Validate topics
if (!Array.isArray(offer.topics) || offer.topics.length === 0) { if (!Array.isArray(offer.topics) || offer.topics.length === 0) {
return c.json({ error: 'Each offer must have a non-empty topics array' }, 400); return c.json({ error: 'Each offer must have a non-empty topics array' }, 400);
@@ -182,6 +192,7 @@ export function createApp(storage: Storage, config: Config) {
topics: offer.topics, topics: offer.topics,
expiresAt: Date.now() + ttl, expiresAt: Date.now() + ttl,
secret: offer.secret, secret: offer.secret,
info: offer.info,
}); });
} }
@@ -254,7 +265,8 @@ export function createApp(storage: Storage, config: Config) {
topics: o.topics, topics: o.topics,
expiresAt: o.expiresAt, expiresAt: o.expiresAt,
lastSeen: o.lastSeen, lastSeen: o.lastSeen,
hasSecret: !!o.secret // Indicate if secret is required without exposing it hasSecret: !!o.secret, // Indicate if secret is required without exposing it
info: o.info // Public info field
})), })),
total: bloomParam ? total + excludePeerIds.length : total, total: bloomParam ? total + excludePeerIds.length : total,
returned: offers.length returned: offers.length
@@ -321,7 +333,8 @@ export function createApp(storage: Storage, config: Config) {
topics: o.topics, topics: o.topics,
expiresAt: o.expiresAt, expiresAt: o.expiresAt,
lastSeen: o.lastSeen, lastSeen: o.lastSeen,
hasSecret: !!o.secret // Indicate if secret is required without exposing it hasSecret: !!o.secret, // Indicate if secret is required without exposing it
info: o.info // Public info field
})), })),
topics: Array.from(topicsSet) topics: Array.from(topicsSet)
}, 200); }, 200);
@@ -351,6 +364,7 @@ export function createApp(storage: Storage, config: Config) {
expiresAt: o.expiresAt, expiresAt: o.expiresAt,
lastSeen: o.lastSeen, lastSeen: o.lastSeen,
secret: o.secret, // Owner can see the secret secret: o.secret, // Owner can see the secret
info: o.info, // Owner can see the info
answererPeerId: o.answererPeerId, answererPeerId: o.answererPeerId,
answeredAt: o.answeredAt answeredAt: o.answeredAt
})) }))

View File

@@ -10,6 +10,7 @@ export interface Offer {
expiresAt: number; expiresAt: number;
lastSeen: number; lastSeen: number;
secret?: string; secret?: string;
info?: string;
answererPeerId?: string; answererPeerId?: string;
answerSdp?: string; answerSdp?: string;
answeredAt?: number; answeredAt?: number;
@@ -46,6 +47,7 @@ export interface CreateOfferRequest {
topics: string[]; topics: string[];
expiresAt: number; expiresAt: number;
secret?: string; secret?: string;
info?: string;
} }
/** /**