Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Files & Directories

AeorDB exposes a content-addressable filesystem through its engine routes. Every path under /engine/ represents either a file or a directory.

Endpoint Summary

MethodPathDescriptionAuthStatus Codes
PUT/engine/{path}Store a fileYes201, 400, 404, 409, 500
GET/engine/{path}Read a file or list a directoryYes200, 404, 500
DELETE/engine/{path}Delete a fileYes200, 404, 500
HEAD/engine/{path}Check existence and get metadataYes200, 404, 500
POST/engine-symlink/{path}Create or update a symlinkYes201, 400, 500

PUT /engine/

Store a file at the given path. Parent directories are created automatically. If a file already exists at the path, it is overwritten (creating a new version).

Body limit: 10 GB

Request

  • Headers:
    • Authorization: Bearer <token> (required)
    • Content-Type (optional) – auto-detected from magic bytes if omitted
  • Body: raw file bytes

Response

Status: 201 Created

{
  "path": "/data/report.pdf",
  "content_type": "application/pdf",
  "total_size": 245678,
  "created_at": 1775968398000,
  "updated_at": 1775968398000
}

Side Effects

  • If the path matches /.config/indexes.json (or a nested variant like /data/.config/indexes.json), a reindex task is automatically enqueued for the parent directory. Any existing pending or running reindex for that path is cancelled first.
  • Triggers entries_created events on the event bus.
  • Runs any deployed store-phase plugins.

Example

curl -X PUT http://localhost:3000/engine/data/report.pdf \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/pdf" \
  --data-binary @report.pdf

Error Responses

StatusCondition
400Invalid input (e.g., empty path)
404Parent path references a non-existent entity
409Path conflict (e.g., file exists where directory expected)
500Internal storage failure

GET /engine/

Read a file or list a directory. The server determines the type automatically:

  • If the path resolves to a file, the file content is streamed with appropriate headers.
  • If the path resolves to a directory, a JSON array of children is returned.

Request

  • Headers:
    • Authorization: Bearer <token> (required)

Query Parameters

ParamTypeDefaultDescription
snapshotstringRead the file as it was at this named snapshot
versionstringRead the file at this version hash (hex)
nofollowbooleanfalseIf the path is a symlink, return metadata instead of following
depthinteger0Directory listing depth: 0 = immediate children, -1 = unlimited recursion
globstringFilter directory listing by file name glob pattern (*, ?, [abc])

File Response

Status: 200 OK

Headers:

HeaderDescription
X-PathCanonical path of the file
X-Total-SizeFile size in bytes
X-Created-AtUnix timestamp (milliseconds)
X-Updated-AtUnix timestamp (milliseconds)
Content-TypeMIME type (if known)

Body: raw file bytes (streamed)

Directory Response

Status: 200 OK

Each entry includes path, hash, and numeric entry_type fields. Symlink entries also include a target field.

Entry types: 2 = file, 3 = directory, 8 = symlink.

[
  {
    "path": "/data/report.pdf",
    "name": "report.pdf",
    "entry_type": 2,
    "hash": "a3f8c1...",
    "total_size": 245678,
    "created_at": 1775968398000,
    "updated_at": 1775968398000,
    "content_type": "application/pdf"
  },
  {
    "path": "/data/images",
    "name": "images",
    "entry_type": 3,
    "hash": "b2c4d5...",
    "total_size": 0,
    "created_at": 1775968000000,
    "updated_at": 1775968000000,
    "content_type": null
  },
  {
    "path": "/data/latest",
    "name": "latest",
    "entry_type": 8,
    "hash": "c3d5e6...",
    "target": "/data/report.pdf",
    "total_size": 0,
    "created_at": 1775968500000,
    "updated_at": 1775968500000,
    "content_type": null
  }
]

Examples

Read a file:

curl http://localhost:3000/engine/data/report.pdf \
  -H "Authorization: Bearer $TOKEN" \
  -o report.pdf

List a directory:

curl http://localhost:3000/engine/data/ \
  -H "Authorization: Bearer $TOKEN"

Recursive Directory Listing

Use the depth and glob query parameters to list files recursively:

# List all files recursively
curl http://localhost:3000/engine/data/?depth=-1 \
  -H "Authorization: Bearer $TOKEN"

# List only .psd files anywhere under /assets/
curl "http://localhost:3000/engine/assets/?depth=-1&glob=*.psd" \
  -H "Authorization: Bearer $TOKEN"

# List one level deep
curl http://localhost:3000/engine/data/?depth=1 \
  -H "Authorization: Bearer $TOKEN"

When depth > 0 or depth = -1, the response contains files only in a flat list. Directory entries are traversed but not included in the output.

Versioned Reads

Read a file as it was at a specific snapshot or version:

# Read file at a named snapshot
curl "http://localhost:3000/engine/data/report.pdf?snapshot=v1.0" \
  -H "Authorization: Bearer $TOKEN"

# Read file at a specific version hash
curl "http://localhost:3000/engine/data/report.pdf?version=a1b2c3..." \
  -H "Authorization: Bearer $TOKEN"

If both snapshot and version are provided, snapshot takes precedence. Returns 404 if the file did not exist at that version.

Error Responses

StatusCondition
404Path does not exist as file or directory
500Internal read failure

DELETE /engine/

Delete a file at the given path. Creates a DeletionRecord and removes the file from its parent directory listing. Directories cannot be deleted directly – delete all files within first.

Request

  • Headers:
    • Authorization: Bearer <token> (required)

Response

Status: 200 OK

{
  "deleted": true,
  "path": "/data/report.pdf"
}

Side Effects

  • Triggers entries_deleted events on the event bus.
  • Updates index entries for the deleted file.

Example

curl -X DELETE http://localhost:3000/engine/data/report.pdf \
  -H "Authorization: Bearer $TOKEN"

Error Responses

StatusCondition
404File not found
500Internal deletion failure

AeorDB supports soft symlinks — entries that point to another path. Symlinks are transparent by default: reading a symlink path returns the target’s content.

POST /engine-symlink/

Create or update a symlink.

Request Body:

{
  "target": "/assets/logo.psd"
}

Response: 201 Created

{
  "path": "/latest-logo",
  "target": "/assets/logo.psd",
  "entry_type": 8,
  "created_at": 1775968398000,
  "updated_at": 1775968398000
}

The target path does not need to exist at creation time (dangling symlinks are allowed).

By default, GET /engine/{path} follows symlinks transparently:

# Returns the content of /assets/logo.psd
curl http://localhost:3000/engine/latest-logo \
  -H "Authorization: Bearer $TOKEN"

To inspect the symlink itself without following it, use ?nofollow=true:

curl "http://localhost:3000/engine/latest-logo?nofollow=true" \
  -H "Authorization: Bearer $TOKEN"

Returns the symlink metadata as JSON instead of the target’s content.

Symlinks can point to other symlinks — chains are followed recursively. AeorDB detects cycles and enforces a maximum resolution depth of 32 hops.

ScenarioResult
Symlink → fileReturns file content
Symlink → directoryReturns directory listing
Symlink → symlink → fileFollows chain, returns file content
Symlink → nonexistent404 (dangling symlink)
Symlink cycle (A → B → A)400 with cycle detection message
Chain exceeds 32 hops400 with depth exceeded message

HEAD /engine/{path} returns symlink metadata as headers:

X-Entry-Type: symlink
X-Symlink-Target: /assets/logo.psd
X-Path: /latest-logo
X-Created-At: 1775968398000
X-Updated-At: 1775968398000

DELETE /engine/{path} on a symlink deletes the symlink itself, not the target:

curl -X DELETE http://localhost:3000/engine/latest-logo \
  -H "Authorization: Bearer $TOKEN"
{
  "deleted": true,
  "path": "latest-logo",
  "type": "symlink"
}

Symlinks appear in directory listings with entry_type: 8 and a target field:

{
  "path": "/data/latest",
  "name": "latest",
  "entry_type": 8,
  "hash": "c3d5e6...",
  "target": "/data/report.pdf",
  "total_size": 0,
  "created_at": 1775968500000,
  "updated_at": 1775968500000,
  "content_type": null
}

Symlinks are versioned like files. Snapshots capture the symlink’s target path at that point in time. Restoring a snapshot restores the link, not the resolved content.


HEAD /engine/

Check whether a path exists and retrieve its metadata as response headers, without downloading the body. Works for both files and directories.

Request

  • Headers:
    • Authorization: Bearer <token> (required)

Response

Status: 200 OK (empty body)

Headers:

HeaderValue
X-Entry-Typefile, directory, or symlink
X-PathCanonical path
X-Total-SizeFile size in bytes (files only)
X-Created-AtUnix timestamp in milliseconds (files only)
X-Updated-AtUnix timestamp in milliseconds (files only)
Content-TypeMIME type (files only, if known)
X-Symlink-TargetTarget path (symlinks only)

Example

curl -I http://localhost:3000/engine/data/report.pdf \
  -H "Authorization: Bearer $TOKEN"
HTTP/1.1 200 OK
X-Entry-Type: file
X-Path: /data/report.pdf
X-Total-Size: 245678
X-Created-At: 1775968398000
X-Updated-At: 1775968398000
Content-Type: application/pdf

Error Responses

StatusCondition
404Path does not exist
500Internal metadata lookup failure