pelagora 0.1.5
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 +40 -0
- package/LICENSE +663 -0
- package/README.md +139 -0
- package/dist/ai/product-lookup.d.ts +26 -0
- package/dist/ai/product-lookup.d.ts.map +1 -0
- package/dist/ai/product-lookup.js +153 -0
- package/dist/ai/product-lookup.js.map +1 -0
- package/dist/api/collections.d.ts +3 -0
- package/dist/api/collections.d.ts.map +1 -0
- package/dist/api/collections.js +69 -0
- package/dist/api/collections.js.map +1 -0
- package/dist/api/favorites.d.ts +3 -0
- package/dist/api/favorites.d.ts.map +1 -0
- package/dist/api/favorites.js +43 -0
- package/dist/api/favorites.js.map +1 -0
- package/dist/api/health.d.ts +12 -0
- package/dist/api/health.d.ts.map +1 -0
- package/dist/api/health.js +54 -0
- package/dist/api/health.js.map +1 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +56 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/items.d.ts +3 -0
- package/dist/api/items.d.ts.map +1 -0
- package/dist/api/items.js +170 -0
- package/dist/api/items.js.map +1 -0
- package/dist/api/media.d.ts +3 -0
- package/dist/api/media.d.ts.map +1 -0
- package/dist/api/media.js +241 -0
- package/dist/api/media.js.map +1 -0
- package/dist/api/negotiations.d.ts +3 -0
- package/dist/api/negotiations.d.ts.map +1 -0
- package/dist/api/negotiations.js +244 -0
- package/dist/api/negotiations.js.map +1 -0
- package/dist/api/offers.d.ts +3 -0
- package/dist/api/offers.d.ts.map +1 -0
- package/dist/api/offers.js +57 -0
- package/dist/api/offers.js.map +1 -0
- package/dist/api/refs.d.ts +3 -0
- package/dist/api/refs.d.ts.map +1 -0
- package/dist/api/refs.js +390 -0
- package/dist/api/refs.js.map +1 -0
- package/dist/api/scans.d.ts +3 -0
- package/dist/api/scans.d.ts.map +1 -0
- package/dist/api/scans.js +384 -0
- package/dist/api/scans.js.map +1 -0
- package/dist/api/settings.d.ts +3 -0
- package/dist/api/settings.d.ts.map +1 -0
- package/dist/api/settings.js +442 -0
- package/dist/api/settings.js.map +1 -0
- package/dist/db/index.d.ts +4 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +18 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/queries.d.ts +237 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +891 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.d.ts +6 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +531 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/dht/discovery.d.ts +33 -0
- package/dist/dht/discovery.d.ts.map +1 -0
- package/dist/dht/discovery.js +281 -0
- package/dist/dht/discovery.js.map +1 -0
- package/dist/dht/index.d.ts +2 -0
- package/dist/dht/index.d.ts.map +1 -0
- package/dist/dht/index.js +6 -0
- package/dist/dht/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +215 -0
- package/dist/index.js.map +1 -0
- package/dist/ref-schemas.d.ts +59 -0
- package/dist/ref-schemas.d.ts.map +1 -0
- package/dist/ref-schemas.js +1038 -0
- package/dist/ref-schemas.js.map +1 -0
- package/dist/skills/export.d.ts +12 -0
- package/dist/skills/export.d.ts.map +1 -0
- package/dist/skills/export.js +54 -0
- package/dist/skills/export.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +11 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/loader.d.ts +37 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +183 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/registry.d.ts +37 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +136 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/sync/index.d.ts +58 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +331 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/reffo-client.d.ts +144 -0
- package/dist/sync/reffo-client.d.ts.map +1 -0
- package/dist/sync/reffo-client.js +279 -0
- package/dist/sync/reffo-client.js.map +1 -0
- package/dist/taxonomy.d.ts +4 -0
- package/dist/taxonomy.d.ts.map +1 -0
- package/dist/taxonomy.js +141 -0
- package/dist/taxonomy.js.map +1 -0
- package/dist/types/index.d.ts +198 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +25 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui.d.ts +2 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +6786 -0
- package/dist/ui.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +14 -0
- package/dist/version.js.map +1 -0
- package/footer-brand.png +0 -0
- package/header-brand.png +0 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# reffo-beacon
|
|
2
|
+
|
|
3
|
+
Self-hosted beacon server for the protocol.
|
|
4
|
+
|
|
5
|
+
Beacons store inventory locally in SQLite and announce to a Hyperswarm DHT so other beacons can discover and query your listings without any central server. Data is structured using [Schema.org](https://schema.org) types for universal compatibility with search engines, LLMs, and third-party platforms.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install
|
|
11
|
+
npm run build
|
|
12
|
+
npm start
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The beacon runs on `http://localhost:3000` by default. Open it in a browser to use the web UI.
|
|
16
|
+
|
|
17
|
+
For development with auto-reload:
|
|
18
|
+
```bash
|
|
19
|
+
npm run dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Web UI
|
|
23
|
+
|
|
24
|
+
Navigate to `http://localhost:3000` in your browser. The built-in UI lets you:
|
|
25
|
+
|
|
26
|
+
- **List a Ref** — fill in name, category/subcategory, category-specific attributes, price and click submit
|
|
27
|
+
- **My Refs** — see all your inventory with prices, condition badges, and attribute summaries
|
|
28
|
+
- **Search Network** — search across connected peer beacons by keyword, category, or max price
|
|
29
|
+
|
|
30
|
+
## Data Model
|
|
31
|
+
|
|
32
|
+
Every listing is a **Ref** — the universal base unit in Reffo. Refs support category-specific attributes (car fields for cars, house fields for houses, etc.) with Schema.org compatibility.
|
|
33
|
+
|
|
34
|
+
Key concepts:
|
|
35
|
+
- **Category Schemas**: Each category defines typed fields, condition options, and Schema.org mappings
|
|
36
|
+
- **Trait System**: Refs compose behavior through traits (Priceable, Conditional, Valueable, Serialized, LocationBound, etc.)
|
|
37
|
+
- **Schema.org JSON-LD**: Attributes transform into standard Schema.org structured data when synced
|
|
38
|
+
|
|
39
|
+
See the [Data Model documentation](./docs/REF_DATA_MODEL.md) for full details.
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
Full API documentation: [docs/API_REFERENCE.md](./docs/API_REFERENCE.md)
|
|
44
|
+
|
|
45
|
+
### Refs
|
|
46
|
+
```
|
|
47
|
+
GET /refs # List all (or ?category=X&subcategory=Y or ?search=X)
|
|
48
|
+
GET /refs/:id # Get one
|
|
49
|
+
POST /refs # Create { name, description?, category?, subcategory?, condition?, attributes?, ... }
|
|
50
|
+
PATCH /refs/:id # Update fields
|
|
51
|
+
DELETE /refs/:id # Remove
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Media
|
|
55
|
+
```
|
|
56
|
+
GET /refs/:refId/media # List media for a ref
|
|
57
|
+
POST /refs/:refId/media # Upload photos/video (multipart)
|
|
58
|
+
DELETE /refs/:refId/media/:id # Delete one
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Offers
|
|
62
|
+
```
|
|
63
|
+
GET /offers # List all (or ?refId=X)
|
|
64
|
+
GET /offers/:id # Get one
|
|
65
|
+
POST /offers # Create { refId, price, priceCurrency?, status?, location? }
|
|
66
|
+
PATCH /offers/:id # Update fields
|
|
67
|
+
DELETE /offers/:id # Remove
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Negotiations
|
|
71
|
+
```
|
|
72
|
+
GET /negotiations # List all (or ?role=buyer|seller)
|
|
73
|
+
POST /negotiations # Send proposal
|
|
74
|
+
PATCH /negotiations/:id # Respond (accept/reject/counter)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Peer Search
|
|
78
|
+
```
|
|
79
|
+
GET /search?q=guitar # Search across all connected beacons
|
|
80
|
+
GET /search?c=Electronics&sc=Gaming&maxPrice=100
|
|
81
|
+
GET /search?lat=28.5&lng=-81.3&radiusMiles=50
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Param | Description |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `q` | Keyword search |
|
|
87
|
+
| `c` | Category filter |
|
|
88
|
+
| `sc` | Subcategory filter |
|
|
89
|
+
| `maxPrice` | Maximum price |
|
|
90
|
+
| `lat` | Search center latitude |
|
|
91
|
+
| `lng` | Search center longitude |
|
|
92
|
+
| `radiusMiles` | Search radius in miles |
|
|
93
|
+
|
|
94
|
+
## Environment Variables
|
|
95
|
+
|
|
96
|
+
| Variable | Default | Description |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `PORT` | `3000` | HTTP server port |
|
|
99
|
+
| `BEACON_ID` | random | 64-char hex beacon identity |
|
|
100
|
+
| `REFFO_DB_PATH` | `./reffo-beacon.db` | SQLite database path |
|
|
101
|
+
|
|
102
|
+
## Docker
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
docker build -t reffo-beacon .
|
|
106
|
+
docker run -p 3000:3000 -v reffo-data:/app reffo-beacon
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## How It Works
|
|
110
|
+
|
|
111
|
+
1. You list refs and create offers via the web UI or REST API
|
|
112
|
+
2. Your beacon joins the Reffo DHT topic via Hyperswarm
|
|
113
|
+
3. Other beacons connect as peers and exchange announcements
|
|
114
|
+
4. When someone searches (`GET /search`), your beacon queries all connected peers
|
|
115
|
+
5. Peers respond with matching refs and offers from their local databases
|
|
116
|
+
6. When synced to reffo.ai, attributes are transformed to Schema.org JSON-LD
|
|
117
|
+
|
|
118
|
+
No central server required. Each beacon is a fully independent node.
|
|
119
|
+
|
|
120
|
+
## Contributing
|
|
121
|
+
|
|
122
|
+
Reffo's category system is designed to be community-extensible. To add a new category schema:
|
|
123
|
+
|
|
124
|
+
1. Define the Schema.org type mapping and form fields in `src/ref-schemas.ts`
|
|
125
|
+
2. Register it in the `CATEGORY_SCHEMAS` map
|
|
126
|
+
3. See [docs/ADDING_CATEGORIES.md](./docs/ADDING_CATEGORIES.md) for the complete guide
|
|
127
|
+
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
- [Data Model](./docs/REF_DATA_MODEL.md) — Ref base class, traits, and privacy tiers
|
|
131
|
+
- [Schema.org Guide](./docs/SCHEMA_GUIDE.md) — How Refs map to Schema.org JSON-LD
|
|
132
|
+
- [Adding Categories](./docs/ADDING_CATEGORIES.md) — Step-by-step guide for new category schemas
|
|
133
|
+
- [API Reference](./docs/API_REFERENCE.md) — Complete REST API documentation
|
|
134
|
+
|
|
135
|
+
## Testing
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm test
|
|
139
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-provider AI product lookup abstraction.
|
|
3
|
+
* Supports: anthropic, openai, google, xai — all returning the same response shape.
|
|
4
|
+
*/
|
|
5
|
+
export type AiProvider = 'anthropic' | 'openai' | 'google' | 'xai';
|
|
6
|
+
export interface ProductLookupRequest {
|
|
7
|
+
name: string;
|
|
8
|
+
category?: string;
|
|
9
|
+
subcategory?: string;
|
|
10
|
+
attributeKeys: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface ProductLookupResponse {
|
|
13
|
+
description: string | null;
|
|
14
|
+
sku: string | null;
|
|
15
|
+
product_url: string | null;
|
|
16
|
+
image_url: string | null;
|
|
17
|
+
attributes: Record<string, string>;
|
|
18
|
+
price_estimate: {
|
|
19
|
+
low: number;
|
|
20
|
+
high: number;
|
|
21
|
+
typical: number;
|
|
22
|
+
confidence: 'low' | 'medium' | 'high';
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare function callProductLookup(provider: AiProvider, apiKey: string, req: ProductLookupRequest): Promise<ProductLookupResponse>;
|
|
26
|
+
//# sourceMappingURL=product-lookup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-lookup.d.ts","sourceRoot":"","sources":["../../src/ai/product-lookup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,cAAc,EAAE;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;KACvC,CAAC;CACH;AAyJD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,UAAU,EACpB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,qBAAqB,CAAC,CAehC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Multi-provider AI product lookup abstraction.
|
|
4
|
+
* Supports: anthropic, openai, google, xai — all returning the same response shape.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.callProductLookup = callProductLookup;
|
|
8
|
+
function buildPrompt(req) {
|
|
9
|
+
const parts = [
|
|
10
|
+
`Product: ${req.name}`,
|
|
11
|
+
req.category && `Category: ${req.category}`,
|
|
12
|
+
req.subcategory && `Subcategory: ${req.subcategory}`,
|
|
13
|
+
].filter(Boolean).join('\n');
|
|
14
|
+
const attrList = req.attributeKeys.length > 0
|
|
15
|
+
? `Only fill these attribute keys: ${req.attributeKeys.join(', ')}`
|
|
16
|
+
: 'No category-specific attributes for this category.';
|
|
17
|
+
return `You are a product data expert. Given a product name and category, return structured product data as JSON.
|
|
18
|
+
|
|
19
|
+
${parts}
|
|
20
|
+
|
|
21
|
+
${attrList}
|
|
22
|
+
|
|
23
|
+
Return this exact JSON format:
|
|
24
|
+
{
|
|
25
|
+
"description": "<Start with 1 concise summary sentence. Then 1-2 detailed paragraphs covering key features, specs, and typical use cases. Factual only, not marketing copy. Null if unknown.>",
|
|
26
|
+
"sku": "<manufacturer SKU/part number, or null if unknown>",
|
|
27
|
+
"product_url": "<official manufacturer product page URL, or null if unknown>",
|
|
28
|
+
"image_url": "<official product image URL from manufacturer domain, or null if unknown>",
|
|
29
|
+
"attributes": {<only keys from the provided list, values as strings, omit unknown>},
|
|
30
|
+
"price_estimate": {"low": <number>, "high": <number>, "typical": <number>, "confidence": "<low|medium|high>"}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Rules:
|
|
34
|
+
- Return null for any field you are uncertain about. Do NOT hallucinate.
|
|
35
|
+
- Only provide URLs from the manufacturer's official domain.
|
|
36
|
+
- Only fill attribute keys from the provided list.
|
|
37
|
+
- Description should start with one concise summary sentence, followed by 1-2 detailed paragraphs. Factual only, not marketing copy.
|
|
38
|
+
- All prices in USD as numbers (no $ sign).
|
|
39
|
+
- confidence: "high" if well-known product, "medium" if somewhat familiar, "low" if uncertain.
|
|
40
|
+
- Respond with ONLY valid JSON, no other text.`;
|
|
41
|
+
}
|
|
42
|
+
async function callAnthropic(apiKey, prompt) {
|
|
43
|
+
const res = await fetch('https://api.anthropic.com/v1/messages', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'x-api-key': apiKey,
|
|
48
|
+
'anthropic-version': '2023-06-01',
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
model: 'claude-3-haiku-20240307',
|
|
52
|
+
max_tokens: 1024,
|
|
53
|
+
temperature: 0,
|
|
54
|
+
messages: [{ role: 'user', content: prompt }],
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
if (!res.ok) {
|
|
58
|
+
const errText = await res.text();
|
|
59
|
+
throw new Error(`Anthropic API error ${res.status}: ${errText}`);
|
|
60
|
+
}
|
|
61
|
+
const data = await res.json();
|
|
62
|
+
const text = data.content?.[0]?.type === 'text' ? data.content[0].text : '';
|
|
63
|
+
return parseResponse(text, 'claude-3-haiku-20240307');
|
|
64
|
+
}
|
|
65
|
+
async function callOpenAICompatible(apiKey, prompt, endpoint, model) {
|
|
66
|
+
const res = await fetch(endpoint, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
model,
|
|
74
|
+
temperature: 0,
|
|
75
|
+
max_tokens: 1024,
|
|
76
|
+
response_format: { type: 'json_object' },
|
|
77
|
+
messages: [{ role: 'user', content: prompt }],
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
if (!res.ok) {
|
|
81
|
+
const errText = await res.text();
|
|
82
|
+
throw new Error(`${model} API error ${res.status}: ${errText}`);
|
|
83
|
+
}
|
|
84
|
+
const data = await res.json();
|
|
85
|
+
const text = data.choices?.[0]?.message?.content ?? '';
|
|
86
|
+
return parseResponse(text, model);
|
|
87
|
+
}
|
|
88
|
+
async function callGoogle(apiKey, prompt) {
|
|
89
|
+
const model = 'gemini-2.0-flash-lite';
|
|
90
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
|
|
91
|
+
const res = await fetch(url, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: { 'Content-Type': 'application/json' },
|
|
94
|
+
body: JSON.stringify({
|
|
95
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
96
|
+
generationConfig: {
|
|
97
|
+
temperature: 0,
|
|
98
|
+
maxOutputTokens: 1024,
|
|
99
|
+
responseMimeType: 'application/json',
|
|
100
|
+
},
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
if (!res.ok) {
|
|
104
|
+
const errText = await res.text();
|
|
105
|
+
throw new Error(`Google AI error ${res.status}: ${errText}`);
|
|
106
|
+
}
|
|
107
|
+
const data = await res.json();
|
|
108
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text ?? '';
|
|
109
|
+
return parseResponse(text, model);
|
|
110
|
+
}
|
|
111
|
+
function parseResponse(text, model) {
|
|
112
|
+
const cleaned = text.replace(/```json\s*/g, '').replace(/```\s*/g, '').trim();
|
|
113
|
+
const parsed = JSON.parse(cleaned);
|
|
114
|
+
const DEVICE_UNIQUE = new Set(['vin', 'hin', 'imei', 'parcel_id']);
|
|
115
|
+
const attrs = {};
|
|
116
|
+
if (parsed.attributes && typeof parsed.attributes === 'object') {
|
|
117
|
+
for (const [k, v] of Object.entries(parsed.attributes)) {
|
|
118
|
+
if (v != null && v !== '' && !DEVICE_UNIQUE.has(k))
|
|
119
|
+
attrs[k] = String(v);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const pe = parsed.price_estimate || {};
|
|
123
|
+
const confidence = ['low', 'medium', 'high'].includes(pe.confidence) ? pe.confidence : 'low';
|
|
124
|
+
return {
|
|
125
|
+
description: typeof parsed.description === 'string' ? parsed.description : null,
|
|
126
|
+
sku: typeof parsed.sku === 'string' ? parsed.sku : null,
|
|
127
|
+
product_url: typeof parsed.product_url === 'string' ? parsed.product_url : null,
|
|
128
|
+
image_url: typeof parsed.image_url === 'string' ? parsed.image_url : null,
|
|
129
|
+
attributes: attrs,
|
|
130
|
+
price_estimate: {
|
|
131
|
+
low: Math.max(0, Number(pe.low) || 0),
|
|
132
|
+
high: Math.max(0, Number(pe.high) || 0),
|
|
133
|
+
typical: Math.max(0, Number(pe.typical) || 0),
|
|
134
|
+
confidence,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function callProductLookup(provider, apiKey, req) {
|
|
139
|
+
const prompt = buildPrompt(req);
|
|
140
|
+
switch (provider) {
|
|
141
|
+
case 'anthropic':
|
|
142
|
+
return callAnthropic(apiKey, prompt);
|
|
143
|
+
case 'openai':
|
|
144
|
+
return callOpenAICompatible(apiKey, prompt, 'https://api.openai.com/v1/chat/completions', 'gpt-4o-mini');
|
|
145
|
+
case 'google':
|
|
146
|
+
return callGoogle(apiKey, prompt);
|
|
147
|
+
case 'xai':
|
|
148
|
+
return callOpenAICompatible(apiKey, prompt, 'https://api.x.ai/v1/chat/completions', 'grok-3-mini-fast');
|
|
149
|
+
default:
|
|
150
|
+
throw new Error(`Unsupported AI provider: ${provider}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=product-lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-lookup.js","sourceRoot":"","sources":["../../src/ai/product-lookup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/api/collections.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAyExB,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const express_1 = require("express");
|
|
4
|
+
const db_1 = require("../db");
|
|
5
|
+
const router = (0, express_1.Router)();
|
|
6
|
+
// GET /collections
|
|
7
|
+
router.get('/', (_req, res) => {
|
|
8
|
+
const collections = new db_1.CollectionQueries();
|
|
9
|
+
const list = collections.list();
|
|
10
|
+
const result = list.map(c => ({
|
|
11
|
+
...c,
|
|
12
|
+
refCount: collections.countRefs(c.id),
|
|
13
|
+
}));
|
|
14
|
+
res.json(result);
|
|
15
|
+
});
|
|
16
|
+
// POST /collections
|
|
17
|
+
router.post('/', (req, res) => {
|
|
18
|
+
const collections = new db_1.CollectionQueries();
|
|
19
|
+
const { name, description } = req.body;
|
|
20
|
+
if (!name || typeof name !== 'string') {
|
|
21
|
+
return res.status(400).json({ error: 'name is required' });
|
|
22
|
+
}
|
|
23
|
+
const collection = collections.create({ name, description });
|
|
24
|
+
res.status(201).json({
|
|
25
|
+
...collection,
|
|
26
|
+
refCount: 0,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
// GET /collections/:id
|
|
30
|
+
router.get('/:id', (req, res) => {
|
|
31
|
+
const collections = new db_1.CollectionQueries();
|
|
32
|
+
const collection = collections.get(String(req.params.id));
|
|
33
|
+
if (!collection)
|
|
34
|
+
return res.status(404).json({ error: 'Collection not found' });
|
|
35
|
+
res.json({
|
|
36
|
+
...collection,
|
|
37
|
+
refCount: collections.countRefs(collection.id),
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
// PATCH /collections/:id
|
|
41
|
+
router.patch('/:id', (req, res) => {
|
|
42
|
+
const collections = new db_1.CollectionQueries();
|
|
43
|
+
const { name, description } = req.body;
|
|
44
|
+
const updated = collections.update(String(req.params.id), { name, description });
|
|
45
|
+
if (!updated)
|
|
46
|
+
return res.status(404).json({ error: 'Collection not found' });
|
|
47
|
+
res.json({
|
|
48
|
+
...updated,
|
|
49
|
+
refCount: collections.countRefs(updated.id),
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
// DELETE /collections/:id
|
|
53
|
+
router.delete('/:id', (req, res) => {
|
|
54
|
+
const collections = new db_1.CollectionQueries();
|
|
55
|
+
const deleted = collections.delete(String(req.params.id));
|
|
56
|
+
if (!deleted)
|
|
57
|
+
return res.status(404).json({ error: 'Collection not found' });
|
|
58
|
+
res.status(204).send();
|
|
59
|
+
});
|
|
60
|
+
// GET /collections/:id/refs
|
|
61
|
+
router.get('/:id/refs', (req, res) => {
|
|
62
|
+
const collections = new db_1.CollectionQueries();
|
|
63
|
+
const collection = collections.get(String(req.params.id));
|
|
64
|
+
if (!collection)
|
|
65
|
+
return res.status(404).json({ error: 'Collection not found' });
|
|
66
|
+
res.json(collections.listRefs(collection.id));
|
|
67
|
+
});
|
|
68
|
+
exports.default = router;
|
|
69
|
+
//# sourceMappingURL=collections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.js","sourceRoot":"","sources":["../../src/api/collections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"favorites.d.ts","sourceRoot":"","sources":["../../src/api/favorites.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA8CxB,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const express_1 = require("express");
|
|
4
|
+
const db_1 = require("../db");
|
|
5
|
+
const router = (0, express_1.Router)();
|
|
6
|
+
// GET /favorites — list all favorites
|
|
7
|
+
router.get('/', (_req, res) => {
|
|
8
|
+
const favorites = new db_1.FavoriteQueries();
|
|
9
|
+
res.json(favorites.list());
|
|
10
|
+
});
|
|
11
|
+
// GET /favorites/ids — return array of "refId:beaconId" strings for quick card overlay
|
|
12
|
+
router.get('/ids', (_req, res) => {
|
|
13
|
+
const favorites = new db_1.FavoriteQueries();
|
|
14
|
+
res.json(favorites.listKeys());
|
|
15
|
+
});
|
|
16
|
+
// POST /favorites/toggle — toggle favorite on/off
|
|
17
|
+
router.post('/toggle', (req, res) => {
|
|
18
|
+
const favorites = new db_1.FavoriteQueries();
|
|
19
|
+
const { refId, refName, beaconId, offerPrice, offerCurrency, listingStatus, category, subcategory, locationCity, locationState, locationZip, imageUrl } = req.body;
|
|
20
|
+
if (!refId || typeof refId !== 'string') {
|
|
21
|
+
return res.status(400).json({ error: 'refId is required' });
|
|
22
|
+
}
|
|
23
|
+
if (!beaconId || typeof beaconId !== 'string') {
|
|
24
|
+
return res.status(400).json({ error: 'beaconId is required' });
|
|
25
|
+
}
|
|
26
|
+
const result = favorites.toggle({ refId, refName, beaconId, offerPrice, offerCurrency, listingStatus, category, subcategory, locationCity, locationState, locationZip, imageUrl });
|
|
27
|
+
res.json(result);
|
|
28
|
+
});
|
|
29
|
+
// DELETE /favorites — remove by refId + beaconId
|
|
30
|
+
router.delete('/', (req, res) => {
|
|
31
|
+
const favorites = new db_1.FavoriteQueries();
|
|
32
|
+
const { refId, beaconId } = req.body;
|
|
33
|
+
if (!refId || typeof refId !== 'string') {
|
|
34
|
+
return res.status(400).json({ error: 'refId is required' });
|
|
35
|
+
}
|
|
36
|
+
if (!beaconId || typeof beaconId !== 'string') {
|
|
37
|
+
return res.status(400).json({ error: 'beaconId is required' });
|
|
38
|
+
}
|
|
39
|
+
const removed = favorites.remove(refId, beaconId);
|
|
40
|
+
res.json({ removed });
|
|
41
|
+
});
|
|
42
|
+
exports.default = router;
|
|
43
|
+
//# sourceMappingURL=favorites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"favorites.js","sourceRoot":"","sources":["../../src/api/favorites.ts"],"names":[],"mappings":";;AAAA,qCAAoD;AACpD,8BAAwC;AAExC,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,sCAAsC;AACtC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IAC/C,MAAM,SAAS,GAAG,IAAI,oBAAe,EAAE,CAAC;IACxC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEH,uFAAuF;AACvF,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IAClD,MAAM,SAAS,GAAG,IAAI,oBAAe,EAAE,CAAC;IACxC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AAEH,kDAAkD;AAClD,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACrD,MAAM,SAAS,GAAG,IAAI,oBAAe,EAAE,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;IAEnK,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnL,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEH,iDAAiD;AACjD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACjD,MAAM,SAAS,GAAG,IAAI,oBAAe,EAAE,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;IAErC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAClD,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AACxB,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const router: import("express-serve-static-core").Router;
|
|
2
|
+
export declare function setBeaconId(id: string): void;
|
|
3
|
+
export declare function setDhtStatus(status: {
|
|
4
|
+
connected: boolean;
|
|
5
|
+
peers: number;
|
|
6
|
+
}): void;
|
|
7
|
+
export declare function setUpdateInfo(info: {
|
|
8
|
+
available: boolean;
|
|
9
|
+
version: string | null;
|
|
10
|
+
}): void;
|
|
11
|
+
export default router;
|
|
12
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/api/health.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAOxB,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAEhF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAExF;AAqCD,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setBeaconId = setBeaconId;
|
|
4
|
+
exports.setDhtStatus = setDhtStatus;
|
|
5
|
+
exports.setUpdateInfo = setUpdateInfo;
|
|
6
|
+
const express_1 = require("express");
|
|
7
|
+
const db_1 = require("../db");
|
|
8
|
+
const version_1 = require("../version");
|
|
9
|
+
const router = (0, express_1.Router)();
|
|
10
|
+
const startTime = Date.now();
|
|
11
|
+
let beaconId = '';
|
|
12
|
+
let dhtStatus = { connected: false, peers: 0 };
|
|
13
|
+
let updateInfo = { available: false, version: null };
|
|
14
|
+
function setBeaconId(id) {
|
|
15
|
+
beaconId = id;
|
|
16
|
+
}
|
|
17
|
+
function setDhtStatus(status) {
|
|
18
|
+
dhtStatus = status;
|
|
19
|
+
}
|
|
20
|
+
function setUpdateInfo(info) {
|
|
21
|
+
updateInfo = info;
|
|
22
|
+
}
|
|
23
|
+
router.get('/dashboard', (_req, res) => {
|
|
24
|
+
const refs = new db_1.RefQueries();
|
|
25
|
+
const offers = new db_1.OfferQueries();
|
|
26
|
+
const negotiations = new db_1.NegotiationQueries();
|
|
27
|
+
const favorites = new db_1.FavoriteQueries();
|
|
28
|
+
res.json({
|
|
29
|
+
totalListed: refs.count(),
|
|
30
|
+
activeOffers: offers.countActive(),
|
|
31
|
+
pendingNegotiations: negotiations.countPending(),
|
|
32
|
+
favoritesCount: favorites.count(),
|
|
33
|
+
archivedCount: refs.listArchived().length,
|
|
34
|
+
recentItems: refs.list().slice(0, 6),
|
|
35
|
+
recentOffers: offers.list().slice(0, 3),
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
router.get('/', (_req, res) => {
|
|
39
|
+
const refs = new db_1.RefQueries();
|
|
40
|
+
const offers = new db_1.OfferQueries();
|
|
41
|
+
const info = {
|
|
42
|
+
id: beaconId,
|
|
43
|
+
version: (0, version_1.getVersion)(),
|
|
44
|
+
refCount: refs.count(),
|
|
45
|
+
offerCount: offers.countActive(),
|
|
46
|
+
uptime: Math.floor((Date.now() - startTime) / 1000),
|
|
47
|
+
dht: dhtStatus,
|
|
48
|
+
updateAvailable: updateInfo.available,
|
|
49
|
+
latestVersion: updateInfo.version,
|
|
50
|
+
};
|
|
51
|
+
res.json(info);
|
|
52
|
+
});
|
|
53
|
+
exports.default = router;
|
|
54
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/api/health.ts"],"names":[],"mappings":";;AAYA,kCAEC;AAED,oCAEC;AAED,sCAEC;AAtBD,qCAAoD;AACpD,8BAAsF;AAEtF,wCAAwC;AAExC,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AACxB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE7B,IAAI,QAAQ,GAAG,EAAE,CAAC;AAClB,IAAI,SAAS,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAC/C,IAAI,UAAU,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAqB,EAAE,CAAC;AAEtE,SAAgB,WAAW,CAAC,EAAU;IACpC,QAAQ,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,SAAgB,YAAY,CAAC,MAA6C;IACxE,SAAS,GAAG,MAAM,CAAC;AACrB,CAAC;AAED,SAAgB,aAAa,CAAC,IAAoD;IAChF,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IACxD,MAAM,IAAI,GAAG,IAAI,eAAU,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,iBAAY,EAAE,CAAC;IAClC,MAAM,YAAY,GAAG,IAAI,uBAAkB,EAAE,CAAC;IAC9C,MAAM,SAAS,GAAG,IAAI,oBAAe,EAAE,CAAC;IAExC,GAAG,CAAC,IAAI,CAAC;QACP,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE;QACzB,YAAY,EAAE,MAAM,CAAC,WAAW,EAAE;QAClC,mBAAmB,EAAE,YAAY,CAAC,YAAY,EAAE;QAChD,cAAc,EAAE,SAAS,CAAC,KAAK,EAAE;QACjC,aAAa,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM;QACzC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACpC,YAAY,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;KACxC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IAC/C,MAAM,IAAI,GAAG,IAAI,eAAU,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,iBAAY,EAAE,CAAC;IAElC,MAAM,IAAI,GAA4E;QACpF,EAAE,EAAE,QAAQ;QACZ,OAAO,EAAE,IAAA,oBAAU,GAAE;QACrB,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE;QACtB,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE;QAChC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;QACnD,GAAG,EAAE,SAAS;QACd,eAAe,EAAE,UAAU,CAAC,SAAS;QACrC,aAAa,EAAE,UAAU,CAAC,OAAO;KAClC,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAc9B,wBAAgB,SAAS,IAAI,OAAO,CAAC,OAAO,CA4C3C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createApp = createApp;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const health_1 = __importDefault(require("./health"));
|
|
10
|
+
const refs_1 = __importDefault(require("./refs"));
|
|
11
|
+
const offers_1 = __importDefault(require("./offers"));
|
|
12
|
+
const media_1 = __importDefault(require("./media"));
|
|
13
|
+
const negotiations_1 = __importDefault(require("./negotiations"));
|
|
14
|
+
const settings_1 = __importDefault(require("./settings"));
|
|
15
|
+
const favorites_1 = __importDefault(require("./favorites"));
|
|
16
|
+
const collections_1 = __importDefault(require("./collections"));
|
|
17
|
+
const scans_1 = __importDefault(require("./scans"));
|
|
18
|
+
const ui_1 = require("../ui");
|
|
19
|
+
const taxonomy_1 = require("../taxonomy");
|
|
20
|
+
function createApp() {
|
|
21
|
+
const app = (0, express_1.default)();
|
|
22
|
+
app.use(express_1.default.json());
|
|
23
|
+
// Allow cross-origin requests (so browsers can fetch media from peer beacons)
|
|
24
|
+
app.use((_req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); next(); });
|
|
25
|
+
// Serve uploaded media files
|
|
26
|
+
app.use('/uploads', express_1.default.static(path_1.default.join(process.cwd(), 'uploads')));
|
|
27
|
+
// Serve brand assets (favicon.ico, beacon.png, footer_bolt.png)
|
|
28
|
+
app.get('/favicon.ico', (_req, res) => { res.type('image/x-icon').sendFile(path_1.default.join(__dirname, '../../favicon.ico')); });
|
|
29
|
+
app.get('/beacon.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../beacon.png')); });
|
|
30
|
+
app.get('/footer_bolt.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../footer_bolt.png')); });
|
|
31
|
+
app.get('/header-brand.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../header-brand.png')); });
|
|
32
|
+
app.get('/footer-brand.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../footer-brand.png')); });
|
|
33
|
+
app.get('/', (_req, res) => {
|
|
34
|
+
res.type('html').send((0, ui_1.renderUI)());
|
|
35
|
+
});
|
|
36
|
+
app.get('/taxonomy', (_req, res) => {
|
|
37
|
+
res.json(taxonomy_1.TAXONOMY);
|
|
38
|
+
});
|
|
39
|
+
app.use('/health', health_1.default);
|
|
40
|
+
app.use('/refs', refs_1.default);
|
|
41
|
+
app.use('/refs/:refId/media', media_1.default);
|
|
42
|
+
app.use('/offers', offers_1.default);
|
|
43
|
+
app.use('/negotiations', negotiations_1.default);
|
|
44
|
+
app.use('/settings', settings_1.default);
|
|
45
|
+
app.use('/favorites', favorites_1.default);
|
|
46
|
+
app.use('/collections', collections_1.default);
|
|
47
|
+
app.use('/scans', scans_1.default);
|
|
48
|
+
// Global error handler — catches multer errors, etc., and returns JSON instead of HTML
|
|
49
|
+
app.use((err, _req, res, _next) => {
|
|
50
|
+
console.error('[API] Error:', err.message);
|
|
51
|
+
const status = err.status || err.statusCode || 500;
|
|
52
|
+
res.status(status).json({ error: err.message });
|
|
53
|
+
});
|
|
54
|
+
return app;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"items.d.ts","sourceRoot":"","sources":["../../src/api/items.ts"],"names":[],"mappings":"AASA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA+LxB,eAAe,MAAM,CAAC"}
|