u
This commit is contained in:
@@ -207,7 +207,13 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/pos/init.md`](routes/pos/init.md) | `GET /v1/init` |
|
||||
| [`routes/pos/pimage.md`](routes/pos/pimage.md) | `GET /v1/pimage` |
|
||||
| [`routes/v1/product.md`](routes/v1/product.md) | `GET /v1/product` |
|
||||
| [`routes/vfs/list.md`](routes/vfs/list.md) | `GET /vfs` |
|
||||
| [`routes/vfs/mkdir.md`](routes/vfs/mkdir.md) | `POST /vfs/mkdir` |
|
||||
| [`routes/vfs/rename.md`](routes/vfs/rename.md) | `POST /vfs/rename` |
|
||||
| [`routes/vfs/upload.md`](routes/vfs/upload.md) | `POST /vfs/upload` |
|
||||
| [`routes/vfs/delete.md`](routes/vfs/delete.md) | `DELETE /vfs/{*path}` |
|
||||
| [`routes/vfs/_*path.md`](routes/vfs/_*path.md) | `GET /vfs/{*path}` |
|
||||
| [`routes/vfs/write.md`](routes/vfs/write.md) | `PUT /vfs/{*path}` |
|
||||
| [`routes/warehouse/list.md`](routes/warehouse/list.md) | `GET /warehouse` |
|
||||
| [`routes/warehouse/create.md`](routes/warehouse/create.md) | `POST /warehouse` |
|
||||
| [`routes/warehouse/order.md`](routes/warehouse/order.md) | `PUT /warehouse/order` |
|
||||
@@ -227,6 +233,7 @@ Clients subscribe via [`GET /events`](routes/events.md) (`text/event-stream`). A
|
||||
| `article-<sku>` | `PUT /article/{sku}/brand`, `PUT /article/{sku}/categories`, `PUT /article/{sku}/eans`, `POST /article/{sku}/image`, `DELETE /article/{sku}/image/{fullHash}`, `PUT /article/{sku}/images/order`, `PUT /article/{sku}/prices`, `POST /article/{sku}/supplier`, `PUT /article/{sku}/supplier/order`, `DELETE /article/{sku}/supplier/{id}`, `PATCH /article/{sku}/supplier/{id}`, `PUT /article/{sku}/track_stock`, `PUT /article/{sku}/weight` |
|
||||
| `articles` | `POST /article`, `DELETE /article/{sku}`, `PATCH /article/{sku}` |
|
||||
| `category` | `POST /category`, `PUT /category/order`, `DELETE /category/{id}`, `PATCH /category/{id}`, `DELETE /category/{id}/image`, `POST /category/{id}/image` |
|
||||
| `vfs` | `POST /vfs/mkdir`, `POST /vfs/rename`, `POST /vfs/upload`, `DELETE /vfs/{*path}`, `PUT /vfs/{*path}` |
|
||||
|
||||
## DESIGN
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dash API Routes Overview (All)
|
||||
|
||||
Overview of all 183 API endpoints across all modules.
|
||||
Overview of all 189 API endpoints across all modules.
|
||||
|
||||
### Notation
|
||||
|
||||
@@ -575,9 +575,27 @@ _none_
|
||||
#### JTL-POS product catalog synchronization — `GET /v1/product`
|
||||
- Params: `query: lastChangedProduct?: str, limit?: int`
|
||||
- Returns: `200 obj[]`
|
||||
#### List virtual filesystem files — `GET /vfs`
|
||||
_none_
|
||||
- Returns: `200 { files: { name: str, size: int, mime: str, updated_at: str, created_at: str, isText: bool, isImage: bool, isPdf: bool }[] }`
|
||||
#### Create directory in virtual filesystem — `POST /vfs/mkdir`
|
||||
- Params: `body: { path: str }`
|
||||
- Returns: `200 { success: bool, dir: str }`
|
||||
#### Rename or move a virtual filesystem file or directory — `POST /vfs/rename`
|
||||
- Params: `body: { oldPath: str, newPath: str }`
|
||||
- Returns: `200 { success: bool, oldPath: str, newPath: str }`
|
||||
#### Upload files to virtual filesystem — `POST /vfs/upload`
|
||||
- Params: `form: { files: str[], targetDir?: str }`
|
||||
- Returns: `200 { success: bool, uploaded: { name: str, size: int, mime: str }[] }`
|
||||
#### Delete a virtual filesystem file — `DELETE /vfs/{*path}`
|
||||
- Params: `path: str`
|
||||
- Returns: `200 { success: bool, deleted: str }`
|
||||
#### Get a virtual filesystem file — `GET /vfs/{*path}`
|
||||
- Params: `path: str, query: download?: bool, raw?: bool`
|
||||
- Returns: `200 str`
|
||||
#### Create or overwrite a virtual filesystem file — `PUT /vfs/{*path}`
|
||||
- Params: `path: str, body: { content: str, mime?: str }`
|
||||
- Returns: `200 { success: bool, file: { name: str, size: int, mime: str, updated_at: str } }`
|
||||
#### List warehouses — `GET /warehouse`
|
||||
_none_
|
||||
- Returns: `200 { warehouses: T37[] }`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dash API Routes Overview
|
||||
|
||||
Overview of all 146 API endpoints across all modules.
|
||||
Overview of all 145 API endpoints across all modules.
|
||||
|
||||
### Notation
|
||||
|
||||
@@ -460,9 +460,6 @@ _none_
|
||||
#### Upsert unit — `PUT /unit`
|
||||
- Params: `body: { si: str, basesi: str, basesifactor: num, symbol: str, name: str }`
|
||||
- Returns: `200 { unit: { si: str, basesi: str, basesifactor: num, symbol: str, name: str } }`
|
||||
#### Get a virtual filesystem file — `GET /vfs/{*path}`
|
||||
- Params: `path: str, query: download?: bool, raw?: bool`
|
||||
- Returns: `200 str`
|
||||
#### List warehouses — `GET /warehouse`
|
||||
_none_
|
||||
- Returns: `200 { warehouses: T34[] }`
|
||||
|
||||
@@ -4,42 +4,70 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Get a virtual filesystem file
|
||||
|
||||
Returns a file the model produced in the `javascript_execute` sandbox
|
||||
(virtual filesystem), for the authenticated user's selected company.
|
||||
Returns a file from the virtual filesystem for the authenticated user's selected company.
|
||||
Commonly used to retrieve artifacts generated by the model in the `javascript_execute` sandbox or uploaded by users.
|
||||
|
||||
Embed the returned URL in chat markdown to display a generated image:
|
||||
``.
|
||||
### URL Format
|
||||
Accepts:
|
||||
- Relative VFS paths: `example.png`, `reports/summary.pdf`
|
||||
- Full endpoint paths: `/vfs/example.png`, `/api/vfs/example.png` (leading `api/` and `vfs/` prefixes are automatically stripped)
|
||||
- Absolute URLs: `https://.../api/vfs/example.png`
|
||||
- Traversal (`..`), null bytes (`\0`), and backslashes (`\`) are strictly forbidden and rejected with HTTP 400.
|
||||
|
||||
Images are returned as a 250x250 aspect-preserving preview unless requested with
|
||||
`download=1` or `raw=1`.
|
||||
Browser-compatible files (HTML, CSS, JS, JSON, PDF, text, images, media) are served
|
||||
inline so they open directly in the browser; other files are sent as downloads.
|
||||
### Image Previews & Thumbnails
|
||||
Supported raster images (`image/png`, `image/jpeg`, `image/gif`, `image/webp`, `image/avif`, `image/bmp`)
|
||||
are automatically transformed into a **250×250 aspect-preserving preview thumbnail** (WebP format, quality 88):
|
||||
- Scaled to fit within a 250×250 box without distortion (e.g. 2000×100 becomes 250×13).
|
||||
- Images whose larger edge is below 100px are upscaled to 100px for icon legibility.
|
||||
- A translucent dark metadata strip (`#101317`, max 50% height) with monospace text (`DejaVu Sans Mono`)
|
||||
is rendered along the bottom edge, displaying original dimensions and file size.
|
||||
- Served with `Content-Security-Policy: default-src 'none'; sandbox`.
|
||||
- Use `?raw=1` (or `?raw=true`) to bypass preview generation and return the original unmodified image inline.
|
||||
|
||||
### Inline vs Attachment
|
||||
- Browser-compatible types (HTML, CSS, JS, JSON, PDF, text, images, audio, video, fonts, WASM)
|
||||
are served with `Content-Disposition: inline; filename="..."` so they open directly in modern browsers.
|
||||
- Non-browser/binary types default to `Content-Disposition: attachment; filename="..."`.
|
||||
- Use `?download=1` (or `?download=true`) to force file download with `Content-Disposition: attachment`.
|
||||
|
||||
### Caching & Conditional Requests
|
||||
- Generates weak ETags (`W/"thumb-..."` for previews, `W/"<timestamp>-<mode>"` for originals).
|
||||
- Sets `Cache-Control: private, max-age=0, must-revalidate`.
|
||||
- Supports `If-None-Match` conditional requests returning HTTP `304 Not Modified`.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `path` | yes | string | VFS file path (e.g. `example.png`, `labels/a.png`) |
|
||||
| `path` | yes | string | VFS file path (e.g. `example.png`, `charts/graph.svg`) |
|
||||
|
||||
## Query parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `download` | no | boolean | Force file download with Content-Disposition: attachment.
|
||||
|
|
||||
| `raw` | no | boolean | Return original unmodified image inline without generating a preview thumbnail.
|
||||
|
|
||||
| `download` | no | boolean | Force file download with Content-Disposition: attachment (1 or true). |
|
||||
| `raw` | no | boolean | Return original unmodified image inline without generating a preview thumbnail (1 or true). |
|
||||
|
||||
## Response `200`
|
||||
|
||||
File bytes
|
||||
File bytes. Served inline for browser-renderable formats or as a download.
|
||||
Includes headers:
|
||||
- `Content-Type`: MIME type of file, or `image/webp` for previews
|
||||
- `Content-Length`: Size of served payload in bytes
|
||||
- `Content-Disposition`: `inline; filename="..."` or `attachment; filename="..."`
|
||||
- `Cache-Control`: `private, max-age=0, must-revalidate`
|
||||
- `ETag`: Weak ETag identifier
|
||||
- `X-Content-Type-Options`: `nosniff`
|
||||
- `Content-Security-Policy`: `default-src 'none'; sandbox` (for preview thumbnails)
|
||||
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid path, or no company selected — `{"error":"…"}` |
|
||||
| 304 | Not modified (If-None-Match matched ETag) |
|
||||
| 400 | Invalid path, path escapes VFS boundary, or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | File not found — `{"error":"…"}` |
|
||||
|
||||
42
docs/api/routes/vfs/delete.md
Normal file
42
docs/api/routes/vfs/delete.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# `DELETE /vfs/{*path}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete a virtual filesystem file
|
||||
|
||||
Deletes a file from both the on-disk virtual filesystem and database for the authenticated user's selected company.
|
||||
Deleting read-only database files (`image/*` or filenames containing 64-character hex hashes) is blocked with HTTP 403.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `path` | yes | string | VFS file path to delete (e.g. `temp.png`, `notes.txt`) |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `vfs` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
File successfully deleted
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"deleted": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid path, path traversal, or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized, or cannot delete read-only database files — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
43
docs/api/routes/vfs/list.md
Normal file
43
docs/api/routes/vfs/list.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# `GET /vfs`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
List virtual filesystem files
|
||||
|
||||
Lists all virtual filesystem files for the authenticated user's selected company.
|
||||
Scans directories recursively (ignoring hidden dotfiles) and returns file
|
||||
metadata including path, byte size, detected MIME type, timestamps, and classification flags.
|
||||
|
||||
|
||||
## Response `200`
|
||||
|
||||
List of virtual filesystem files
|
||||
|
||||
```json
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"mime": "…",
|
||||
"updated_at": "2026-08-10T00:00:00.000Z",
|
||||
"created_at": "2026-08-10T00:00:00.000Z",
|
||||
"isText": true,
|
||||
"isImage": true,
|
||||
"isPdf": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
48
docs/api/routes/vfs/mkdir.md
Normal file
48
docs/api/routes/vfs/mkdir.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# `POST /vfs/mkdir`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create directory in virtual filesystem
|
||||
|
||||
Creates a directory (and any necessary parent directories) in the virtual filesystem
|
||||
for the authenticated user's selected company.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `path` | yes | string | Directory path to create (e.g. `reports/2026/q1`) |
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `vfs` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Directory created successfully
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"dir": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Path is required, invalid characters, traversal, or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized, or cannot create directory inside read-only database paths — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
52
docs/api/routes/vfs/rename.md
Normal file
52
docs/api/routes/vfs/rename.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# `POST /vfs/rename`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Rename or move a virtual filesystem file or directory
|
||||
|
||||
Renames or moves a file or directory within the virtual filesystem for the authenticated user's selected company.
|
||||
Parent directories for the destination path are created automatically if needed.
|
||||
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `oldPath` | yes | string | Existing VFS file or directory path (e.g. `draft.txt`) |
|
||||
| `newPath` | yes | string | New destination VFS path (e.g. `archive/final.txt`) |
|
||||
|
||||
```json
|
||||
{
|
||||
"oldPath": "…",
|
||||
"newPath": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `vfs` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
File or directory successfully renamed
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"oldPath": "…",
|
||||
"newPath": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Path is required, invalid characters, traversal, or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized, or cannot rename read-only database paths — `{"error":"…"}` |
|
||||
| 404 | Source file or directory not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
53
docs/api/routes/vfs/upload.md
Normal file
53
docs/api/routes/vfs/upload.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# `POST /vfs/upload`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Upload files to virtual filesystem
|
||||
|
||||
Uploads one or more files to the virtual filesystem for the authenticated user's selected company.
|
||||
Files are written to the company's VFS root directory and saved to the database.
|
||||
An optional `targetDir` form field specifies a subfolder within the VFS.
|
||||
|
||||
Writing to read-only database paths (`image/*` or filenames containing 64-character hex hashes) is
|
||||
forbidden and automatically skipped during upload.
|
||||
|
||||
|
||||
## Body (`multipart/form-data`)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `files` | yes | file | One or more files to upload (form field name `files`) |
|
||||
| `targetDir` | no | string | Optional destination subdirectory within VFS (e.g. `reports` or `charts/q1`) |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `vfs` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
Successfully uploaded files
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"uploaded": [
|
||||
{
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"mime": "…"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | No files uploaded, invalid path, or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
66
docs/api/routes/vfs/write.md
Normal file
66
docs/api/routes/vfs/write.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# `PUT /vfs/{*path}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Create or overwrite a virtual filesystem file
|
||||
|
||||
Creates or overwrites a file at the specified virtual filesystem path for the authenticated user's selected company.
|
||||
Supports multiple request payload formats:
|
||||
- JSON body: `{"content": "text content", "mime": "optional/mime"}`
|
||||
- Binary body: raw binary buffer with optional `Content-Type` header
|
||||
- Plain text: raw UTF-8 string
|
||||
|
||||
Modifying read-only database paths (`image/*` or filenames containing 64-character hex hashes) is blocked with HTTP 403.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `path` | yes | string | Destination VFS file path (e.g. `notes.txt`, `data/metrics.json`) |
|
||||
|
||||
## Body (JSON)
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `content` | yes | string | File text content |
|
||||
| `mime` | no | string | Optional MIME type override |
|
||||
|
||||
```json
|
||||
{
|
||||
"content": "…",
|
||||
"mime": "…"
|
||||
}
|
||||
```
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `vfs` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `200`
|
||||
|
||||
File successfully written
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"file": {
|
||||
"name": "…",
|
||||
"size": 1,
|
||||
"mime": "…",
|
||||
"updated_at": "2026-08-10T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Path is required, invalid characters/traversal, no content provided, or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized, or cannot modify read-only database files — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
Reference in New Issue
Block a user