Skip to content
Closed
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
25aaa98
feat: make name field optional on Create and improve AI agent descrip…
claude Apr 8, 2026
eb9e4b4
chore: bump version to 1.4.0, update changelog, add CLAUDE.md
claude Apr 8, 2026
30e3e52
fix: QA improvements - performance, entity decoding, markdown-first s…
claude Apr 8, 2026
57d14be
feat: encode token-efficient navigation strategy in all tool descript…
claude Apr 8, 2026
3b3b4b6
fix: guard against whitespace-only markdown headings in fallback name…
claude Apr 8, 2026
84722b8
docs: add KNOWN_ISSUES.md, update changelog and learnings
claude Apr 8, 2026
5da1a97
fix: clean up action texts - move AI guidance from titles to field de…
claude Apr 8, 2026
76b23ae
fix: rewrite tool descriptions for 100% LLM correctness
claude Apr 8, 2026
f297cef
fix: close 8 LLM description gaps found in tool-use audit
claude Apr 8, 2026
f39129e
docs: add archive-first best practice for AI agents
claude Apr 8, 2026
c06dcd7
fix: final QA audit fixes - action texts, placeholder, known issues
claude Apr 8, 2026
b5b6bdd
fix: final audit cleanup - duplicate changelog, 2 new known issues
claude Apr 8, 2026
422b78b
Merge branch 'lucaguindani:development' into claude/bookstack-integra…
Puma7 Apr 8, 2026
d163274
fix: provide complete list of filterable fields per resource
claude Apr 8, 2026
7bc662e
docs: add 4 missing findings to KNOWN_ISSUES.md (total: 24)
claude Apr 8, 2026
14e1a59
fix: document response fields for every tool so LLMs know what comes …
claude Apr 8, 2026
732d295
fix: resolve 3 remaining dissatisfaction items
claude Apr 8, 2026
509c17a
fix: harden tag name:value parsing against edge cases
claude Apr 8, 2026
d64798a
docs: final learnings from API consistency check
claude Apr 8, 2026
1253922
feat: add Page Title (AI) field that supports $fromAI for AI agents
claude Apr 9, 2026
a1a4957
test: rename name field to test_name_field to check if n8n blocks fie…
claude Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ All notable changes to this project will be documented in this file. Dates are d

Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [1.4.0](https://github.com/lucaguindani/n8n-nodes-bookstack/compare/1.3.0...1.4.0)

> 8 April 2026

##### Features
- Make `name` field optional on Create operations for Page, Book, Chapter, and Shelf resources
- Add `generateFallbackName()` for auto-generation of names from content (extracts headings from HTML/markdown for pages, uses description for other resources, falls back to timestamp)
- Add `decodeHtmlEntities()` for clean auto-generated names from HTML content
- Improve all operation action texts for better AI agent guidance via MCP
- Enrich field descriptions with move semantics, search syntax hints, and tag usage guidance
- Update Global Search description with BookStack advanced filter syntax (`{type:page}`, `{tag:name}`, `{in_name:text}`, `{in_body:text}`)
- Encode token-efficient navigation strategy in all tool descriptions (Search first, Get by ID, never Get Many with Return All on large instances)
- Add warnings to Return All, Deep Dive, and Get Many operations about token cost
- Recommend Markdown over HTML in page content descriptions (~3x fewer tokens)

##### QA & Documentation
- Add `CLAUDE.md` project knowledge base for AI-assisted development
- Add `KNOWN_ISSUES.md` documenting 16 pre-existing issues found during QA audit
- Guard against whitespace-only markdown headings in fallback name generation
- Limit HTML text extraction to 2000-char prefix for performance

#### [1.3.0](https://github.com/lucaguindani/n8n-nodes-bookstack/compare/1.2.0...1.3.0)

- Bump flatted in the npm_and_yarn group across 1 directory [`#6`](https://github.com/lucaguindani/n8n-nodes-bookstack/pull/6)
Expand Down
430 changes: 430 additions & 0 deletions CLAUDE.md

Large diffs are not rendered by default.

314 changes: 314 additions & 0 deletions KNOWN_ISSUES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
# Known Issues

Issues found during QA audit (v1.4.0). Items marked **(v1.4.0)** were introduced
by the v1.4.0 changes. All others are pre-existing.

---

## MEDIUM Severity

### ~~1. Tags do not support BookStack name:value pairs~~ **FIXED in v1.4.0**

Tags now support `name:value` pairs. Input `"topic:networking"` produces
`{name: "topic", value: "networking"}`. The `{tag:name=value}` search syntax works.

---

### 2. Audit-log endpoint has query parameter baked into the URL path

**File:** `nodes/Bookstack/Bookstack.node.ts`, line 382

**Description:** The endpoint string is `'/audit-log?sort=-created_at'` with additional
`qs` parameters (`count`, `offset`) passed separately. The HTTP library constructs:
`baseUrl/audit-log?sort=-created_at&count=50&offset=0`

While most HTTP libraries handle this correctly by appending with `&`, it is fragile
and unconventional.

**Suggested Fix:** Move `sort` into the `qs` object:

```typescript
const qs = { count, offset, sort: '-created_at' } as IDataObject;
const res = await bookstackApiRequest.call(context, 'GET', '/audit-log', {}, qs);
```

---

### 3. Attachment and Image limit field ignores returnAll condition

**Files:**
- `nodes/Bookstack/descriptions/Attachment.description.ts`, lines 216-224
- `nodes/Bookstack/descriptions/Image.description.ts`, lines 123-131

**Description:** Both files use `.map()` which completely **replaces** the original
`displayOptions` from `ListOperations.ts`. The `limit` field has
`displayOptions: { show: { returnAll: [false] } }` to hide when "Return All" is enabled.
For attachments and images, this condition is lost.

Compare with Book/Page/Chapter/Shelf descriptions which correctly use:
```typescript
...(op.displayOptions?.show ?? {})
```

**Impact:** The Limit field remains visible in the UI even when "Return All" is toggled on
for Attachment and Image resources.

**Suggested Fix:** Use the same spread pattern as the other description files.

---

### 4. handleAuditLogOperation lacks Array.isArray safety check

**File:** `nodes/Bookstack/Bookstack.node.ts`, line 386

**Description:** The line casts directly without verifying the result is an array:

```typescript
const data: JsonObject[] = (res?.data ?? res) as JsonObject[];
```

Compare with `handleGetAllOperation` which safely checks:
```typescript
Array.isArray(data) ? (data as JsonObject[]) : []
```

**Impact:** If the API response shape changes or returns an error object,
`aggregated.push(...data)` would throw a runtime error.

---

## LOW Severity

### 5. No filename sanitization in multipart upload

**File:** `nodes/Bookstack/utils/BookstackApiHelpers.ts`, line 101

The `fileName` from `binaryData.fileName` is interpolated directly into the
`Content-Disposition` header. If the filename contains double quotes or CRLF
characters, it could break multipart parsing. Unlikely in practice.

---

### 6. No trailing-slash normalization on baseUrl

**File:** `nodes/Bookstack/utils/BookstackApiHelpers.ts`, line 46

If the user configures `baseUrl` as `https://example.com/api/` (with trailing slash),
the resulting URL will have a double slash: `https://example.com/api//pages`.
Most web servers handle this, but a `.replace(/\/+$/, '')` on `baseUrl` would be cleaner.

---

### 7. HTML heading regex does not enforce matching tag levels

**File:** `nodes/Bookstack/Bookstack.node.ts`, line 143

The regex `/<h[1-6][^>]*>([\s\S]*?)<\/h[1-6]>/i` would match `<h1>text</h2>`
(mismatched levels). Extremely unlikely with BookStack-generated HTML. Only affects
fallback name generation.

---

### 8. decodeHtmlEntities inconsistent case sensitivity

**File:** `nodes/Bookstack/Bookstack.node.ts`, lines 115-123

`&nbsp;` is matched with `/gi` (case-insensitive) but other entities use `/g`
(case-sensitive). So `&NBSP;` decodes but `&AMP;` does not. In practice HTML
entities are almost always lowercase.

---

### 9. decodeHtmlEntities does not handle hex numeric entities

**File:** `nodes/Bookstack/Bookstack.node.ts`, line 123

Only decimal numeric entities (`&#65;`) are handled. Hex entities like `&#x41;`
are not decoded (except the explicitly handled `&#x27;`). Acceptable since the
method is only used for fallback name generation.

---

### 10. decodeHtmlEntities missing &apos; entity

**File:** `nodes/Bookstack/Bookstack.node.ts`, lines 114-124

Handles `&#39;` and `&#x27;` (apostrophe) but not the named entity `&apos;`.
Valid XML/HTML5 but less common in BookStack output.

---

### 11. NodeApiError detection via string comparison

**File:** `nodes/Bookstack/Bookstack.node.ts`, line 753

`e?.constructor?.name === 'NodeApiError'` relies on class name surviving minification.
Using `instanceof NodeApiError` (with import) would be safer.

---

### 12. Null error in catch block could cause secondary TypeError

**File:** `nodes/Bookstack/Bookstack.node.ts`, line 756

If `error` is `null` (extremely unlikely), `e.message` would throw TypeError.
Using `e?.message` would be more defensive.

---

## INFO Severity

### 13. tsconfig.json references non-existent .eslintrc.js

**File:** `tsconfig.json`, line 28

The `include` array references `./.eslintrc.js` which does not exist. Silently
ignored by TypeScript but represents stale configuration.

---

### 14. Type aliases add no type safety

**File:** `nodes/Bookstack/Bookstack.node.ts`, lines 26-27

`SearchItemMinimal` and `ContentResponseShape` are both aliases for `IDataObject`.
Consider using proper interfaces with defined properties.

---

### 15. handleUpdateImageOperation can send empty multipart request

**File:** `nodes/Bookstack/Bookstack.node.ts`, lines 576-592

If `name` and `binaryPropertyName` are both empty, a multipart form with zero fields
is sent. BookStack API would return a validation error.

---

### 16. Double-decoding potential in decodeHtmlEntities

**File:** `nodes/Bookstack/Bookstack.node.ts`, lines 114-124

Replacement order means `&amp;lt;` becomes `&lt;` then `<` (double-decoded).
Acceptable for fallback name generation but not faithful HTML entity decoding.

---

### 17. `requiresDataPath: 'single'` on search query field

**File:** `nodes/Bookstack/descriptions/Global.description.ts`, line 29

The `requiresDataPath: 'single'` property on the search query field is unusual for
a plain text search string. This property is typically used for expression-mode fields
that need data path resolution. On a plain search string field, this could cause
unexpected behavior in certain n8n execution contexts. May be intentional for AI
tool usage but warrants verification.

---

### 18. No `continueOnFail()` support in execute()

**File:** `nodes/Bookstack/Bookstack.node.ts`, lines 747-758

The catch block always rethrows errors. It never checks `this.continueOnFail()`,
which is a common n8n pattern for allowing workflows to continue despite errors.
Items that fail will halt the entire node execution. This may be intentional for
data integrity but limits error resilience in batch workflows.

---

### 19. Multipart request handler has no try/catch error wrapping

**File:** `nodes/Bookstack/utils/BookstackApiHelpers.ts`, line 122

The `bookstackApiRequest()` function wraps HTTP errors in `NodeApiError` for clean
error messages. The `bookstackApiRequestMultipart()` function does NOT - errors from
attachment/image uploads propagate as raw, unformatted exceptions. Users see
unfriendly error messages on upload failures.

**Suggested Fix:** Add the same try/catch pattern:
```typescript
try {
return await this.helpers.httpRequestWithAuthentication.call(this, 'bookstackApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
```

---

### 20. Redundant credential null checks

**File:** `nodes/Bookstack/utils/BookstackApiHelpers.ts`, lines 32-35 and 67-70

`if (!credentials)` check after `await this.getCredentials('bookstackApi')`. The
`getCredentials()` method already throws if credentials are not found, so these
checks are dead code. Not harmful, just redundant.

---

### ~~21. `!body.name` falsy check is too broad~~ **FIXED in v1.4.0**

The check now uses `body.name === undefined || body.name === ''` instead of `!body.name`.

---

### 22. Removing `required: true` from name silently accepts empty names **(v1.4.0)**

**Files:** Page/Book/Chapter/Shelf description files

Previously, the n8n UI blocked submission when the name field was empty (enforced
by `required: true`). Now the UI allows it and the node auto-generates a fallback
name (e.g. `page-2026-04-08T14-30-00`). Manual users who accidentally leave the
name empty will not get a validation error - they will get an auto-generated name
they may not notice until later.

This is an intentional design decision for AI agent usage but changes behavior
for manual users.

---

### ~~23. Page ID description is misleading for Delete operation~~ **FIXED in v1.4.0**

The ID field description now documents all three operations separately:
Get returns fields, Update returns updated object, Delete returns empty on success.

---

### 24. README typo: "lunch" instead of "launch"

**File:** `README.md`, line 122

"To lunch a local instance" should be "To launch a local instance".

---

### 25. `book_id`/`chapter_id`/`default_template_id` sent as strings instead of integers

**Files:** Page.description.ts, Chapter.description.ts, Book.description.ts

These ID fields are `type: 'string'` in the n8n field definitions but the BookStack
API expects integers. PHP/Laravel auto-coerces `"123"` to `123` so this works in
practice, but it is technically sending the wrong type.

---

### 26. Search result `preview_html` is an object, not a string

**File:** `nodes/Bookstack/Bookstack.node.ts`, line 258

BookStack returns `preview_html` as `{name: string, content: string}` with
HTML-highlighted matches. The node maps it to `preview` in the output. The
description says "preview (short text snippet)" which is slightly inaccurate.

---

### 27. Missing API fields not exposed by the node

The following BookStack API fields exist but are not in the node:
- `description_html` (books, chapters, shelves - HTML variant, max 2000 chars)
- `priority` (pages, chapters - ordering within parent)
- `image` / `cover` (books, shelves - cover image)
- `default_template_id` for chapters (only exposed for books currently)

These are feature gaps for potential future versions.
Loading