u
This commit is contained in:
@@ -132,6 +132,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/quote/delete.md`](routes/quote/delete.md) | `DELETE /quote/{id}` |
|
||||
| [`routes/quote/get.md`](routes/quote/get.md) | `GET /quote/{id}` |
|
||||
| [`routes/quote/update.md`](routes/quote/update.md) | `PATCH /quote/{id}` |
|
||||
| [`routes/serper/images.md`](routes/serper/images.md) | `POST /serper/images` |
|
||||
| [`routes/stock/adjust.md`](routes/stock/adjust.md) | `POST /stock/adjust` |
|
||||
| [`routes/supplier/list.md`](routes/supplier/list.md) | `GET /supplier` |
|
||||
| [`routes/supplier/create.md`](routes/supplier/create.md) | `POST /supplier` |
|
||||
|
||||
@@ -91,6 +91,10 @@
|
||||
{
|
||||
"name": "Stock",
|
||||
"description": "Manual stock additions and removals"
|
||||
},
|
||||
{
|
||||
"name": "Serper",
|
||||
"description": "Serper Google image search and thumbnail streaming"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
@@ -986,6 +990,142 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/serper/images": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Serper"
|
||||
],
|
||||
"summary": "Search images via Serper.dev and stream WebP thumbnails (SSE)",
|
||||
"description": "Queries Google Image search via `https://google.serper.dev/images` using the\ncompany setting `keys.serper` (or server `SERPER_API_KEY`), and streams the\nresults via Server-Sent Events (`text/event-stream`).\n\n1. First emits an `images` event with the full search result list (including `imageUrl`).\n2. Then streams `thumb` events with WebP base64 thumbnails (max 200×200) as they are generated.\n3. Emits `done` when all thumbnails have completed (or `error` on failure).\n",
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
}
|
||||
],
|
||||
"x-markdown": "serper/images.md",
|
||||
"x-sse-events": [
|
||||
{
|
||||
"name": "images",
|
||||
"description": "First event; list of search result images with id, url, width, and height",
|
||||
"payload": "{ \"images\": [ { \"id\": 0, \"url\": \"…\", \"width\": 1000, \"height\": 800 } ] }"
|
||||
},
|
||||
{
|
||||
"name": "thumb",
|
||||
"description": "Emitted for each image as its 200×200 max WebP thumbnail is generated",
|
||||
"payload": "{ \"id\": 0, \"dataUrl\": \"data:image/webp;base64,…\" }"
|
||||
},
|
||||
{
|
||||
"name": "done",
|
||||
"description": "Emitted after all thumbnails have finished streaming; closes the SSE stream",
|
||||
"payload": "{ \"total\": 100 }"
|
||||
},
|
||||
{
|
||||
"name": "error",
|
||||
"description": "Emitted when an error occurs during Serper request or processing",
|
||||
"payload": "{ \"error\": \"…\" }"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"q"
|
||||
],
|
||||
"properties": {
|
||||
"q": {
|
||||
"type": "string",
|
||||
"description": "Image search query (e.g. \"Purize logo\")"
|
||||
},
|
||||
"gl": {
|
||||
"type": "string",
|
||||
"default": "de",
|
||||
"description": "Country code"
|
||||
},
|
||||
"hl": {
|
||||
"type": "string",
|
||||
"default": "de",
|
||||
"description": "Language code"
|
||||
},
|
||||
"num": {
|
||||
"type": "integer",
|
||||
"default": 100,
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"description": "Number of search results to fetch"
|
||||
},
|
||||
"preferSource": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether to prefer downloading from the full imageUrl before falling back to Google thumbnailUrl"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"q": "Purize logo",
|
||||
"gl": "de",
|
||||
"hl": "de",
|
||||
"num": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "`text/event-stream` — emits `images`, `thumb`, `done` (and `error` on failure).\n",
|
||||
"content": {
|
||||
"text/event-stream": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Query missing, invalid input, or Serper API key not configured",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not authorized",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Company not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/quote": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -6617,7 +6757,7 @@
|
||||
"CompanySetting"
|
||||
],
|
||||
"summary": "Upsert company setting",
|
||||
"description": "Sets (upserts) a company setting for the selected company.\nOnly a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`,\n`keys.openrouter`, `labelprinter.addr`, `labelprinter.type`.\n",
|
||||
"description": "Sets (upserts) a company setting for the selected company.\nOnly a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`,\n`keys.openrouter`, `keys.serper`, `labelprinter.addr`, `labelprinter.type`.\n",
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
@@ -10834,11 +10974,43 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"BrandPic": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"sort",
|
||||
"fullHash",
|
||||
"thumbW",
|
||||
"thumbH",
|
||||
"thumbHash"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sort": {
|
||||
"type": "integer"
|
||||
},
|
||||
"fullHash": {
|
||||
"type": "string"
|
||||
},
|
||||
"thumbW": {
|
||||
"type": "integer"
|
||||
},
|
||||
"thumbH": {
|
||||
"type": "integer"
|
||||
},
|
||||
"thumbHash": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Brand": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"name"
|
||||
"name",
|
||||
"pics"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -10850,6 +11022,13 @@
|
||||
"gsprpinfo": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"pics": {
|
||||
"type": "array",
|
||||
"description": "Brand pictures sorted by sort",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/BrandPic"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -16,7 +16,17 @@ Brand list
|
||||
{
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"gsprpinfo": "…"
|
||||
"gsprpinfo": "…",
|
||||
"pics": [
|
||||
{
|
||||
"id": 1,
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -25,7 +25,17 @@ Upserted brand
|
||||
"brand": {
|
||||
"id": 1,
|
||||
"name": "…",
|
||||
"gsprpinfo": "…"
|
||||
"gsprpinfo": "…",
|
||||
"pics": [
|
||||
{
|
||||
"id": 1,
|
||||
"sort": 1,
|
||||
"fullHash": "…",
|
||||
"thumbW": 1,
|
||||
"thumbH": 1,
|
||||
"thumbHash": "…"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -6,7 +6,7 @@ Upsert company setting
|
||||
|
||||
Sets (upserts) a company setting for the selected company.
|
||||
Only a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`,
|
||||
`keys.openrouter`, `labelprinter.addr`, `labelprinter.type`.
|
||||
`keys.openrouter`, `keys.serper`, `labelprinter.addr`, `labelprinter.type`.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
54
docs/api/routes/serper/images.md
Normal file
54
docs/api/routes/serper/images.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# `POST /serper/images`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Search images via Serper.dev and stream WebP thumbnails (SSE)
|
||||
|
||||
Queries Google Image search via `https://google.serper.dev/images` using the
|
||||
company setting `keys.serper` (or server `SERPER_API_KEY`), and streams the
|
||||
results via Server-Sent Events (`text/event-stream`).
|
||||
|
||||
1. First emits an `images` event with the full search result list (including `imageUrl`).
|
||||
2. Then streams `thumb` events with WebP base64 thumbnails (max 200×200) as they are generated.
|
||||
3. Emits `done` when all thumbnails have completed (or `error` on failure).
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
```json
|
||||
{
|
||||
"q": "Purize logo",
|
||||
"gl": "de",
|
||||
"hl": "de",
|
||||
"num": 100
|
||||
}
|
||||
```
|
||||
|
||||
## SSE Events
|
||||
|
||||
The response is a `text/event-stream`. Events are emitted in order until the stream closes.
|
||||
|
||||
| Event | Description | Payload |
|
||||
|-------|-------------|---------|
|
||||
| `images` | First event; list of search result images with id, url, width, and height | `{ "images": [ { "id": 0, "url": "…", "width": 1000, "height": 800 } ] }` |
|
||||
| `thumb` | Emitted for each image as its 200×200 max WebP thumbnail is generated | `{ "id": 0, "dataUrl": "data:image/webp;base64,…" }` |
|
||||
| `done` | Emitted after all thumbnails have finished streaming; closes the SSE stream | `{ "total": 100 }` |
|
||||
| `error` | Emitted when an error occurs during Serper request or processing | `{ "error": "…" }` |
|
||||
|
||||
## Response `200`
|
||||
|
||||
`text/event-stream` — emits `images`, `thumb`, `done` (and `error` on failure).
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Query missing, invalid input, or Serper API key not configured — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Company not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
Reference in New Issue
Block a user