@shuji-bonji/pdf-writer-mcp 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/README.ja.md +32 -2
- package/README.md +32 -2
- package/dist/config.d.ts +12 -0
- package/dist/config.js +21 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +5 -0
- package/dist/constants.js.map +1 -1
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +76 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +9 -35
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.js +45 -0
- package/dist/server.js.map +1 -0
- package/dist/services/builder.js +8 -1
- package/dist/services/builder.js.map +1 -1
- package/dist/services/editor.d.ts +24 -8
- package/dist/services/editor.js +85 -136
- package/dist/services/editor.js.map +1 -1
- package/dist/services/font-manager.js +8 -9
- package/dist/services/font-manager.js.map +1 -1
- package/dist/services/form.d.ts +24 -0
- package/dist/services/form.js +98 -2
- package/dist/services/form.js.map +1 -1
- package/dist/services/output.js +5 -4
- package/dist/services/output.js.map +1 -1
- package/dist/services/page-ops.d.ts +15 -0
- package/dist/services/page-ops.js +136 -0
- package/dist/services/page-ops.js.map +1 -0
- package/dist/services/renderers/text.js +2 -3
- package/dist/services/renderers/text.js.map +1 -1
- package/dist/services/struct-append.d.ts +7 -3
- package/dist/services/struct-append.js +18 -4
- package/dist/services/struct-append.js.map +1 -1
- package/dist/services/xmp.js +5 -2
- package/dist/services/xmp.js.map +1 -1
- package/dist/tools/definitions.d.ts +25 -797
- package/dist/tools/definitions.js +78 -427
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/handlers.d.ts +8 -4
- package/dist/tools/handlers.js +54 -45
- package/dist/tools/handlers.js.map +1 -1
- package/dist/types/index.d.ts +13 -0
- package/dist/utils/page-spec.js +6 -5
- package/dist/utils/page-spec.js.map +1 -1
- package/dist/utils/stdout-guard.d.ts +12 -0
- package/dist/utils/stdout-guard.js +16 -0
- package/dist/utils/stdout-guard.js.map +1 -0
- package/dist/utils/validation.d.ts +529 -27
- package/dist/utils/validation.js +399 -391
- package/dist/utils/validation.js.map +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.8.0] - 2026-07-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`tag_form_fields`** — repair the form inside an already-tagged PDF so it
|
|
10
|
+
conforms to PDF/UA-1 (B-6). A tagged PDF that merely *contains* an AcroForm
|
|
11
|
+
fails validation; this tool retrofits the three requirements:
|
|
12
|
+
|
|
13
|
+
- **7.18.4-1**: every Widget annotation is nested in a `Form` structure
|
|
14
|
+
element (`OBJR` + `/StructParent` + ParentTree registration — the same
|
|
15
|
+
machinery `add_annotation` uses for `Annot` elements, now generalised in
|
|
16
|
+
`struct-append.ts`).
|
|
17
|
+
- **7.18.3-1**: pages carrying widgets get `/Tabs /S`.
|
|
18
|
+
- **7.18.1-3**: every field gets a `/TU` (alternate name). Pass `labels`
|
|
19
|
+
with human-readable names (`{"user.name": "氏名"}`); fields without a
|
|
20
|
+
label fall back to the field name and are reported via `warnings`,
|
|
21
|
+
because screen readers announce `/TU` and "user.name" reads poorly.
|
|
22
|
+
|
|
23
|
+
Idempotent: widgets that already have `/StructParent` are skipped, so
|
|
24
|
+
running it twice never duplicates structure elements. Untagged documents
|
|
25
|
+
are rejected (`INVALID_ARGUMENT`) — creating a structure tree from scratch
|
|
26
|
+
is the create tools' job (`tagged: true`) or future Tier C `ensure_tagged`.
|
|
27
|
+
Handles both widget forms pdf-lib produces (`/Kids` children) and merged
|
|
28
|
+
field/widget dictionaries from other producers.
|
|
29
|
+
|
|
30
|
+
**Measured with veraPDF** (`--flavour ua1`): a tagged PDF with an untagged
|
|
31
|
+
form fails exactly 7.18.1-3 / 7.18.3-1 / 7.18.4-1; after `tag_form_fields`
|
|
32
|
+
it is **COMPLIANT (106/106)**.
|
|
33
|
+
|
|
34
|
+
- **Warning for `tagged: true` with the standard font** — found while
|
|
35
|
+
verifying the above: Helvetica is never embedded, so a tagged PDF built
|
|
36
|
+
without `fontPath` always fails PDF/UA-1 7.21.4.1-1. The create tools now
|
|
37
|
+
warn that the output will not validate and point at `fontPath` /
|
|
38
|
+
`PDF_WRITER_FONT`.
|
|
39
|
+
|
|
40
|
+
## [0.7.0] - 2026-07-17
|
|
41
|
+
|
|
42
|
+
コードレビュー(2026-07-17)と TASKS.md E 系(コード衛生・family 整合)への
|
|
43
|
+
一括対応。**ツール名・必須フィールド・成功時の出力形式は不変**。エラー応答の
|
|
44
|
+
形式のみ family 契約に揃えて変わった(minor バンプの理由)。
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **McpServer + Zod へ移行(E-5)** — 低レベル `Server` + 手書き JSON Schema
|
|
49
|
+
(definitions.ts 553 行)+ asserts 検査(validation.ts 502 行)の二重管理を解消。
|
|
50
|
+
Zod スキーマ(validation.ts)が公開スキーマと実行時検証の単一情報源になった。
|
|
51
|
+
reader / verify と同じ `registerTool` パターン。`server.ts` の `buildServer()`
|
|
52
|
+
はテストから `InMemoryTransport` で検証され、`registry.test.ts` が 17 ツールの
|
|
53
|
+
名前・必須フィールド・annotations を外部仕様スナップショットとして固定する。
|
|
54
|
+
- **構造化エラー(E-2)** — `{error: message}` から reader v0.6.0 と同じ
|
|
55
|
+
`code` / `hint` / `next_actions` / `retryable` 形式へ。writer 固有のガードは
|
|
56
|
+
すべて「解除フラグ付きで再試行可能」として表現される:
|
|
57
|
+
`SIGNED_PDF` (allowBreakingSignatures) / `TAGGED_PDF` (allowBreakingTags) /
|
|
58
|
+
`FONT_REQUIRED` (fontPath) / `MISSING_GLYPH` (onMissingGlyph)。ほかに
|
|
59
|
+
`DOC_NOT_FOUND` / `FILE_TOO_LARGE` / `ENCRYPTED_PDF` / `INVALID_PDF` /
|
|
60
|
+
`UNSUPPORTED_PDF_FEATURE` (XFA) / `FONT_NOT_FOUND` / `INVALID_ARGUMENT`。
|
|
61
|
+
- **ページ操作を page-ops.ts へ分離** — merge / split / extract / delete /
|
|
62
|
+
reorder / rotate を editor.ts(20.6kB → 16.1kB)から切り出し。mergePdfs が
|
|
63
|
+
文書情報の引き継ぎのために先頭ファイルを二重読込していた無駄も解消。
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
- **パス検査の強化(E-1)** — すべてのパス引数(inputPath / inputPaths[] /
|
|
68
|
+
outputPath / outputDir / fontPath / attachmentPath)に絶対パスを強制し、
|
|
69
|
+
`..` セグメントを拒否。入力 PDF に 100MB のサイズ上限を新設
|
|
70
|
+
(verify の `MAX_FILE_SIZE` と同水準)。
|
|
71
|
+
- **stdout ガード(E-3)** — `marked` / `subset-font` 等の依存が `console.log`
|
|
72
|
+
を吐いても stdio の JSON-RPC を汚染しないよう、side-effect-first の
|
|
73
|
+
`stdout-guard.ts` を導入(reader / verify と同パターン)。
|
|
74
|
+
- **tool annotations(E-4)** — 全 17 ツールに `readOnlyHint` /
|
|
75
|
+
`destructiveHint` / `idempotentHint` / `openWorldHint` を付与。
|
|
76
|
+
`destructiveHint: true` は情報が失われる `delete_pages` と `flatten_form` のみ。
|
|
77
|
+
- **決定論的出力(E-6)** — 環境変数 `SOURCE_DATE_EPOCH`(UNIX 秒、
|
|
78
|
+
reproducible-builds.org の慣習)設定時に CreationDate / ModificationDate /
|
|
79
|
+
XMP の日時を固定し、同一入力 → 同一バイト列を保証。学習データ工場の
|
|
80
|
+
差分検証・キャッシュ・再現テスト用。不正値は黙殺せずエラー。
|
|
81
|
+
- 依存に `zod ^4.4.3` を追加。
|
|
82
|
+
|
|
5
83
|
## [0.6.0] - 2026-07-16
|
|
6
84
|
|
|
7
85
|
### Added
|
package/README.ja.md
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
## ツール
|
|
14
14
|
|
|
15
|
+
> **ファイルパスはすべて絶対パスで指定してください**(v0.7.0〜)。相対パスと `..` を含むパスは拒否されます — 相対パスは MCP ホストの作業ディレクトリ基準で解決されるため、意図しない場所を指します。対象は `inputPath` / `inputPaths` / `outputPath` / `outputDir` / `fontPath` / `attachmentPath`。100MB を超える入力 PDF も拒否されます。
|
|
16
|
+
|
|
15
17
|
### 生成
|
|
16
18
|
|
|
17
19
|
| ツール | 役割 |
|
|
@@ -53,6 +55,7 @@ PDF/UA はタイトルを要求するため、`tagged: true` では `title` が
|
|
|
53
55
|
| `stamp_page_numbers` | ページ番号を刻む(`{n}` / `{total}`、6 箇所の配置、`pages`、`startAt`)。タグ付き PDF では Artifact になるため準拠を維持する |
|
|
54
56
|
| `fill_form` | AcroForm に値を記入する。日本語は埋め込みフォントで描画。同時にフラット化も可能 |
|
|
55
57
|
| `flatten_form` | フォームを静的な内容に焼き込む。タグ付き PDF は既定で拒否(PDF/UA が壊れるため) |
|
|
58
|
+
| `tag_form_fields` | タグ付き PDF 内のフォームを PDF/UA-1 準拠へ修復する。Widget を `Form` 構造要素に内包(7.18.4-1)、`/Tabs S` を設定(7.18.3-1)、代替名 `/TU` を付与(7.18.1-3)。`labels` で人間可読な名前を渡す。冪等なので何度実行しても安全 |
|
|
56
59
|
| `add_watermark` | 斜めの透かしを重ねる("社外秘" / "DRAFT")。既定で本文の背面。タグ付き PDF では Artifact になる |
|
|
57
60
|
|
|
58
61
|
共通オプション: `outputPath` / `returnBase64` / `allowBreakingSignatures`。
|
|
@@ -118,6 +121,31 @@ PDF/UA はタイトルを要求するため、`tagged: true` では `title` が
|
|
|
118
121
|
|
|
119
122
|
編集ツールは `font` を除いた同じ形を返します。`split_pdf` は `{ files: [...], count }` を返します。
|
|
120
123
|
|
|
124
|
+
## エラー応答(v0.7.0)
|
|
125
|
+
|
|
126
|
+
エラーは `pdf-reader-mcp` と同じ契約の構造化形式で返します。プログラム判定用の安定した `code` に加え、LLM エージェントがそのまま行動できる `next_actions` を含みます。writer 固有のガードはすべて「明示フラグを足せば再試行できる」形で表現されます:
|
|
127
|
+
|
|
128
|
+
```jsonc
|
|
129
|
+
{
|
|
130
|
+
"error": "\"/in/signed.pdf\" appears to be digitally signed (/ByteRange found). …",
|
|
131
|
+
"code": "SIGNED_PDF",
|
|
132
|
+
"retryable": true,
|
|
133
|
+
"next_actions": [
|
|
134
|
+
{
|
|
135
|
+
"action": "retry_with_allowBreakingSignatures",
|
|
136
|
+
"reason": "署名を無効化してよい場合のみ…",
|
|
137
|
+
"example": { "allowBreakingSignatures": true }
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
コード一覧: `INVALID_ARGUMENT` / `DOC_NOT_FOUND` / `FONT_NOT_FOUND` / `INVALID_PDF` / `ENCRYPTED_PDF` / `UNSUPPORTED_PDF_FEATURE`(XFA)/ `FILE_TOO_LARGE` / `INTERNAL_ERROR`、および writer 固有ガードの `SIGNED_PDF`(`allowBreakingSignatures`)/ `TAGGED_PDF`(`allowBreakingTags`)/ `FONT_REQUIRED`(`fontPath`)/ `MISSING_GLYPH`(`onMissingGlyph`)。
|
|
144
|
+
|
|
145
|
+
## 決定論的出力(v0.7.0)
|
|
146
|
+
|
|
147
|
+
環境変数 `SOURCE_DATE_EPOCH`(UNIX 秒。[reproducible-builds.org](https://reproducible-builds.org/docs/source-date-epoch/) の慣習)を設定すると、CreationDate / ModificationDate / XMP の日時が固定され、**同一入力から同一バイト列**が得られます。差分検証・キャッシュ・再現テストに有用です。不正な値は黙殺せずエラーになります。
|
|
148
|
+
|
|
121
149
|
## テキスト抽出
|
|
122
150
|
|
|
123
151
|
生成される PDF はテキストの選択・コピー・全文検索・スクリーンリーダ読み上げが可能です。埋め込みサブセットフォントでも pdf-lib が ToUnicode CMap を出力するためで、この性質は回帰テスト(`extract.test.ts` / `render.test.ts`)で担保しています。
|
|
@@ -151,8 +179,10 @@ TEST_FONT_PATH=/path/to/NotoSansJP-Regular.otf npm test
|
|
|
151
179
|
- [x] 編集系 Tier A 第2波 — しおり・注釈(v0.4.0)
|
|
152
180
|
- [x] タグ付き PDF / PDF/UA-1 — veraPDF で準拠を確認(v0.5.0)
|
|
153
181
|
- [x] タグ付き出力での注釈の `Annot` タグ内包(v0.5.1)
|
|
154
|
-
- [x] 編集系 Tier B —
|
|
155
|
-
- [
|
|
182
|
+
- [x] 編集系 Tier B — 添付ファイル・フォーム記入 / フラット化・透かし・ページ番号スタンプ(v0.6.0)
|
|
183
|
+
- [x] コード衛生・family 整合 — McpServer + Zod、構造化エラー、絶対パス強制、stdout ガード、tool annotations、決定論的出力(v0.7.0)
|
|
184
|
+
- [x] `tag_form_fields` — タグ付き PDF 内フォームの PDF/UA 修復。veraPDF で COMPLIANT を確認(v0.8.0)
|
|
185
|
+
- [ ] 出力パイプライン Skill(write → pdf-reader で読み戻し → pdf-verify で品質ゲート)
|
|
156
186
|
- [ ] 画像の代替テキスト(`Figure` + `/Alt`)
|
|
157
187
|
- [ ] `.ttc` からのフェイス自動抽出
|
|
158
188
|
- [ ] 見出し用と本文用のフォント分け(太字フェイス埋め込み)
|
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ Part of the PDF family alongside [pdf-reader-mcp](https://github.com/shuji-bonji
|
|
|
12
12
|
|
|
13
13
|
## Tools
|
|
14
14
|
|
|
15
|
+
> **All file paths must be absolute** (since v0.7.0). Relative paths and paths containing `..` are rejected — a relative path would resolve against the MCP host's working directory, which is not the directory you think it is. This applies to `inputPath`, `inputPaths`, `outputPath`, `outputDir`, `fontPath` and `attachmentPath`. Input PDFs larger than 100 MB are also rejected.
|
|
16
|
+
|
|
15
17
|
### Creation
|
|
16
18
|
|
|
17
19
|
| Tool | Purpose |
|
|
@@ -53,6 +55,7 @@ PDF/UA mandates a document title, so `tagged: true` requires `title`. `lang` (BC
|
|
|
53
55
|
| `stamp_page_numbers` | Stamp page numbers (`{n}` / `{total}`, six positions, `pages`, `startAt`). Becomes an artifact on tagged PDFs, so conformance holds |
|
|
54
56
|
| `fill_form` | Fill AcroForm fields. Japanese values via an embedded font; can flatten in the same pass |
|
|
55
57
|
| `flatten_form` | Flatten a form into static content. Refuses tagged PDFs by default (breaks PDF/UA) |
|
|
58
|
+
| `tag_form_fields` | Repair the form inside a tagged PDF for PDF/UA-1: nest widgets in `Form` structure elements (7.18.4-1), set `/Tabs S` (7.18.3-1), add `/TU` alternate names (7.18.1-3). Pass `labels` with human-readable names; idempotent, so safe to re-run |
|
|
56
59
|
| `add_watermark` | Overlay a diagonal watermark ("社外秘" / "DRAFT"). Behind the body content by default; artifact on tagged PDFs |
|
|
57
60
|
|
|
58
61
|
Shared options: `outputPath`, `returnBase64`, `allowBreakingSignatures`.
|
|
@@ -118,6 +121,31 @@ Characters absent from the font (e.g. ✔ U+2714, which Noto Sans JP does not in
|
|
|
118
121
|
|
|
119
122
|
Editing tools return the same shape without `font`; `split_pdf` returns `{ files: [...], count }`.
|
|
120
123
|
|
|
124
|
+
## Errors (v0.7.0)
|
|
125
|
+
|
|
126
|
+
Errors are structured, following the same contract as `pdf-reader-mcp`: a stable `code` for programs, plus `next_actions` an LLM agent can act on. Writer-specific guards are all expressed as *retryable with an explicit flag*:
|
|
127
|
+
|
|
128
|
+
```jsonc
|
|
129
|
+
{
|
|
130
|
+
"error": "\"/in/signed.pdf\" appears to be digitally signed (/ByteRange found). …",
|
|
131
|
+
"code": "SIGNED_PDF",
|
|
132
|
+
"retryable": true,
|
|
133
|
+
"next_actions": [
|
|
134
|
+
{
|
|
135
|
+
"action": "retry_with_allowBreakingSignatures",
|
|
136
|
+
"reason": "Only if invalidating the signature is acceptable…",
|
|
137
|
+
"example": { "allowBreakingSignatures": true }
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Codes: `INVALID_ARGUMENT`, `DOC_NOT_FOUND`, `FONT_NOT_FOUND`, `INVALID_PDF`, `ENCRYPTED_PDF`, `UNSUPPORTED_PDF_FEATURE` (XFA), `FILE_TOO_LARGE`, `INTERNAL_ERROR`, and the writer guards `SIGNED_PDF` (`allowBreakingSignatures`), `TAGGED_PDF` (`allowBreakingTags`), `FONT_REQUIRED` (`fontPath`), `MISSING_GLYPH` (`onMissingGlyph`).
|
|
144
|
+
|
|
145
|
+
## Deterministic output (v0.7.0)
|
|
146
|
+
|
|
147
|
+
Set the `SOURCE_DATE_EPOCH` environment variable (UNIX seconds, per the [reproducible-builds.org](https://reproducible-builds.org/docs/source-date-epoch/) convention) to pin `CreationDate`, `ModificationDate` and XMP timestamps. The same input then yields byte-identical output — useful for diffing, caching, and reproducible tests. Invalid values raise an error rather than being ignored.
|
|
148
|
+
|
|
121
149
|
## Text extraction
|
|
122
150
|
|
|
123
151
|
Generated PDFs are selectable, copyable, searchable, and screen-reader accessible: pdf-lib emits a ToUnicode CMap even for embedded subset fonts. This is covered by regression tests (`extract.test.ts`, `render.test.ts`).
|
|
@@ -151,8 +179,10 @@ TEST_FONT_PATH=/path/to/NotoSansJP-Regular.otf npm test
|
|
|
151
179
|
- [x] Editing Tier A wave 2 — bookmarks and annotations (v0.4.0)
|
|
152
180
|
- [x] Tagged PDF / PDF/UA-1 — verified by veraPDF (v0.5.0)
|
|
153
181
|
- [x] Annotations nested in `Annot` tags on tagged output (v0.5.1)
|
|
154
|
-
- [x] Editing Tier B — file attachments (v0.6.0)
|
|
155
|
-
- [
|
|
182
|
+
- [x] Editing Tier B — file attachments, form filling/flattening, watermarks, page-number stamping (v0.6.0)
|
|
183
|
+
- [x] Code hygiene / family alignment — McpServer + Zod, structured errors, absolute-path enforcement, stdout guard, tool annotations, deterministic output (v0.7.0)
|
|
184
|
+
- [x] `tag_form_fields` — PDF/UA repair for forms in tagged PDFs, verified COMPLIANT by veraPDF (v0.8.0)
|
|
185
|
+
- [ ] Publish-pipeline skill (write → read back with pdf-reader → gate with pdf-verify)
|
|
156
186
|
- [ ] Images with alt text (`Figure` + `/Alt`)
|
|
157
187
|
- [ ] Automatic face extraction from `.ttc`
|
|
158
188
|
- [ ] Separate faces for headings and body (bold face embedding)
|
package/dist/config.d.ts
CHANGED
|
@@ -15,7 +15,19 @@ export declare const PACKAGE_INFO: {
|
|
|
15
15
|
export declare const ENV_KEYS: {
|
|
16
16
|
/** デフォルトで埋め込むフォントファイルのパス(.ttf / .otf) */
|
|
17
17
|
readonly DEFAULT_FONT: 'PDF_WRITER_FONT';
|
|
18
|
+
/**
|
|
19
|
+
* 決定論的出力(E-6): reproducible-builds.org の慣習に従う UNIX 秒。
|
|
20
|
+
* 設定時は CreationDate / ModificationDate / XMP の各日時に固定値を使い、
|
|
21
|
+
* 同一入力 → 同一バイト列を保証する(学習データ工場の差分検証・キャッシュ用)。
|
|
22
|
+
*/
|
|
23
|
+
readonly SOURCE_DATE_EPOCH: 'SOURCE_DATE_EPOCH';
|
|
18
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* 出力に焼き込む「現在時刻」。SOURCE_DATE_EPOCH が設定されていれば固定値を返す。
|
|
27
|
+
* 値が不正(数値でない・負)な場合は黙って現在時刻に落とさずエラーにする —
|
|
28
|
+
* 再現性を期待した呼び出し側が黙って非決定的な出力を得るのが最悪のケースのため。
|
|
29
|
+
*/
|
|
30
|
+
export declare function outputDate(): Date;
|
|
19
31
|
/**
|
|
20
32
|
* PDF 生成のデフォルト値
|
|
21
33
|
* 単位はすべて pt(1pt = 1/72 inch)
|
package/dist/config.js
CHANGED
|
@@ -18,7 +18,28 @@ export const PACKAGE_INFO = {
|
|
|
18
18
|
export const ENV_KEYS = {
|
|
19
19
|
/** デフォルトで埋め込むフォントファイルのパス(.ttf / .otf) */
|
|
20
20
|
DEFAULT_FONT: 'PDF_WRITER_FONT',
|
|
21
|
+
/**
|
|
22
|
+
* 決定論的出力(E-6): reproducible-builds.org の慣習に従う UNIX 秒。
|
|
23
|
+
* 設定時は CreationDate / ModificationDate / XMP の各日時に固定値を使い、
|
|
24
|
+
* 同一入力 → 同一バイト列を保証する(学習データ工場の差分検証・キャッシュ用)。
|
|
25
|
+
*/
|
|
26
|
+
SOURCE_DATE_EPOCH: 'SOURCE_DATE_EPOCH',
|
|
21
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* 出力に焼き込む「現在時刻」。SOURCE_DATE_EPOCH が設定されていれば固定値を返す。
|
|
30
|
+
* 値が不正(数値でない・負)な場合は黙って現在時刻に落とさずエラーにする —
|
|
31
|
+
* 再現性を期待した呼び出し側が黙って非決定的な出力を得るのが最悪のケースのため。
|
|
32
|
+
*/
|
|
33
|
+
export function outputDate() {
|
|
34
|
+
const raw = process.env[ENV_KEYS.SOURCE_DATE_EPOCH];
|
|
35
|
+
if (raw === undefined || raw === '')
|
|
36
|
+
return new Date();
|
|
37
|
+
const epoch = Number(raw);
|
|
38
|
+
if (!Number.isFinite(epoch) || epoch < 0) {
|
|
39
|
+
throw new Error(`${ENV_KEYS.SOURCE_DATE_EPOCH} must be a non-negative number of seconds, got "${raw}"`);
|
|
40
|
+
}
|
|
41
|
+
return new Date(epoch * 1000);
|
|
42
|
+
}
|
|
22
43
|
/**
|
|
23
44
|
* PDF 生成のデフォルト値
|
|
24
45
|
* 単位はすべて pt(1pt = 1/72 inch)
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAG5C,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,WAAW,CAAC,IAAI;IACtB,OAAO,EAAE,WAAW,CAAC,OAAO;CACpB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,yCAAyC;IACzC,YAAY,EAAE,iBAAiB;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAG5C,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,WAAW,CAAC,IAAI;IACtB,OAAO,EAAE,WAAW,CAAC,OAAO;CACpB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,yCAAyC;IACzC,YAAY,EAAE,iBAAiB;IAC/B;;;;OAIG;IACH,iBAAiB,EAAE,mBAAmB;CAC9B,CAAC;AAEX;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IACpD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,GAAG,QAAQ,CAAC,iBAAiB,mDAAmD,GAAG,GAAG,CACvF,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,cAAc;IACd,QAAQ,EAAE,IAAI;IACd,eAAe;IACf,MAAM,EAAE,EAAE,EAAE,SAAS;IACrB,gBAAgB;IAChB,QAAQ,EAAE,EAAE;IACZ,wDAAwD;IACxD,UAAU,EAAE,IAAI;IAChB,eAAe;IACf,YAAY,EAAE,CAAC;CACP,CAAC"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -38,6 +38,11 @@ export declare const LIMITS: {
|
|
|
38
38
|
readonly BOOKMARK_MAX_DEPTH: 8;
|
|
39
39
|
/** 埋め込みファイルの最大サイズ(バイト)。PDF 全体がメモリに載るため上限を設ける */
|
|
40
40
|
readonly ATTACHMENT_MAX_BYTES: number;
|
|
41
|
+
/**
|
|
42
|
+
* 入力 PDF の最大サイズ(バイト)。pdf-lib は全体をメモリに載せるため、
|
|
43
|
+
* verify(MAX_FILE_SIZE = 100MB)と同水準の上限を設ける。
|
|
44
|
+
*/
|
|
45
|
+
readonly INPUT_PDF_MAX_BYTES: number;
|
|
41
46
|
};
|
|
42
47
|
/** stamp_page_numbers の配置 */
|
|
43
48
|
export declare const STAMP_POSITIONS: readonly ['bottom-left', 'bottom-center', 'bottom-right', 'top-left', 'top-center', 'top-right'];
|
package/dist/constants.js
CHANGED
|
@@ -37,6 +37,11 @@ export const LIMITS = {
|
|
|
37
37
|
BOOKMARK_MAX_DEPTH: 8,
|
|
38
38
|
/** 埋め込みファイルの最大サイズ(バイト)。PDF 全体がメモリに載るため上限を設ける */
|
|
39
39
|
ATTACHMENT_MAX_BYTES: 100 * 1024 * 1024,
|
|
40
|
+
/**
|
|
41
|
+
* 入力 PDF の最大サイズ(バイト)。pdf-lib は全体をメモリに載せるため、
|
|
42
|
+
* verify(MAX_FILE_SIZE = 100MB)と同水準の上限を設ける。
|
|
43
|
+
*/
|
|
44
|
+
INPUT_PDF_MAX_BYTES: 100 * 1024 * 1024,
|
|
40
45
|
};
|
|
41
46
|
/** stamp_page_numbers の配置 */
|
|
42
47
|
export const STAMP_POSITIONS = [
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;IACrB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC;CACV,CAAC;AAIX;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,qBAAqB;IACrB,aAAa,EAAE,CAAC;IAChB,aAAa,EAAE,EAAE;IACjB,sCAAsC;IACtC,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,GAAG;IACf,6CAA6C;IAC7C,eAAe,EAAE,OAAO;IACxB,+BAA+B;IAC/B,cAAc,EAAE,EAAE;IAClB,cAAc,EAAE,KAAK;IACrB,4BAA4B;IAC5B,gBAAgB,EAAE,EAAE;IACpB,wBAAwB;IACxB,eAAe,EAAE,GAAG;IACpB,uBAAuB;IACvB,kBAAkB,EAAE,KAAK;IACzB,kBAAkB,EAAE,CAAC;IACrB,gDAAgD;IAChD,oBAAoB,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;IACrB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC;CACV,CAAC;AAIX;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,qBAAqB;IACrB,aAAa,EAAE,CAAC;IAChB,aAAa,EAAE,EAAE;IACjB,sCAAsC;IACtC,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,GAAG;IACf,6CAA6C;IAC7C,eAAe,EAAE,OAAO;IACxB,+BAA+B;IAC/B,cAAc,EAAE,EAAE;IAClB,cAAc,EAAE,KAAK;IACrB,4BAA4B;IAC5B,gBAAgB,EAAE,EAAE;IACpB,wBAAwB;IACxB,eAAe,EAAE,GAAG;IACpB,uBAAuB;IACvB,kBAAkB,EAAE,KAAK;IACzB,kBAAkB,EAAE,CAAC;IACrB,gDAAgD;IAChD,oBAAoB,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;IACvC;;;OAGG;IACH,mBAAmB,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;CAC9B,CAAC;AAEX,6BAA6B;AAC7B,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,aAAa;IACb,eAAe;IACf,cAAc;IACd,UAAU;IACV,YAAY;IACZ,WAAW;CACH,CAAC;AAEX,8BAA8B;AAC9B,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,KAAK;IACb,QAAQ,EAAE,eAAe;IACzB,MAAM,EAAE,EAAE;IACV,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,CAAC;CACF,CAAC;AAEX,yBAAyB;AACzB,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,IAAI;CACJ,CAAC;AAEX,sDAAsD;AACtD,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,QAAQ;IACR,MAAM;IACN,aAAa;IACb,YAAY;IACZ,aAAa;CACL,CAAC;AAEX,gCAAgC;AAChC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAEzE,kDAAkD;AAClD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM;IACN,SAAS;IACT,KAAK;IACL,MAAM;IACN,cAAc;IACd,WAAW;IACX,QAAQ;CACA,CAAC;AAEX,qCAAqC;AACrC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,eAAe,CAAC;AAExD;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,mCAAmC;IACnC,GAAG,EAAE,MAAM;CACH,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* family-compatible 構造化エラー応答(E-2) — pdf-writer-mcp 実装
|
|
3
|
+
*
|
|
4
|
+
* 設計指針:
|
|
5
|
+
* - pdf-reader-mcp v0.6.0 の error contract に準拠(`code` 文字列を共有)
|
|
6
|
+
* - 共通パッケージ依存を持たない独立実装
|
|
7
|
+
* - writer 固有のコード(SIGNED_PDF / TAGGED_PDF / FONT_REQUIRED /
|
|
8
|
+
* MISSING_GLYPH)を追加。いずれも「明示フラグや引数の追加で再試行できる」
|
|
9
|
+
* ガード系で、`retryable: true` + `next_actions` により出力パイプライン
|
|
10
|
+
* Skill / LLM エージェントが自律的に分岐できる。
|
|
11
|
+
*
|
|
12
|
+
* family contract 仕様:
|
|
13
|
+
* @see https://github.com/shuji-bonji/houki-research-skill/blob/main/docs/ERROR-CODES.md
|
|
14
|
+
*/
|
|
15
|
+
/** family 共通コードの部分集合 + writer 固有拡張 */
|
|
16
|
+
export type WriterErrorCode = 'INVALID_ARGUMENT' | 'DOC_NOT_FOUND' | 'FONT_NOT_FOUND' | 'INVALID_PDF' | 'ENCRYPTED_PDF' | 'UNSUPPORTED_PDF_FEATURE' | 'FILE_TOO_LARGE' | 'SIGNED_PDF' | 'TAGGED_PDF' | 'FONT_REQUIRED' | 'MISSING_GLYPH' | 'INTERNAL_ERROR';
|
|
17
|
+
/** 次に取るべきアクションの提案。LLM が読んで自律的に再試行することを想定 */
|
|
18
|
+
export interface NextAction {
|
|
19
|
+
/** 推奨アクション(tool 名 or 自然言語) */
|
|
20
|
+
action: string;
|
|
21
|
+
/** どんなときに有効か */
|
|
22
|
+
reason: string;
|
|
23
|
+
/** 具体的な引数例(任意) */
|
|
24
|
+
example?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/** family-compatible 共通エラー応答 */
|
|
27
|
+
export interface WriterServiceError {
|
|
28
|
+
/** 1文の人間可読メッセージ(LLM もここを読む) */
|
|
29
|
+
error: string;
|
|
30
|
+
/** プログラム判定用の安定したコード */
|
|
31
|
+
code: WriterErrorCode;
|
|
32
|
+
/** 追加情報(任意) */
|
|
33
|
+
hint?: string;
|
|
34
|
+
/** LLM が次に取るべき手段の候補 */
|
|
35
|
+
next_actions?: NextAction[];
|
|
36
|
+
/** フラグや引数を変えれば再試行できるか */
|
|
37
|
+
retryable?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** コード・ヒント・next_actions を運ぶ writer 固有の Error */
|
|
40
|
+
export declare class PdfWriterError extends Error {
|
|
41
|
+
readonly code: WriterErrorCode;
|
|
42
|
+
readonly options: {
|
|
43
|
+
hint?: string;
|
|
44
|
+
next_actions?: NextAction[];
|
|
45
|
+
retryable?: boolean;
|
|
46
|
+
};
|
|
47
|
+
constructor(message: string, code: WriterErrorCode, options?: {
|
|
48
|
+
hint?: string;
|
|
49
|
+
next_actions?: NextAction[];
|
|
50
|
+
retryable?: boolean;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** 引数エラーの短縮形(validation.ts / page-spec.ts の大量の検査で使う) */
|
|
54
|
+
export declare function invalidArg(message: string): PdfWriterError;
|
|
55
|
+
/** 投げられた値を family 形式のエラー応答へ変換する */
|
|
56
|
+
export declare function toStructuredError(error: unknown): WriterServiceError;
|
|
57
|
+
/** よく使う next_actions のプリセット(writer のガード解除フラグ群) */
|
|
58
|
+
export declare const NEXT_ACTIONS: {
|
|
59
|
+
readonly allowBreakingSignatures: () => NextAction;
|
|
60
|
+
readonly allowBreakingTags: () => NextAction;
|
|
61
|
+
readonly provideFontPath: () => NextAction;
|
|
62
|
+
readonly changeMissingGlyphPolicy: () => NextAction;
|
|
63
|
+
readonly checkFilePath: (path?: string) => NextAction;
|
|
64
|
+
};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* family-compatible 構造化エラー応答(E-2) — pdf-writer-mcp 実装
|
|
3
|
+
*
|
|
4
|
+
* 設計指針:
|
|
5
|
+
* - pdf-reader-mcp v0.6.0 の error contract に準拠(`code` 文字列を共有)
|
|
6
|
+
* - 共通パッケージ依存を持たない独立実装
|
|
7
|
+
* - writer 固有のコード(SIGNED_PDF / TAGGED_PDF / FONT_REQUIRED /
|
|
8
|
+
* MISSING_GLYPH)を追加。いずれも「明示フラグや引数の追加で再試行できる」
|
|
9
|
+
* ガード系で、`retryable: true` + `next_actions` により出力パイプライン
|
|
10
|
+
* Skill / LLM エージェントが自律的に分岐できる。
|
|
11
|
+
*
|
|
12
|
+
* family contract 仕様:
|
|
13
|
+
* @see https://github.com/shuji-bonji/houki-research-skill/blob/main/docs/ERROR-CODES.md
|
|
14
|
+
*/
|
|
15
|
+
/** コード・ヒント・next_actions を運ぶ writer 固有の Error */
|
|
16
|
+
export class PdfWriterError extends Error {
|
|
17
|
+
code;
|
|
18
|
+
options;
|
|
19
|
+
constructor(message, code, options = {}) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.name = 'PdfWriterError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** 引数エラーの短縮形(validation.ts / page-spec.ts の大量の検査で使う) */
|
|
27
|
+
export function invalidArg(message) {
|
|
28
|
+
return new PdfWriterError(message, 'INVALID_ARGUMENT');
|
|
29
|
+
}
|
|
30
|
+
/** 投げられた値を family 形式のエラー応答へ変換する */
|
|
31
|
+
export function toStructuredError(error) {
|
|
32
|
+
if (error instanceof PdfWriterError) {
|
|
33
|
+
const out = { error: error.message, code: error.code };
|
|
34
|
+
if (error.options.hint)
|
|
35
|
+
out.hint = error.options.hint;
|
|
36
|
+
if (error.options.next_actions && error.options.next_actions.length > 0) {
|
|
37
|
+
out.next_actions = error.options.next_actions;
|
|
38
|
+
}
|
|
39
|
+
if (error.options.retryable !== undefined)
|
|
40
|
+
out.retryable = error.options.retryable;
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
if (error instanceof Error) {
|
|
44
|
+
return { error: error.message, code: 'INTERNAL_ERROR' };
|
|
45
|
+
}
|
|
46
|
+
return { error: String(error), code: 'INTERNAL_ERROR' };
|
|
47
|
+
}
|
|
48
|
+
/** よく使う next_actions のプリセット(writer のガード解除フラグ群) */
|
|
49
|
+
export const NEXT_ACTIONS = {
|
|
50
|
+
allowBreakingSignatures: () => ({
|
|
51
|
+
action: 'retry_with_allowBreakingSignatures',
|
|
52
|
+
reason: '署名を無効化してよい場合のみ、同じ引数に "allowBreakingSignatures": true を足して再試行してください',
|
|
53
|
+
example: { allowBreakingSignatures: true },
|
|
54
|
+
}),
|
|
55
|
+
allowBreakingTags: () => ({
|
|
56
|
+
action: 'retry_with_allowBreakingTags',
|
|
57
|
+
reason: 'PDF/UA 適合を壊してよい場合のみ、"allowBreakingTags": true を足して再試行してください',
|
|
58
|
+
example: { allowBreakingTags: true },
|
|
59
|
+
}),
|
|
60
|
+
provideFontPath: () => ({
|
|
61
|
+
action: 'retry_with_fontPath',
|
|
62
|
+
reason: '非 Latin 文字(日本語等)には埋め込みフォントが必要です。"fontPath" に .ttf/.otf を指定するか、環境変数 PDF_WRITER_FONT を設定してください',
|
|
63
|
+
example: { fontPath: '/path/to/NotoSansJP-Regular.otf' },
|
|
64
|
+
}),
|
|
65
|
+
changeMissingGlyphPolicy: () => ({
|
|
66
|
+
action: 'retry_with_onMissingGlyph',
|
|
67
|
+
reason: 'フォントに無い文字が本文に含まれます。別のフォントを指定するか、"onMissingGlyph": "replace"(豆腐で置換)/ "ignore"(黙って除去)を指定してください',
|
|
68
|
+
example: { onMissingGlyph: 'replace' },
|
|
69
|
+
}),
|
|
70
|
+
checkFilePath: (path) => ({
|
|
71
|
+
action: 'verify_file_path',
|
|
72
|
+
reason: 'ファイルパスが正しいか、絶対パスで指定されているか確認してください',
|
|
73
|
+
example: path ? { inputPath: path } : undefined,
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA8CH,gDAAgD;AAChD,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGrB,IAAI;IACJ,OAAO;IAHzB,YACE,OAAe,EACC,IAAqB,EACrB,OAAO,GAInB,EAAE;QAEN,KAAK,CAAC,OAAO,CAAC,CAAC;oBAPC,IAAI;uBACJ,OAAO;QAOvB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,wDAAwD;AACxD,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,IAAI,cAAc,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACzD,CAAC;AAED,mCAAmC;AACnC,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;QACpC,MAAM,GAAG,GAAuB,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3E,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QACtD,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxE,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;QAChD,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS;YAAE,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QACnF,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IAC1D,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;AAC1D,CAAC;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,uBAAuB,EAAE,GAAe,EAAE,CAAC,CAAC;QAC1C,MAAM,EAAE,oCAAoC;QAC5C,MAAM,EACJ,oEAAoE;QACtE,OAAO,EAAE,EAAE,uBAAuB,EAAE,IAAI,EAAE;KAC3C,CAAC;IACF,iBAAiB,EAAE,GAAe,EAAE,CAAC,CAAC;QACpC,MAAM,EAAE,8BAA8B;QACtC,MAAM,EAAE,6DAA6D;QACrE,OAAO,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACrC,CAAC;IACF,eAAe,EAAE,GAAe,EAAE,CAAC,CAAC;QAClC,MAAM,EAAE,qBAAqB;QAC7B,MAAM,EACJ,8FAA8F;QAChG,OAAO,EAAE,EAAE,QAAQ,EAAE,iCAAiC,EAAE;KACzD,CAAC;IACF,wBAAwB,EAAE,GAAe,EAAE,CAAC,CAAC;QAC3C,MAAM,EAAE,2BAA2B;QACnC,MAAM,EACJ,8FAA8F;QAChG,OAAO,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE;KACvC,CAAC;IACF,aAAa,EAAE,CAAC,IAAa,EAAc,EAAE,CAAC,CAAC;QAC7C,MAAM,EAAE,kBAAkB;QAC1B,MAAM,EAAE,mCAAmC;QAC3C,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;KAChD,CAAC;CACM,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* pdf-writer-mcp — MCP server entry
|
|
4
|
-
* テキスト / Markdown / 表データから PDF
|
|
4
|
+
* テキスト / Markdown / 表データから PDF を生成し、既存 PDF を編集する。
|
|
5
|
+
*
|
|
6
|
+
* E-5: reader / verify と同じ McpServer + registerTool + Zod 構成。
|
|
7
|
+
* ツール定義(説明・スキーマ・annotations)は tools/definitions.ts の
|
|
8
|
+
* レジストリ、実装は tools/handlers.ts、スキーマは utils/validation.ts。
|
|
5
9
|
*/
|
|
6
|
-
|
|
10
|
+
import './utils/stdout-guard.js';
|
package/dist/index.js
CHANGED
|
@@ -1,46 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* pdf-writer-mcp — MCP server entry
|
|
4
|
-
* テキスト / Markdown / 表データから PDF
|
|
4
|
+
* テキスト / Markdown / 表データから PDF を生成し、既存 PDF を編集する。
|
|
5
|
+
*
|
|
6
|
+
* E-5: reader / verify と同じ McpServer + registerTool + Zod 構成。
|
|
7
|
+
* ツール定義(説明・スキーマ・annotations)は tools/definitions.ts の
|
|
8
|
+
* レジストリ、実装は tools/handlers.ts、スキーマは utils/validation.ts。
|
|
5
9
|
*/
|
|
6
|
-
|
|
10
|
+
// stdout ガードは他のあらゆる import より先(side-effect first)
|
|
11
|
+
import './utils/stdout-guard.js';
|
|
7
12
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
|
-
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
9
13
|
import { PACKAGE_INFO } from './config.js';
|
|
10
|
-
import {
|
|
11
|
-
import { toolHandlers } from './tools/handlers.js';
|
|
14
|
+
import { buildServer } from './server.js';
|
|
12
15
|
import { logger } from './utils/logger.js';
|
|
13
|
-
const server = new Server({
|
|
14
|
-
name: PACKAGE_INFO.name,
|
|
15
|
-
version: PACKAGE_INFO.version,
|
|
16
|
-
}, {
|
|
17
|
-
capabilities: { tools: {} },
|
|
18
|
-
});
|
|
19
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
20
|
-
tools,
|
|
21
|
-
}));
|
|
22
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
23
|
-
const { name, arguments: args } = request.params;
|
|
24
|
-
try {
|
|
25
|
-
const handler = toolHandlers[name];
|
|
26
|
-
if (!handler) {
|
|
27
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
28
|
-
}
|
|
29
|
-
const result = await handler(args);
|
|
30
|
-
return {
|
|
31
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
36
|
-
logger.error(name, message, error instanceof Error ? error : undefined);
|
|
37
|
-
return {
|
|
38
|
-
content: [{ type: 'text', text: JSON.stringify({ error: message }, null, 2) }],
|
|
39
|
-
isError: true,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
16
|
async function main() {
|
|
17
|
+
const server = buildServer();
|
|
44
18
|
const transport = new StdioServerTransport();
|
|
45
19
|
await server.connect(transport);
|
|
46
20
|
logger.info(PACKAGE_INFO.name, `v${PACKAGE_INFO.version} started (stdio)`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,kDAAkD;AAClD,OAAO,yBAAyB,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,YAAY,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC7E,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,wBAAwB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* McpServer の構築(E-5)。
|
|
3
|
+
* index.ts(stdio 接続)とテスト(InMemoryTransport)の両方から使う。
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import { PACKAGE_INFO } from './config.js';
|
|
7
|
+
import { toStructuredError } from './errors.js';
|
|
8
|
+
import { tools } from './tools/definitions.js';
|
|
9
|
+
import { toolHandlers } from './tools/handlers.js';
|
|
10
|
+
import { logger } from './utils/logger.js';
|
|
11
|
+
export function buildServer() {
|
|
12
|
+
const server = new McpServer({
|
|
13
|
+
name: PACKAGE_INFO.name,
|
|
14
|
+
version: PACKAGE_INFO.version,
|
|
15
|
+
});
|
|
16
|
+
for (const tool of tools) {
|
|
17
|
+
const handler = toolHandlers[tool.name];
|
|
18
|
+
if (!handler) {
|
|
19
|
+
throw new Error(`No handler registered for tool: ${tool.name}`);
|
|
20
|
+
}
|
|
21
|
+
server.registerTool(tool.name, {
|
|
22
|
+
title: tool.title,
|
|
23
|
+
description: tool.description,
|
|
24
|
+
inputSchema: tool.shape,
|
|
25
|
+
annotations: tool.annotations,
|
|
26
|
+
}, async (args) => {
|
|
27
|
+
try {
|
|
28
|
+
const result = await handler(args);
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const structured = toStructuredError(error);
|
|
35
|
+
logger.error(tool.name, structured.error, error instanceof Error ? error : undefined);
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: JSON.stringify(structured, null, 2) }],
|
|
38
|
+
isError: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return server;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,YAAY,CAAC,IAAI;QACvB,OAAO,EAAE,YAAY,CAAC,OAAO;KAC9B,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,KAAK;YACvB,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;YACtB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBACnC,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;iBAC5E,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBAC5C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;gBACtF,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;oBAC/E,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/services/builder.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { PDFDocument, rgb } from 'pdf-lib';
|
|
10
10
|
import { DEFAULTS } from '../config.js';
|
|
11
11
|
import { PAGE_SIZES, RENDERER_GENERATED_CHARS } from '../constants.js';
|
|
12
|
+
import { invalidArg } from '../errors.js';
|
|
12
13
|
import { inferLang } from '../utils/lang.js';
|
|
13
14
|
import { applyMissingGlyphPolicy, embedFontFor, openFont, } from './font-manager.js';
|
|
14
15
|
import { LayoutEngine } from './layout.js';
|
|
@@ -43,7 +44,13 @@ export async function buildPdf(opts, inputTexts, render) {
|
|
|
43
44
|
let lang;
|
|
44
45
|
if (opts.tagged) {
|
|
45
46
|
if (!title) {
|
|
46
|
-
throw
|
|
47
|
+
throw invalidArg('tagged: true requires "title" — PDF/UA (ISO 14289-1, 7.1) mandates a document title.');
|
|
48
|
+
}
|
|
49
|
+
if (source.isStandard) {
|
|
50
|
+
// veraPDF 実測(2026-07-17): 標準フォントは 7.21.4.1-1(フォント埋め込み)で必ず違反になる
|
|
51
|
+
warnings.push('The standard font (Helvetica) is not embedded, but PDF/UA-1 (7.21.4.1) requires all ' +
|
|
52
|
+
'fonts to be embedded — this tagged PDF will NOT pass conformance validation. ' +
|
|
53
|
+
'Pass "fontPath" (or set PDF_WRITER_FONT) to embed a font.');
|
|
47
54
|
}
|
|
48
55
|
lang = opts.lang;
|
|
49
56
|
if (!lang) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/services/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,UAAU,EAAqB,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/services/builder.ts"],"names":[],"mappings":"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"}
|