document-rest 1.4.89 → 1.4.91

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/dist/bin.js CHANGED
@@ -5,11 +5,18 @@ import { OdbReportNotSpecifiedError, OdmUnresolvedSectionError } from "documents
5
5
  import { z } from "zod";
6
6
  //#region src/server.ts
7
7
  const OPERATIONS_BY_NAME = new Map(DOCUMENT_OPERATIONS.map((operation) => [operation.name, operation]));
8
+ /** The HTTP status codes this server ever sends, named for readability at each call site rather than repeated as bare literals. Exported so tests can assert against the same names rather than re-declaring the numbers. */
9
+ const HTTP_STATUS = {
10
+ ok: 200,
11
+ badRequest: 400,
12
+ notFound: 404,
13
+ methodNotAllowed: 405
14
+ };
8
15
  function buildErrorMappers() {
9
16
  return /* @__PURE__ */ new Map([["odb_render_report", (error) => {
10
17
  if (!(error instanceof OdbReportNotSpecifiedError)) return void 0;
11
18
  return {
12
- status: 400,
19
+ status: HTTP_STATUS.badRequest,
13
20
  body: {
14
21
  error: error.message,
15
22
  availableReports: error.availableReports
@@ -18,7 +25,7 @@ function buildErrorMappers() {
18
25
  }], ["odm_to_pdf", (error) => {
19
26
  if (!(error instanceof OdmUnresolvedSectionError)) return void 0;
20
27
  return {
21
- status: 400,
28
+ status: HTTP_STATUS.badRequest,
22
29
  body: {
23
30
  error: `${error.message} Pass chaptersDir containing these files, or an explicit chapters override, for each href.`,
24
31
  hrefs: error.hrefs
@@ -50,26 +57,27 @@ async function handleOperationRequest(req, res, operation) {
50
57
  try {
51
58
  rawBody = await readJsonBody(req);
52
59
  } catch (error) {
53
- sendJson(res, 400, { error: `Request body is not valid JSON: ${error instanceof Error ? error.message : String(error)}` });
60
+ sendJson(res, HTTP_STATUS.badRequest, { error: `Request body is not valid JSON: ${error instanceof Error ? error.message : String(error)}` });
54
61
  return;
55
62
  }
56
63
  const parsed = operation.inputSchema.safeParse(rawBody);
57
64
  if (!parsed.success) {
58
- sendJson(res, 400, {
65
+ sendJson(res, HTTP_STATUS.badRequest, {
59
66
  error: "Request body failed validation.",
60
67
  issues: z.treeifyError(parsed.error)
61
68
  });
62
69
  return;
63
70
  }
64
71
  try {
65
- sendJson(res, 200, { result: await operation.run(parsed.data, { signal: abortSignalFor(res) }) });
72
+ const result = await operation.run(parsed.data, { signal: abortSignalFor(res) });
73
+ sendJson(res, HTTP_STATUS.ok, { result });
66
74
  } catch (error) {
67
75
  const mapped = buildErrorMappers().get(operation.name)?.(error);
68
76
  if (mapped !== void 0) {
69
77
  sendJson(res, mapped.status, mapped.body);
70
78
  return;
71
79
  }
72
- sendJson(res, 400, { error: error instanceof Error ? error.message : String(error) });
80
+ sendJson(res, HTTP_STATUS.badRequest, { error: error instanceof Error ? error.message : String(error) });
73
81
  }
74
82
  }
75
83
  function listOperations() {
@@ -86,22 +94,22 @@ function createRestServer() {
86
94
  return createServer((req, res) => {
87
95
  (async () => {
88
96
  if (req.url === void 0 || req.method === void 0) {
89
- sendJson(res, 400, { error: "Malformed request: no url or method." });
97
+ sendJson(res, HTTP_STATUS.badRequest, { error: "Malformed request: no url or method." });
90
98
  return;
91
99
  }
92
100
  const url = new URL(req.url, "http://localhost");
93
101
  if (url.pathname === "/" && req.method === "GET") {
94
- sendJson(res, 200, listOperations());
102
+ sendJson(res, HTTP_STATUS.ok, listOperations());
95
103
  return;
96
104
  }
97
105
  const name = url.pathname.slice(1);
98
106
  const operation = OPERATIONS_BY_NAME.get(name);
99
107
  if (operation === void 0) {
100
- sendJson(res, 404, { error: `No operation named "${name}". GET / lists every available operation.` });
108
+ sendJson(res, HTTP_STATUS.notFound, { error: `No operation named "${name}". GET / lists every available operation.` });
101
109
  return;
102
110
  }
103
111
  if (req.method !== "POST") {
104
- sendJson(res, 405, { error: `${name} only accepts POST, received ${req.method}.` });
112
+ sendJson(res, HTTP_STATUS.methodNotAllowed, { error: `${name} only accepts POST, received ${req.method}.` });
105
113
  return;
106
114
  }
107
115
  await handleOperationRequest(req, res, operation);
@@ -111,6 +119,8 @@ function createRestServer() {
111
119
  //#endregion
112
120
  //#region src/cli.ts
113
121
  const DEFAULT_PORT = 3100;
122
+ /** The highest valid TCP port number (16 bits, so 2^16 - 1). */
123
+ const MAX_TCP_PORT = 65535;
114
124
  function readFlag(args, name) {
115
125
  const prefix = `--${name}=`;
116
126
  for (const [index, arg] of args.entries()) {
@@ -124,7 +134,7 @@ function readFlag(args, name) {
124
134
  }
125
135
  function parsePort(raw) {
126
136
  const port = Number.parseInt(raw, 10);
127
- if (!Number.isInteger(port) || String(port) !== raw.trim() || port < 0 || port > 65535) throw new Error(`--port must be an integer between 0 and 65535, got "${raw}"`);
137
+ if (!Number.isInteger(port) || String(port) !== raw.trim() || port < 0 || port > 65535) throw new Error(`--port must be an integer between 0 and ${String(MAX_TCP_PORT)}, got "${raw}"`);
128
138
  return port;
129
139
  }
130
140
  /**
package/dist/index.cjs CHANGED
@@ -5,11 +5,18 @@ let documents_js = require("documents.js");
5
5
  let zod = require("zod");
6
6
  //#region src/server.ts
7
7
  const OPERATIONS_BY_NAME = new Map(document_operations.DOCUMENT_OPERATIONS.map((operation) => [operation.name, operation]));
8
+ /** The HTTP status codes this server ever sends, named for readability at each call site rather than repeated as bare literals. Exported so tests can assert against the same names rather than re-declaring the numbers. */
9
+ const HTTP_STATUS = {
10
+ ok: 200,
11
+ badRequest: 400,
12
+ notFound: 404,
13
+ methodNotAllowed: 405
14
+ };
8
15
  function buildErrorMappers() {
9
16
  return /* @__PURE__ */ new Map([["odb_render_report", (error) => {
10
17
  if (!(error instanceof documents_js.OdbReportNotSpecifiedError)) return void 0;
11
18
  return {
12
- status: 400,
19
+ status: HTTP_STATUS.badRequest,
13
20
  body: {
14
21
  error: error.message,
15
22
  availableReports: error.availableReports
@@ -18,7 +25,7 @@ function buildErrorMappers() {
18
25
  }], ["odm_to_pdf", (error) => {
19
26
  if (!(error instanceof documents_js.OdmUnresolvedSectionError)) return void 0;
20
27
  return {
21
- status: 400,
28
+ status: HTTP_STATUS.badRequest,
22
29
  body: {
23
30
  error: `${error.message} Pass chaptersDir containing these files, or an explicit chapters override, for each href.`,
24
31
  hrefs: error.hrefs
@@ -50,26 +57,27 @@ async function handleOperationRequest(req, res, operation) {
50
57
  try {
51
58
  rawBody = await readJsonBody(req);
52
59
  } catch (error) {
53
- sendJson(res, 400, { error: `Request body is not valid JSON: ${error instanceof Error ? error.message : String(error)}` });
60
+ sendJson(res, HTTP_STATUS.badRequest, { error: `Request body is not valid JSON: ${error instanceof Error ? error.message : String(error)}` });
54
61
  return;
55
62
  }
56
63
  const parsed = operation.inputSchema.safeParse(rawBody);
57
64
  if (!parsed.success) {
58
- sendJson(res, 400, {
65
+ sendJson(res, HTTP_STATUS.badRequest, {
59
66
  error: "Request body failed validation.",
60
67
  issues: zod.z.treeifyError(parsed.error)
61
68
  });
62
69
  return;
63
70
  }
64
71
  try {
65
- sendJson(res, 200, { result: await operation.run(parsed.data, { signal: abortSignalFor(res) }) });
72
+ const result = await operation.run(parsed.data, { signal: abortSignalFor(res) });
73
+ sendJson(res, HTTP_STATUS.ok, { result });
66
74
  } catch (error) {
67
75
  const mapped = buildErrorMappers().get(operation.name)?.(error);
68
76
  if (mapped !== void 0) {
69
77
  sendJson(res, mapped.status, mapped.body);
70
78
  return;
71
79
  }
72
- sendJson(res, 400, { error: error instanceof Error ? error.message : String(error) });
80
+ sendJson(res, HTTP_STATUS.badRequest, { error: error instanceof Error ? error.message : String(error) });
73
81
  }
74
82
  }
75
83
  function listOperations() {
@@ -86,22 +94,22 @@ function createRestServer() {
86
94
  return (0, node_http.createServer)((req, res) => {
87
95
  (async () => {
88
96
  if (req.url === void 0 || req.method === void 0) {
89
- sendJson(res, 400, { error: "Malformed request: no url or method." });
97
+ sendJson(res, HTTP_STATUS.badRequest, { error: "Malformed request: no url or method." });
90
98
  return;
91
99
  }
92
100
  const url = new URL(req.url, "http://localhost");
93
101
  if (url.pathname === "/" && req.method === "GET") {
94
- sendJson(res, 200, listOperations());
102
+ sendJson(res, HTTP_STATUS.ok, listOperations());
95
103
  return;
96
104
  }
97
105
  const name = url.pathname.slice(1);
98
106
  const operation = OPERATIONS_BY_NAME.get(name);
99
107
  if (operation === void 0) {
100
- sendJson(res, 404, { error: `No operation named "${name}". GET / lists every available operation.` });
108
+ sendJson(res, HTTP_STATUS.notFound, { error: `No operation named "${name}". GET / lists every available operation.` });
101
109
  return;
102
110
  }
103
111
  if (req.method !== "POST") {
104
- sendJson(res, 405, { error: `${name} only accepts POST, received ${req.method}.` });
112
+ sendJson(res, HTTP_STATUS.methodNotAllowed, { error: `${name} only accepts POST, received ${req.method}.` });
105
113
  return;
106
114
  }
107
115
  await handleOperationRequest(req, res, operation);
package/dist/index.js CHANGED
@@ -4,11 +4,18 @@ import { OdbReportNotSpecifiedError, OdmUnresolvedSectionError } from "documents
4
4
  import { z } from "zod";
5
5
  //#region src/server.ts
6
6
  const OPERATIONS_BY_NAME = new Map(DOCUMENT_OPERATIONS.map((operation) => [operation.name, operation]));
7
+ /** The HTTP status codes this server ever sends, named for readability at each call site rather than repeated as bare literals. Exported so tests can assert against the same names rather than re-declaring the numbers. */
8
+ const HTTP_STATUS = {
9
+ ok: 200,
10
+ badRequest: 400,
11
+ notFound: 404,
12
+ methodNotAllowed: 405
13
+ };
7
14
  function buildErrorMappers() {
8
15
  return /* @__PURE__ */ new Map([["odb_render_report", (error) => {
9
16
  if (!(error instanceof OdbReportNotSpecifiedError)) return void 0;
10
17
  return {
11
- status: 400,
18
+ status: HTTP_STATUS.badRequest,
12
19
  body: {
13
20
  error: error.message,
14
21
  availableReports: error.availableReports
@@ -17,7 +24,7 @@ function buildErrorMappers() {
17
24
  }], ["odm_to_pdf", (error) => {
18
25
  if (!(error instanceof OdmUnresolvedSectionError)) return void 0;
19
26
  return {
20
- status: 400,
27
+ status: HTTP_STATUS.badRequest,
21
28
  body: {
22
29
  error: `${error.message} Pass chaptersDir containing these files, or an explicit chapters override, for each href.`,
23
30
  hrefs: error.hrefs
@@ -49,26 +56,27 @@ async function handleOperationRequest(req, res, operation) {
49
56
  try {
50
57
  rawBody = await readJsonBody(req);
51
58
  } catch (error) {
52
- sendJson(res, 400, { error: `Request body is not valid JSON: ${error instanceof Error ? error.message : String(error)}` });
59
+ sendJson(res, HTTP_STATUS.badRequest, { error: `Request body is not valid JSON: ${error instanceof Error ? error.message : String(error)}` });
53
60
  return;
54
61
  }
55
62
  const parsed = operation.inputSchema.safeParse(rawBody);
56
63
  if (!parsed.success) {
57
- sendJson(res, 400, {
64
+ sendJson(res, HTTP_STATUS.badRequest, {
58
65
  error: "Request body failed validation.",
59
66
  issues: z.treeifyError(parsed.error)
60
67
  });
61
68
  return;
62
69
  }
63
70
  try {
64
- sendJson(res, 200, { result: await operation.run(parsed.data, { signal: abortSignalFor(res) }) });
71
+ const result = await operation.run(parsed.data, { signal: abortSignalFor(res) });
72
+ sendJson(res, HTTP_STATUS.ok, { result });
65
73
  } catch (error) {
66
74
  const mapped = buildErrorMappers().get(operation.name)?.(error);
67
75
  if (mapped !== void 0) {
68
76
  sendJson(res, mapped.status, mapped.body);
69
77
  return;
70
78
  }
71
- sendJson(res, 400, { error: error instanceof Error ? error.message : String(error) });
79
+ sendJson(res, HTTP_STATUS.badRequest, { error: error instanceof Error ? error.message : String(error) });
72
80
  }
73
81
  }
74
82
  function listOperations() {
@@ -85,22 +93,22 @@ function createRestServer() {
85
93
  return createServer((req, res) => {
86
94
  (async () => {
87
95
  if (req.url === void 0 || req.method === void 0) {
88
- sendJson(res, 400, { error: "Malformed request: no url or method." });
96
+ sendJson(res, HTTP_STATUS.badRequest, { error: "Malformed request: no url or method." });
89
97
  return;
90
98
  }
91
99
  const url = new URL(req.url, "http://localhost");
92
100
  if (url.pathname === "/" && req.method === "GET") {
93
- sendJson(res, 200, listOperations());
101
+ sendJson(res, HTTP_STATUS.ok, listOperations());
94
102
  return;
95
103
  }
96
104
  const name = url.pathname.slice(1);
97
105
  const operation = OPERATIONS_BY_NAME.get(name);
98
106
  if (operation === void 0) {
99
- sendJson(res, 404, { error: `No operation named "${name}". GET / lists every available operation.` });
107
+ sendJson(res, HTTP_STATUS.notFound, { error: `No operation named "${name}". GET / lists every available operation.` });
100
108
  return;
101
109
  }
102
110
  if (req.method !== "POST") {
103
- sendJson(res, 405, { error: `${name} only accepts POST, received ${req.method}.` });
111
+ sendJson(res, HTTP_STATUS.methodNotAllowed, { error: `${name} only accepts POST, received ${req.method}.` });
104
112
  return;
105
113
  }
106
114
  await handleOperationRequest(req, res, operation);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document-rest",
3
- "version": "1.4.89",
3
+ "version": "1.4.91",
4
4
  "description": "A plain REST API server exposing document-operations' conversion, editing, inspection, and .odb operations as JSON-over-HTTP endpoints — one POST route per operation, for a caller with no MCP client and no Node runtime of their own.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -87,8 +87,8 @@
87
87
  "license": "MIT",
88
88
  "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
89
89
  "dependencies": {
90
- "document-operations": "1.1.86",
91
- "documents.js": "14.4.24",
90
+ "document-operations": "1.1.88",
91
+ "documents.js": "14.4.26",
92
92
  "zod": "4.4.3"
93
93
  },
94
94
  "devDependencies": {
@@ -97,7 +97,7 @@
97
97
  "@vitest/coverage-v8": "4.1.11",
98
98
  "eslint": "10.8.1",
99
99
  "husky": "9.1.7",
100
- "odf.js": "11.1.5",
100
+ "odf.js": "11.1.6",
101
101
  "publint": "0.3.22",
102
102
  "semantic-release": "25.0.9",
103
103
  "tsdown": "0.22.14",