This commit is contained in:
seb
2026-10-23 22:22:30 +02:00
parent e83116c83d
commit 1a5e3f23e2
6 changed files with 141 additions and 69 deletions

View File

@@ -126,8 +126,8 @@ _none_
- Params: `sku: str, body: { eans: str[] }` - Params: `sku: str, body: { eans: str[] }`
- Returns: `204 void` - Returns: `204 void`
#### Get article history by SKU — `GET /article/{sku}/history` #### Get article history by SKU — `GET /article/{sku}/history`
- Params: `sku: str, query: limit?: int` - Params: `sku: str, query: offset?: int, limit?: int, search?: str, seekMonths?: int`
- Returns: `200 { history: { id: int, date: str, text: str }[], truncated: bool }` - Returns: `200 { history: { id: int, date: str, text: str }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
#### Add article image — `POST /article/{sku}/image` #### Add article image — `POST /article/{sku}/image`
- Params: `sku: str, image/avif` - Params: `sku: str, image/avif`
- Returns: `201 { image: { picId: int, sort: int, full: { w: int, h: int, size: int }, thumb: { w: int, h: int }, hash: str, thumbHash: str } }` - Returns: `201 { image: { picId: int, sort: int, full: { w: int, h: int, size: int }, thumb: { w: int, h: int }, hash: str, thumbHash: str } }`

View File

@@ -92,8 +92,8 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body).
- Params: `sku: str, body: { eans: str[] }` - Params: `sku: str, body: { eans: str[] }`
- Returns: `204 void` - Returns: `204 void`
#### Get article history by SKU — `GET /article/{sku}/history` #### Get article history by SKU — `GET /article/{sku}/history`
- Params: `sku: str, query: limit?: int` - Params: `sku: str, query: offset?: int, limit?: int, search?: str, seekMonths?: int`
- Returns: `200 { history: { id: int, date: str, text: str }[], truncated: bool }` - Returns: `200 { history: { id: int, date: str, text: str }[], total: int, unfilteredTotal: int, offset: int, limit: int }`
#### Delete article image — `DELETE /article/{sku}/image/{fullHash}` #### Delete article image — `DELETE /article/{sku}/image/{fullHash}`
- Params: `sku: str, fullHash: str` - Params: `sku: str, fullHash: str`
- Returns: `204 void` - Returns: `204 void`

View File

@@ -5,6 +5,7 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
Get article history by SKU Get article history by SKU
Returns `articlehistory` rows for the article, newest first (`date` DESC, `id` DESC). Returns `articlehistory` rows for the article, newest first (`date` DESC, `id` DESC).
Supports pagination, search filter, and date cutoff via `seekMonths`.
Auth like GET by SKU. Auth like GET by SKU.
@@ -18,11 +19,14 @@ Auth like GET by SKU.
| Param | Required | Type | Description | | Param | Required | Type | Description |
|-------|----------|------|-------------| |-------|----------|------|-------------|
| `limit` | no | integer | Maximum number of entries to return (newest first). Omit for all entries. | | `offset` | no | integer | Paging offset |
| `limit` | no | integer | Page size |
| `search` | no | string | Optional search filter for history text |
| `seekMonths` | no | integer | Negative integer cutoff months ago (e.g. -13) |
## Response `200` ## Response `200`
Article history (newest first) Paged article history list
```json ```json
{ {
@@ -37,7 +41,11 @@ Article history (newest first)
"date": "2026-08-01T09:00:00.000Z", "date": "2026-08-01T09:00:00.000Z",
"text": "Name geändert von \"\" auf \"Tee\"" "text": "Name geändert von \"\" auf \"Tee\""
} }
] ],
"total": 2,
"unfilteredTotal": 2,
"offset": 0,
"limit": 50
} }
``` ```
@@ -45,7 +53,7 @@ Article history (newest first)
| Status | Description | | Status | Description |
|--------|-------------| |--------|-------------|
| 400 | Missing sku — `{"error":"…"}` | | 400 | Missing sku or invalid query parameters — `{"error":"…"}` |
| 401 | Unauthorized — `{"error":"…"}` | | 401 | Unauthorized — `{"error":"…"}` |
| 403 | Not authorized — `{"error":"…"}` | | 403 | Not authorized — `{"error":"…"}` |
| 404 | Article not found — `{"error":"…"}` | | 404 | Article not found — `{"error":"…"}` |

104
package-lock.json generated
View File

@@ -32,7 +32,7 @@
"react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor", "react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor",
"selfsigned": "^5.5.0", "selfsigned": "^5.5.0",
"sharp": "^0.35.5", "sharp": "^0.35.5",
"skelehash-wasm": "^0.1.0", "skelehash-wasm": "file:../skelehash-wasm",
"swagger-ui-dist": "^5.33.3", "swagger-ui-dist": "^5.33.3",
"vm2": "^3.12.2", "vm2": "^3.12.2",
"zod": "^4.6.7" "zod": "^4.6.7"
@@ -72,6 +72,7 @@
} }
}, },
"../llmorbiter": { "../llmorbiter": {
"name": "llmorbiter",
"version": "0.1.0", "version": "0.1.0",
"license": "0BSD", "license": "0BSD",
"dependencies": { "dependencies": {
@@ -81,6 +82,13 @@
"node": ">=18.0.0" "node": ">=18.0.0"
} }
}, },
"../skelehash-wasm": {
"version": "0.1.0",
"license": "MIT",
"devDependencies": {
"sharp": "^0.35.5"
}
},
"node_modules/@alcalzone/ansi-tokenize": { "node_modules/@alcalzone/ansi-tokenize": {
"version": "0.3.1", "version": "0.3.1",
"resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.3.1.tgz", "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.3.1.tgz",
@@ -216,9 +224,9 @@
} }
}, },
"node_modules/@hpcc-js/wasm-graphviz": { "node_modules/@hpcc-js/wasm-graphviz": {
"version": "1.29.2", "version": "1.30.0",
"resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.29.2.tgz", "resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.30.0.tgz",
"integrity": "sha512-AkArBAZERT5OxH52/+kvCHB07cZ6ZNd9GnOvjw+S880bR88D6i27XfK6xj4dBhUDxNA2QPPMdgEcky3x4TJ3KA==", "integrity": "sha512-T20IKosOZuex2qV049fQokVJy2MWv8w9Md5V/4mRKCXDf49fBCR50VD1yBlPYHaQlHPsFGRdqXN//r59vZliWQ==",
"dev": true, "dev": true,
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
@@ -787,9 +795,9 @@
} }
}, },
"node_modules/@modelcontextprotocol/sdk": { "node_modules/@modelcontextprotocol/sdk": {
"version": "1.32.1", "version": "1.32.2",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.32.1.tgz", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.32.2.tgz",
"integrity": "sha512-2DdE+SJDtzLEEWzY1ZjY7Q+VcPhcV1KisD3zI4u0XZyktsjHum1mwbMI+JaulUBi2OZk+KJAi2uPXzxichPkdw==", "integrity": "sha512-SWsVtH/0vULSQStoZ6xxH2K09Li8fXYTMC64ZeogCdpZ3XSi1eCPOByV1OpuJxuI3OcmHhosDWYyii07tpPsLw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@hono/node-server": "^1.19.9 || ^2.0.5", "@hono/node-server": "^1.19.9 || ^2.0.5",
@@ -1467,18 +1475,18 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "2.3.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.4.0.tgz",
"integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "integrity": "sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bytes": "^3.1.2", "bytes": "^3.1.2",
"content-type": "^2.0.0", "content-type": "^2.1.0",
"debug": "^4.4.3", "debug": "^4.4.3",
"http-errors": "^2.0.1", "http-errors": "^2.0.1",
"iconv-lite": "^0.7.2", "iconv-lite": "^0.7.3",
"on-finished": "^2.4.1", "on-finished": "^2.4.1",
"qs": "^6.15.2", "qs": "^6.16.1",
"raw-body": "^3.0.2", "raw-body": "^3.0.2",
"type-is": "^2.1.0" "type-is": "^2.1.0"
}, },
@@ -2267,9 +2275,9 @@
} }
}, },
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "18.0.8", "version": "18.0.9",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.8.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.9.tgz",
"integrity": "sha512-2KDeoFoK/zRtcnbunCDlLG5VWVMcyqeQc6iK65o231nfNAcuGrKoqUQfJFUtBI+QlShk5HKIHxwebBtUl3rEfA==", "integrity": "sha512-3fVOW4cB02R066PUSwn8O4TJyz9NckQl7F81blIbaq9jKBm2tSmOKky7ZHIXzGvkVPXCSn6jkpziBPZdGFs8Tw==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"bin": { "bin": {
"dotenv": "dist/index.cjs" "dotenv": "dist/index.cjs"
@@ -2748,9 +2756,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-uri": { "node_modules/fast-uri": {
"version": "3.1.8", "version": "3.1.9",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz",
"integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -2988,9 +2996,9 @@
} }
}, },
"node_modules/gaxios": { "node_modules/gaxios": {
"version": "8.3.1", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-8.3.1.tgz", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-8.3.2.tgz",
"integrity": "sha512-h4/R7ay7JFXU5kmAkp/Y4Y4Vmm7m83tD579GUgfQQsRRGQ4TzSedyHla6XgTWohQuVffT3ldN4FF6uCqlRGaEA==", "integrity": "sha512-7VsaTExxjbDv2ZK1YuC4jbgfN33NI/6/7zdYWUHB6mcg51v4tCBZe+xzjqPzOpVzI+C5k1Kk9OQ80WVrXAHOqw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"extend": "^3.0.2", "extend": "^3.0.2",
@@ -3002,9 +3010,9 @@
} }
}, },
"node_modules/gcp-metadata": { "node_modules/gcp-metadata": {
"version": "9.2.1", "version": "9.2.2",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-9.2.1.tgz", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-9.2.2.tgz",
"integrity": "sha512-5/LvxarRKbGCA5LJ+ha2aV1iVm7/aALIW4PzeXnQR5dyXiNMWbeA4UOBnqERInLfH/xSFp0ZREcxodUzxhEw2Q==", "integrity": "sha512-hlaHpCBoNCzoUjMnBZq0LbUiYqPAhXFaAgyNwQqwWU44TZIYJK3RD3o2wkNdvPs8nnUXqJjTudnodLJkLMBjow==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"gaxios": "^8.3.0", "gaxios": "^8.3.0",
@@ -3926,9 +3934,9 @@
} }
}, },
"node_modules/jose": { "node_modules/jose": {
"version": "6.2.12", "version": "6.2.13",
"resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.13.tgz",
"integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", "integrity": "sha512-7TIg10ZE1x82YediN+lcrPNvGMKge9yFHQD+Qho/b8y2adfugU3AsvvHfxV0fzyFllT6l9xCjf4RWY9g/Z9PJQ==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/panva" "url": "https://github.com/sponsors/panva"
@@ -4439,9 +4447,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/multer": { "node_modules/multer": {
"version": "2.4.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.4.0.tgz", "resolved": "https://registry.npmjs.org/multer/-/multer-2.5.0.tgz",
"integrity": "sha512-7dqa0ZcFfzbefdTuIkzOSMvZWC0J7FLqBOjJUZvDCXShIURWKxAyTT1wHhnE5q19c7jOJf43IYYKjBmZVZmvhg==", "integrity": "sha512-BsqOzYGVq49JcW2IzoSAxeKYRevb+dGGPPWleOR8Lrlk4igwxu1/9pwSXlByhCb7MVZDrNJFC0IBP5/O5nLYRw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"append-field": "^1.0.0", "append-field": "^1.0.0",
@@ -4535,9 +4543,9 @@
} }
}, },
"node_modules/node-abi": { "node_modules/node-abi": {
"version": "3.99.0", "version": "3.101.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.99.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.101.0.tgz",
"integrity": "sha512-lLdwkeg2XUVPTHqWjPltTxH81zbQNbUWC+AEb9ni50KjxkUzAAx1HGtMT21sbntzfUGfIphhcklvs3imJeqDXw==", "integrity": "sha512-bkb/RkuWCE64eWu1PCh3Fu2pGc9mKRs+kOE+FU2bGHRYlQa86/D321DSATV54AsCQMKz3/xSt9sRgraZTpqdhQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"semver": "^7.3.5" "semver": "^7.3.5"
@@ -4653,15 +4661,19 @@
} }
}, },
"node_modules/on-finished": { "node_modules/on-finished": {
"version": "2.4.1", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.2.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "integrity": "sha512-ATWUv387i+nLD49EiDoOft5scf32Vsdz3ktrQJG9bi7jRFmaXTssvyvj1EmeKVVgvesbqUtvQQvaS2TpTukAZQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ee-first": "1.1.1" "ee-first": "1.1.1"
}, },
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
} }
}, },
"node_modules/once": { "node_modules/once": {
@@ -4865,9 +4877,9 @@
} }
}, },
"node_modules/pkijs": { "node_modules/pkijs": {
"version": "3.4.1", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.1.tgz", "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.3.tgz",
"integrity": "sha512-Oo/NZcSWccq8KyoG7gLE9fnltgHns+pNCjCAp/WmjsUySi+sX7y4z4Xqu4fVb42CDHzRPl33fjzT15V1wvcyhA==", "integrity": "sha512-V9kOzaItwDgqlryhXysQsAXUEKi5O7kqWUaP3dXI7MLvkPqWWMb4wVb1QAtmEDCKI+XIAINsZoNKMFF7sZb1eg==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"workspaces": [ "workspaces": [
"website" "website"
@@ -5727,10 +5739,8 @@
} }
}, },
"node_modules/skelehash-wasm": { "node_modules/skelehash-wasm": {
"version": "0.1.0", "resolved": "../skelehash-wasm",
"resolved": "https://registry.npmjs.org/skelehash-wasm/-/skelehash-wasm-0.1.0.tgz", "link": true
"integrity": "sha512-QdxF9YsJvKlT93O70dXFaWnsKVX7KDD0RgYf9cwgOT6kGnSMOdsO0rsdge+5Tg+vv6BjivbJ/2o5P1KcQsavEw==",
"license": "MIT"
}, },
"node_modules/slice-ansi": { "node_modules/slice-ansi": {
"version": "9.0.1", "version": "9.0.1",
@@ -6000,9 +6010,9 @@
} }
}, },
"node_modules/swagger-ui-dist": { "node_modules/swagger-ui-dist": {
"version": "5.33.3", "version": "5.34.0",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.33.3.tgz", "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.34.0.tgz",
"integrity": "sha512-7xJKxAjf+/ajlW/V/dMfbiY+NC5BWtbvzzdI/AsX5UzMtOMudmFz/tjuKN0jN7QVe5drKKnx01CdYEJvTFvQlw==", "integrity": "sha512-H6tAIjr3XqE31PbkZl0OFya1ziRLDfTwh3J6OHdumPtPCLfjTnyLeagl/55kFNZcTOz9a9QI9WP0FXldwiGJag==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@scarf/scarf": "=1.4.0" "@scarf/scarf": "=1.4.0"

View File

@@ -40,7 +40,7 @@
"react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor", "react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor",
"selfsigned": "^5.5.0", "selfsigned": "^5.5.0",
"sharp": "^0.35.5", "sharp": "^0.35.5",
"skelehash-wasm": "^0.1.0", "skelehash-wasm": "file:../skelehash-wasm",
"swagger-ui-dist": "^5.33.3", "swagger-ui-dist": "^5.33.3",
"vm2": "^3.12.2", "vm2": "^3.12.2",
"zod": "^4.6.7" "zod": "^4.6.7"
@@ -60,4 +60,4 @@
"uuid": "^11.1.1" "uuid": "^11.1.1"
} }
} }
} }

View File

@@ -602,6 +602,7 @@ export function register(app, basePath = '') {
* summary: Get article history by SKU * summary: Get article history by SKU
* description: | * description: |
* Returns `articlehistory` rows for the article, newest first (`date` DESC, `id` DESC). * Returns `articlehistory` rows for the article, newest first (`date` DESC, `id` DESC).
* Supports pagination, search filter, and date cutoff via `seekMonths`.
* Auth like GET by SKU. * Auth like GET by SKU.
* security: * security:
* - cookieAuth: [] * - cookieAuth: []
@@ -614,29 +615,51 @@ export function register(app, basePath = '') {
* type: string * type: string
* description: Article SKU * description: Article SKU
* - in: query * - in: query
* name: offset
* schema:
* type: integer
* minimum: 0
* default: 0
* description: Paging offset
* - in: query
* name: limit * name: limit
* required: false
* schema: * schema:
* type: integer * type: integer
* minimum: 1 * minimum: 1
* maximum: 1000 * maximum: 1000
* description: Maximum number of entries to return (newest first). Omit for all entries. * default: 50
* description: Page size
* - in: query
* name: search
* schema:
* type: string
* description: Optional search filter for history text
* - in: query
* name: seekMonths
* schema:
* type: integer
* description: Negative integer cutoff months ago (e.g. -13)
* responses: * responses:
* 200: * 200:
* description: Article history (newest first) * description: Paged article history list
* content: * content:
* application/json: * application/json:
* schema: * schema:
* type: object * type: object
* required: [history, truncated] * required: [history, total, unfilteredTotal, offset, limit]
* properties: * properties:
* history: * history:
* type: array * type: array
* items: * items:
* $ref: '#/components/schemas/ArticleHistoryEntry' * $ref: '#/components/schemas/ArticleHistoryEntry'
* truncated: * total:
* type: boolean * type: integer
* description: True when a limit was applied and the result set was exactly that size (more entries may exist). * unfilteredTotal:
* type: integer
* offset:
* type: integer
* limit:
* type: integer
* example: * example:
* history: * history:
* - id: 42 * - id: 42
@@ -645,8 +668,12 @@ export function register(app, basePath = '') {
* - id: 41 * - id: 41
* date: '2026-08-01T09:00:00.000Z' * date: '2026-08-01T09:00:00.000Z'
* text: 'Name geändert von "" auf "Tee"' * text: 'Name geändert von "" auf "Tee"'
* total: 2
* unfilteredTotal: 2
* offset: 0
* limit: 50
* 400: * 400:
* description: Missing sku * description: Missing sku or invalid query parameters
* content: * content:
* application/json: * application/json:
* schema: * schema:
@@ -678,8 +705,19 @@ export function register(app, basePath = '') {
return res.status(400).json({ error: 'sku is required' }); return res.status(400).json({ error: 'sku is required' });
} }
const rawOffset = req.query.offset;
const rawLimit = req.query.limit; const rawLimit = req.query.limit;
let limit = null;
let offset = 0;
let limit = 50;
if (rawOffset !== undefined) {
offset = parseInt(rawOffset, 10);
if (!Number.isInteger(offset) || offset < 0) {
return res.status(400).json({ error: 'offset must be an integer >= 0' });
}
}
if (rawLimit !== undefined) { if (rawLimit !== undefined) {
limit = parseInt(rawLimit, 10); limit = parseInt(rawLimit, 10);
if (!Number.isInteger(limit) || limit < 1 || limit > 1000) { if (!Number.isInteger(limit) || limit < 1 || limit > 1000) {
@@ -687,10 +725,26 @@ export function register(app, basePath = '') {
} }
} }
const search = typeof req.query.search === 'string' && req.query.search.trim() !== ''
? req.query.search.trim()
: undefined;
let seekMonths = undefined;
if (req.query.seekMonths !== undefined) {
seekMonths = parseInt(req.query.seekMonths, 10);
if (!Number.isInteger(seekMonths)) {
return res.status(400).json({ error: 'seekMonths must be an integer' });
}
}
try { try {
const history = await db.getHistoryBySku(req.user.id, decodeURIComponent(sku), limit != null ? { limit } : undefined); const result = await db.getHistoryBySku(req.user.id, decodeURIComponent(sku), {
const truncated = limit != null && history.length === limit; offset,
res.status(200).json({ history, truncated }); limit,
search,
seekMonths,
});
res.status(200).json(result);
} catch (error) { } catch (error) {
const status = articleErrorStatus(error); const status = articleErrorStatus(error);
if (status === 500) console.error('Get article history by sku failed:', error); if (status === 500) console.error('Get article history by sku failed:', error);