@insureco/docman 1.0.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.
@@ -0,0 +1,103 @@
1
+ import { D as DocmanClientConfig, C as CreateHtmlTemplateOptions, H as HtmlTemplate, a as HtmlTemplateListQuery, L as ListResult, U as UpdateHtmlTemplateOptions, b as CreatePdfTemplateOptions, P as PdfTemplate, c as PdfTemplateListQuery, d as PdfField, e as UpdatePdfTemplateOptions, f as CreateTemplateGroupOptions, T as TemplateGroup, g as ListQuery, h as UpdateTemplateGroupOptions, G as GenerateOptions, i as GenerateResult, j as DocmanDocument, k as DocumentVersion, l as PageRange, S as SplitPart } from './types-xbeSIrNB.cjs';
2
+ export { m as ListMeta, n as SourceTemplate, o as TemplateCoordinates, p as TemplateGroupItem } from './types-xbeSIrNB.cjs';
3
+
4
+ declare class DocmanClient {
5
+ private readonly baseUrl;
6
+ private readonly accessTokenFn?;
7
+ private readonly internalKey?;
8
+ private readonly retries;
9
+ private readonly timeoutMs;
10
+ private cachedToken;
11
+ constructor(config: DocmanClientConfig);
12
+ /**
13
+ * Create a client from environment variables.
14
+ *
15
+ * Reads DOCMAN_URL (injected automatically when you declare docman as an
16
+ * internalDependency in catalog-info.yaml). Auth priority:
17
+ * 1. BIO_CLIENT_ID + BIO_CLIENT_SECRET → client_credentials token
18
+ * 2. INTERNAL_SERVICE_KEY → internal key header
19
+ * 3. No auth → local dev / testing
20
+ *
21
+ * catalog-info.yaml:
22
+ * spec:
23
+ * internalDependencies:
24
+ * - service: docman
25
+ * port: 3000
26
+ */
27
+ static fromEnv(): DocmanClient;
28
+ private authHeaders;
29
+ private rawFetch;
30
+ private fetchData;
31
+ private fetchList;
32
+ private buildQuery;
33
+ /** Fetch with FormData body (multipart), return raw binary buffer. */
34
+ private fetchBinary;
35
+ /** POST multipart form and parse the JSON response envelope. */
36
+ private fetchMultipartJson;
37
+ /** PUT multipart form and parse the JSON response envelope. */
38
+ private putMultipartJson;
39
+ createHtmlTemplate(options: CreateHtmlTemplateOptions): Promise<HtmlTemplate>;
40
+ listHtmlTemplates(query?: HtmlTemplateListQuery): Promise<ListResult<HtmlTemplate>>;
41
+ getHtmlTemplate(id: string): Promise<HtmlTemplate>;
42
+ updateHtmlTemplate(id: string, options: UpdateHtmlTemplateOptions): Promise<HtmlTemplate>;
43
+ deleteHtmlTemplate(id: string): Promise<HtmlTemplate>;
44
+ /**
45
+ * Upload a PDF form template.
46
+ * @param file Raw PDF bytes (Buffer or Uint8Array)
47
+ * @param options Name, description, and optional coordinates/isSystem flags
48
+ */
49
+ uploadPdfTemplate(file: Buffer | Uint8Array, options?: CreatePdfTemplateOptions): Promise<PdfTemplate>;
50
+ listPdfTemplates(query?: PdfTemplateListQuery): Promise<ListResult<PdfTemplate>>;
51
+ getPdfTemplate(id: string): Promise<PdfTemplate>;
52
+ getPdfTemplateFields(id: string): Promise<readonly PdfField[]>;
53
+ getPdfTemplateDownloadUrl(id: string): Promise<string>;
54
+ /**
55
+ * Update a PDF template's metadata, and optionally replace the PDF file.
56
+ * @param file If provided, replaces the stored PDF and re-extracts form fields
57
+ */
58
+ updatePdfTemplate(id: string, options: UpdatePdfTemplateOptions, file?: Buffer | Uint8Array): Promise<PdfTemplate>;
59
+ deletePdfTemplate(id: string): Promise<PdfTemplate>;
60
+ createTemplateGroup(options: CreateTemplateGroupOptions): Promise<TemplateGroup>;
61
+ listTemplateGroups(query?: ListQuery): Promise<ListResult<TemplateGroup>>;
62
+ getTemplateGroup(id: string): Promise<TemplateGroup>;
63
+ updateTemplateGroup(id: string, options: UpdateTemplateGroupOptions): Promise<TemplateGroup>;
64
+ deleteTemplateGroup(id: string): Promise<void>;
65
+ /**
66
+ * Generate a document and store it in S3.
67
+ * Returns a presigned download URL and a public share URL.
68
+ */
69
+ generate(options: GenerateOptions): Promise<GenerateResult>;
70
+ /**
71
+ * Generate a document and stream the PDF buffer directly.
72
+ * Nothing is stored — useful for previews or on-the-fly delivery.
73
+ */
74
+ generatePassthrough(options: GenerateOptions): Promise<Buffer>;
75
+ listDocuments(query?: ListQuery): Promise<ListResult<DocmanDocument>>;
76
+ getDocument(id: string): Promise<DocmanDocument>;
77
+ /** Get a presigned S3 download URL for a stored document (1-hour TTL). */
78
+ downloadUrl(id: string): Promise<string>;
79
+ getVersions(id: string): Promise<readonly DocumentVersion[]>;
80
+ /** Re-render a stored document using the original template data. */
81
+ regenerate(id: string): Promise<GenerateResult>;
82
+ /**
83
+ * Merge two or more PDF buffers into a single PDF.
84
+ * Returns the merged PDF as a Buffer.
85
+ */
86
+ merge(buffers: readonly (Buffer | Uint8Array)[]): Promise<Buffer>;
87
+ /**
88
+ * Split a PDF into parts by page ranges.
89
+ * Returns an array of SplitPart with buffer, range, and size info.
90
+ */
91
+ split(buffer: Buffer | Uint8Array, ranges: readonly PageRange[]): Promise<readonly SplitPart[]>;
92
+ /** Get the page count of a PDF buffer. */
93
+ pageCount(buffer: Buffer | Uint8Array): Promise<number>;
94
+ }
95
+
96
+ declare class DocmanError extends Error {
97
+ readonly statusCode: number;
98
+ readonly code?: string | undefined;
99
+ readonly details?: Record<string, unknown> | undefined;
100
+ constructor(message: string, statusCode: number, code?: string | undefined, details?: Record<string, unknown> | undefined);
101
+ }
102
+
103
+ export { CreateHtmlTemplateOptions, CreatePdfTemplateOptions, CreateTemplateGroupOptions, DocmanClient, DocmanClientConfig, DocmanDocument, DocmanError, DocumentVersion, GenerateOptions, GenerateResult, HtmlTemplate, HtmlTemplateListQuery, ListQuery, ListResult, PageRange, PdfField, PdfTemplate, PdfTemplateListQuery, SplitPart, TemplateGroup, UpdateHtmlTemplateOptions, UpdatePdfTemplateOptions, UpdateTemplateGroupOptions };
@@ -0,0 +1,103 @@
1
+ import { D as DocmanClientConfig, C as CreateHtmlTemplateOptions, H as HtmlTemplate, a as HtmlTemplateListQuery, L as ListResult, U as UpdateHtmlTemplateOptions, b as CreatePdfTemplateOptions, P as PdfTemplate, c as PdfTemplateListQuery, d as PdfField, e as UpdatePdfTemplateOptions, f as CreateTemplateGroupOptions, T as TemplateGroup, g as ListQuery, h as UpdateTemplateGroupOptions, G as GenerateOptions, i as GenerateResult, j as DocmanDocument, k as DocumentVersion, l as PageRange, S as SplitPart } from './types-xbeSIrNB.js';
2
+ export { m as ListMeta, n as SourceTemplate, o as TemplateCoordinates, p as TemplateGroupItem } from './types-xbeSIrNB.js';
3
+
4
+ declare class DocmanClient {
5
+ private readonly baseUrl;
6
+ private readonly accessTokenFn?;
7
+ private readonly internalKey?;
8
+ private readonly retries;
9
+ private readonly timeoutMs;
10
+ private cachedToken;
11
+ constructor(config: DocmanClientConfig);
12
+ /**
13
+ * Create a client from environment variables.
14
+ *
15
+ * Reads DOCMAN_URL (injected automatically when you declare docman as an
16
+ * internalDependency in catalog-info.yaml). Auth priority:
17
+ * 1. BIO_CLIENT_ID + BIO_CLIENT_SECRET → client_credentials token
18
+ * 2. INTERNAL_SERVICE_KEY → internal key header
19
+ * 3. No auth → local dev / testing
20
+ *
21
+ * catalog-info.yaml:
22
+ * spec:
23
+ * internalDependencies:
24
+ * - service: docman
25
+ * port: 3000
26
+ */
27
+ static fromEnv(): DocmanClient;
28
+ private authHeaders;
29
+ private rawFetch;
30
+ private fetchData;
31
+ private fetchList;
32
+ private buildQuery;
33
+ /** Fetch with FormData body (multipart), return raw binary buffer. */
34
+ private fetchBinary;
35
+ /** POST multipart form and parse the JSON response envelope. */
36
+ private fetchMultipartJson;
37
+ /** PUT multipart form and parse the JSON response envelope. */
38
+ private putMultipartJson;
39
+ createHtmlTemplate(options: CreateHtmlTemplateOptions): Promise<HtmlTemplate>;
40
+ listHtmlTemplates(query?: HtmlTemplateListQuery): Promise<ListResult<HtmlTemplate>>;
41
+ getHtmlTemplate(id: string): Promise<HtmlTemplate>;
42
+ updateHtmlTemplate(id: string, options: UpdateHtmlTemplateOptions): Promise<HtmlTemplate>;
43
+ deleteHtmlTemplate(id: string): Promise<HtmlTemplate>;
44
+ /**
45
+ * Upload a PDF form template.
46
+ * @param file Raw PDF bytes (Buffer or Uint8Array)
47
+ * @param options Name, description, and optional coordinates/isSystem flags
48
+ */
49
+ uploadPdfTemplate(file: Buffer | Uint8Array, options?: CreatePdfTemplateOptions): Promise<PdfTemplate>;
50
+ listPdfTemplates(query?: PdfTemplateListQuery): Promise<ListResult<PdfTemplate>>;
51
+ getPdfTemplate(id: string): Promise<PdfTemplate>;
52
+ getPdfTemplateFields(id: string): Promise<readonly PdfField[]>;
53
+ getPdfTemplateDownloadUrl(id: string): Promise<string>;
54
+ /**
55
+ * Update a PDF template's metadata, and optionally replace the PDF file.
56
+ * @param file If provided, replaces the stored PDF and re-extracts form fields
57
+ */
58
+ updatePdfTemplate(id: string, options: UpdatePdfTemplateOptions, file?: Buffer | Uint8Array): Promise<PdfTemplate>;
59
+ deletePdfTemplate(id: string): Promise<PdfTemplate>;
60
+ createTemplateGroup(options: CreateTemplateGroupOptions): Promise<TemplateGroup>;
61
+ listTemplateGroups(query?: ListQuery): Promise<ListResult<TemplateGroup>>;
62
+ getTemplateGroup(id: string): Promise<TemplateGroup>;
63
+ updateTemplateGroup(id: string, options: UpdateTemplateGroupOptions): Promise<TemplateGroup>;
64
+ deleteTemplateGroup(id: string): Promise<void>;
65
+ /**
66
+ * Generate a document and store it in S3.
67
+ * Returns a presigned download URL and a public share URL.
68
+ */
69
+ generate(options: GenerateOptions): Promise<GenerateResult>;
70
+ /**
71
+ * Generate a document and stream the PDF buffer directly.
72
+ * Nothing is stored — useful for previews or on-the-fly delivery.
73
+ */
74
+ generatePassthrough(options: GenerateOptions): Promise<Buffer>;
75
+ listDocuments(query?: ListQuery): Promise<ListResult<DocmanDocument>>;
76
+ getDocument(id: string): Promise<DocmanDocument>;
77
+ /** Get a presigned S3 download URL for a stored document (1-hour TTL). */
78
+ downloadUrl(id: string): Promise<string>;
79
+ getVersions(id: string): Promise<readonly DocumentVersion[]>;
80
+ /** Re-render a stored document using the original template data. */
81
+ regenerate(id: string): Promise<GenerateResult>;
82
+ /**
83
+ * Merge two or more PDF buffers into a single PDF.
84
+ * Returns the merged PDF as a Buffer.
85
+ */
86
+ merge(buffers: readonly (Buffer | Uint8Array)[]): Promise<Buffer>;
87
+ /**
88
+ * Split a PDF into parts by page ranges.
89
+ * Returns an array of SplitPart with buffer, range, and size info.
90
+ */
91
+ split(buffer: Buffer | Uint8Array, ranges: readonly PageRange[]): Promise<readonly SplitPart[]>;
92
+ /** Get the page count of a PDF buffer. */
93
+ pageCount(buffer: Buffer | Uint8Array): Promise<number>;
94
+ }
95
+
96
+ declare class DocmanError extends Error {
97
+ readonly statusCode: number;
98
+ readonly code?: string | undefined;
99
+ readonly details?: Record<string, unknown> | undefined;
100
+ constructor(message: string, statusCode: number, code?: string | undefined, details?: Record<string, unknown> | undefined);
101
+ }
102
+
103
+ export { CreateHtmlTemplateOptions, CreatePdfTemplateOptions, CreateTemplateGroupOptions, DocmanClient, DocmanClientConfig, DocmanDocument, DocmanError, DocumentVersion, GenerateOptions, GenerateResult, HtmlTemplate, HtmlTemplateListQuery, ListQuery, ListResult, PageRange, PdfField, PdfTemplate, PdfTemplateListQuery, SplitPart, TemplateGroup, UpdateHtmlTemplateOptions, UpdatePdfTemplateOptions, UpdateTemplateGroupOptions };
package/dist/index.js ADDED
@@ -0,0 +1,443 @@
1
+ import {
2
+ DocmanError
3
+ } from "./chunk-7DJVMOS3.js";
4
+
5
+ // src/client.ts
6
+ var DEFAULT_RETRIES = 2;
7
+ var DEFAULT_TIMEOUT_MS = 15e3;
8
+ var TOKEN_BUFFER_SECONDS = 30;
9
+ function sleep(ms) {
10
+ return new Promise((resolve) => setTimeout(resolve, ms));
11
+ }
12
+ function backoff(attempt) {
13
+ const base = Math.min(1e3 * 2 ** attempt, 5e3);
14
+ return base * (0.5 + Math.random() * 0.5);
15
+ }
16
+ function isTokenExpired(token, bufferSeconds = TOKEN_BUFFER_SECONDS) {
17
+ try {
18
+ const parts = token.split(".");
19
+ if (parts.length !== 3) return true;
20
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
21
+ const now = Math.floor(Date.now() / 1e3);
22
+ return (payload.exp ?? 0) <= now + bufferSeconds;
23
+ } catch {
24
+ return true;
25
+ }
26
+ }
27
+ function extractError(envelope) {
28
+ const err = envelope.error;
29
+ if (typeof err === "object" && err !== null) return err;
30
+ return { code: "REQUEST_ERROR", message: err ?? "Request failed" };
31
+ }
32
+ var DocmanClient = class _DocmanClient {
33
+ baseUrl;
34
+ accessTokenFn;
35
+ internalKey;
36
+ retries;
37
+ timeoutMs;
38
+ cachedToken = null;
39
+ constructor(config) {
40
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
41
+ this.accessTokenFn = config.accessTokenFn;
42
+ this.internalKey = config.internalKey;
43
+ this.retries = config.retries ?? DEFAULT_RETRIES;
44
+ this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
45
+ }
46
+ /**
47
+ * Create a client from environment variables.
48
+ *
49
+ * Reads DOCMAN_URL (injected automatically when you declare docman as an
50
+ * internalDependency in catalog-info.yaml). Auth priority:
51
+ * 1. BIO_CLIENT_ID + BIO_CLIENT_SECRET → client_credentials token
52
+ * 2. INTERNAL_SERVICE_KEY → internal key header
53
+ * 3. No auth → local dev / testing
54
+ *
55
+ * catalog-info.yaml:
56
+ * spec:
57
+ * internalDependencies:
58
+ * - service: docman
59
+ * port: 3000
60
+ */
61
+ static fromEnv() {
62
+ const baseUrl = process.env.DOCMAN_URL;
63
+ if (!baseUrl) {
64
+ throw new DocmanError(
65
+ "DOCMAN_URL is not set. Add docman as an internalDependency in catalog-info.yaml",
66
+ 500,
67
+ "CONFIG_ERROR"
68
+ );
69
+ }
70
+ const clientId = process.env.BIO_CLIENT_ID;
71
+ const clientSecret = process.env.BIO_CLIENT_SECRET;
72
+ const bioIdUrl = process.env.BIO_ID_URL ?? "https://bio.tawa.insureco.io";
73
+ if (clientId && clientSecret) {
74
+ return new _DocmanClient({
75
+ baseUrl,
76
+ accessTokenFn: async () => {
77
+ const res = await fetch(`${bioIdUrl}/api/oauth/token`, {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/json" },
80
+ body: JSON.stringify({
81
+ grant_type: "client_credentials",
82
+ client_id: clientId,
83
+ client_secret: clientSecret
84
+ })
85
+ });
86
+ if (!res.ok) {
87
+ throw new DocmanError("Failed to obtain Bio-ID access token", res.status, "AUTH_ERROR");
88
+ }
89
+ const data = await res.json();
90
+ return data.access_token;
91
+ }
92
+ });
93
+ }
94
+ const internalKey = process.env.INTERNAL_SERVICE_KEY;
95
+ if (internalKey) {
96
+ return new _DocmanClient({ baseUrl, internalKey });
97
+ }
98
+ return new _DocmanClient({ baseUrl });
99
+ }
100
+ // ─── Auth ────────────────────────────────────────────────
101
+ async authHeaders() {
102
+ if (this.accessTokenFn) {
103
+ if (!this.cachedToken || isTokenExpired(this.cachedToken)) {
104
+ this.cachedToken = await this.accessTokenFn();
105
+ }
106
+ return { Authorization: `Bearer ${this.cachedToken}` };
107
+ }
108
+ if (this.internalKey) {
109
+ return { "X-Internal-Key": this.internalKey };
110
+ }
111
+ return {};
112
+ }
113
+ // ─── Core fetch ──────────────────────────────────────────
114
+ async rawFetch(method, path, body, attempt = 0) {
115
+ const headers = await this.authHeaders();
116
+ const controller = new AbortController();
117
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
118
+ let response;
119
+ try {
120
+ response = await fetch(`${this.baseUrl}${path}`, {
121
+ method,
122
+ headers: body !== void 0 ? { ...headers, "Content-Type": "application/json" } : headers,
123
+ body: body !== void 0 ? JSON.stringify(body) : void 0,
124
+ signal: controller.signal
125
+ });
126
+ } catch (err) {
127
+ clearTimeout(timer);
128
+ if (attempt < this.retries) {
129
+ await sleep(backoff(attempt));
130
+ return this.rawFetch(method, path, body, attempt + 1);
131
+ }
132
+ throw new DocmanError(`Network error: ${err.message}`, 0, "NETWORK_ERROR");
133
+ } finally {
134
+ clearTimeout(timer);
135
+ }
136
+ if (response.status >= 500 && attempt < this.retries) {
137
+ await sleep(backoff(attempt));
138
+ return this.rawFetch(method, path, body, attempt + 1);
139
+ }
140
+ const envelope = await response.json();
141
+ if (!response.ok || !envelope.success) {
142
+ const { code, message } = extractError(envelope);
143
+ throw new DocmanError(message, response.status, code);
144
+ }
145
+ return envelope;
146
+ }
147
+ async fetchData(method, path, body) {
148
+ const envelope = await this.rawFetch(method, path, body);
149
+ return envelope.data;
150
+ }
151
+ async fetchList(path) {
152
+ const envelope = await this.rawFetch("GET", path);
153
+ return {
154
+ data: envelope.data ?? [],
155
+ meta: envelope.meta ?? { total: 0, page: 1, limit: 20 }
156
+ };
157
+ }
158
+ buildQuery(params) {
159
+ const pairs = Object.entries(params).filter(([, v]) => v !== void 0).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
160
+ return pairs.length > 0 ? `?${pairs.join("&")}` : "";
161
+ }
162
+ /** Fetch with FormData body (multipart), return raw binary buffer. */
163
+ async fetchBinary(method, path, formData, attempt = 0) {
164
+ const headers = await this.authHeaders();
165
+ const controller = new AbortController();
166
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
167
+ let response;
168
+ try {
169
+ response = await fetch(`${this.baseUrl}${path}`, {
170
+ method,
171
+ headers,
172
+ body: formData,
173
+ signal: controller.signal
174
+ });
175
+ } catch (err) {
176
+ clearTimeout(timer);
177
+ if (attempt < this.retries) {
178
+ await sleep(backoff(attempt));
179
+ return this.fetchBinary(method, path, formData, attempt + 1);
180
+ }
181
+ throw new DocmanError(`Network error: ${err.message}`, 0, "NETWORK_ERROR");
182
+ } finally {
183
+ clearTimeout(timer);
184
+ }
185
+ if (response.status >= 500 && attempt < this.retries) {
186
+ await sleep(backoff(attempt));
187
+ return this.fetchBinary(method, path, formData, attempt + 1);
188
+ }
189
+ if (!response.ok) {
190
+ const envelope = await response.json();
191
+ const { code, message } = extractError(envelope);
192
+ throw new DocmanError(message, response.status, code);
193
+ }
194
+ return Buffer.from(await response.arrayBuffer());
195
+ }
196
+ /** POST multipart form and parse the JSON response envelope. */
197
+ async fetchMultipartJson(path, formData) {
198
+ const headers = await this.authHeaders();
199
+ const response = await fetch(`${this.baseUrl}${path}`, {
200
+ method: "POST",
201
+ headers,
202
+ body: formData
203
+ });
204
+ const envelope = await response.json();
205
+ if (!response.ok || !envelope.success) {
206
+ const { code, message } = extractError(envelope);
207
+ throw new DocmanError(message, response.status, code);
208
+ }
209
+ return envelope.data;
210
+ }
211
+ /** PUT multipart form and parse the JSON response envelope. */
212
+ async putMultipartJson(path, formData) {
213
+ const headers = await this.authHeaders();
214
+ const response = await fetch(`${this.baseUrl}${path}`, {
215
+ method: "PUT",
216
+ headers,
217
+ body: formData
218
+ });
219
+ const envelope = await response.json();
220
+ if (!response.ok || !envelope.success) {
221
+ const { code, message } = extractError(envelope);
222
+ throw new DocmanError(message, response.status, code);
223
+ }
224
+ return envelope.data;
225
+ }
226
+ // ─── HTML Templates ──────────────────────────────────────
227
+ async createHtmlTemplate(options) {
228
+ return this.fetchData("POST", "/templates/html", options);
229
+ }
230
+ async listHtmlTemplates(query = {}) {
231
+ return this.fetchList(`/templates/html${this.buildQuery(query)}`);
232
+ }
233
+ async getHtmlTemplate(id) {
234
+ return this.fetchData("GET", `/templates/html/${encodeURIComponent(id)}`);
235
+ }
236
+ async updateHtmlTemplate(id, options) {
237
+ return this.fetchData("PUT", `/templates/html/${encodeURIComponent(id)}`, options);
238
+ }
239
+ async deleteHtmlTemplate(id) {
240
+ return this.fetchData("DELETE", `/templates/html/${encodeURIComponent(id)}`);
241
+ }
242
+ // ─── PDF Templates ───────────────────────────────────────
243
+ /**
244
+ * Upload a PDF form template.
245
+ * @param file Raw PDF bytes (Buffer or Uint8Array)
246
+ * @param options Name, description, and optional coordinates/isSystem flags
247
+ */
248
+ async uploadPdfTemplate(file, options = {}) {
249
+ const form = new FormData();
250
+ const filename = options.name ?? "template.pdf";
251
+ form.append("file", new Blob([file], { type: "application/pdf" }), filename);
252
+ if (options.name) form.append("name", options.name);
253
+ if (options.description) form.append("description", options.description);
254
+ if (options.coordinates) form.append("coordinates", JSON.stringify(options.coordinates));
255
+ if (options.isSystem !== void 0) form.append("isSystem", String(options.isSystem));
256
+ return this.fetchMultipartJson("/templates/pdf", form);
257
+ }
258
+ async listPdfTemplates(query = {}) {
259
+ return this.fetchList(`/templates/pdf${this.buildQuery(query)}`);
260
+ }
261
+ async getPdfTemplate(id) {
262
+ return this.fetchData("GET", `/templates/pdf/${encodeURIComponent(id)}`);
263
+ }
264
+ async getPdfTemplateFields(id) {
265
+ return this.fetchData("GET", `/templates/pdf/${encodeURIComponent(id)}/fields`);
266
+ }
267
+ async getPdfTemplateDownloadUrl(id) {
268
+ const data = await this.fetchData("GET", `/templates/pdf/${encodeURIComponent(id)}/download`);
269
+ return data.url;
270
+ }
271
+ /**
272
+ * Update a PDF template's metadata, and optionally replace the PDF file.
273
+ * @param file If provided, replaces the stored PDF and re-extracts form fields
274
+ */
275
+ async updatePdfTemplate(id, options, file) {
276
+ if (file) {
277
+ const form = new FormData();
278
+ form.append("file", new Blob([file], { type: "application/pdf" }), "template.pdf");
279
+ if (options.name) form.append("name", options.name);
280
+ if (options.description) form.append("description", options.description);
281
+ if (options.coordinates) form.append("coordinates", JSON.stringify(options.coordinates));
282
+ return this.putMultipartJson(`/templates/pdf/${encodeURIComponent(id)}`, form);
283
+ }
284
+ return this.fetchData("PUT", `/templates/pdf/${encodeURIComponent(id)}`, options);
285
+ }
286
+ async deletePdfTemplate(id) {
287
+ return this.fetchData("DELETE", `/templates/pdf/${encodeURIComponent(id)}`);
288
+ }
289
+ // ─── Template Groups ─────────────────────────────────────
290
+ async createTemplateGroup(options) {
291
+ return this.fetchData("POST", "/template-groups", options);
292
+ }
293
+ async listTemplateGroups(query = {}) {
294
+ return this.fetchList(`/template-groups${this.buildQuery(query)}`);
295
+ }
296
+ async getTemplateGroup(id) {
297
+ return this.fetchData("GET", `/template-groups/${encodeURIComponent(id)}`);
298
+ }
299
+ async updateTemplateGroup(id, options) {
300
+ return this.fetchData("PUT", `/template-groups/${encodeURIComponent(id)}`, options);
301
+ }
302
+ async deleteTemplateGroup(id) {
303
+ await this.fetchData("DELETE", `/template-groups/${encodeURIComponent(id)}`);
304
+ }
305
+ // ─── Document Generation ─────────────────────────────────
306
+ /**
307
+ * Generate a document and store it in S3.
308
+ * Returns a presigned download URL and a public share URL.
309
+ */
310
+ async generate(options) {
311
+ return this.fetchData("POST", "/documents/generate", {
312
+ templateIds: options.templateIds,
313
+ templateData: options.data,
314
+ name: options.name,
315
+ description: options.description
316
+ });
317
+ }
318
+ /**
319
+ * Generate a document and stream the PDF buffer directly.
320
+ * Nothing is stored — useful for previews or on-the-fly delivery.
321
+ */
322
+ async generatePassthrough(options) {
323
+ const headers = await this.authHeaders();
324
+ const controller = new AbortController();
325
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
326
+ let response;
327
+ try {
328
+ response = await fetch(`${this.baseUrl}/documents/generate/passthrough`, {
329
+ method: "POST",
330
+ headers: { ...headers, "Content-Type": "application/json" },
331
+ body: JSON.stringify({
332
+ templateIds: options.templateIds,
333
+ templateData: options.data,
334
+ name: options.name,
335
+ description: options.description
336
+ }),
337
+ signal: controller.signal
338
+ });
339
+ } catch (err) {
340
+ clearTimeout(timer);
341
+ throw new DocmanError(`Network error: ${err.message}`, 0, "NETWORK_ERROR");
342
+ } finally {
343
+ clearTimeout(timer);
344
+ }
345
+ if (!response.ok) {
346
+ const envelope = await response.json();
347
+ const { code, message } = extractError(envelope);
348
+ throw new DocmanError(message, response.status, code);
349
+ }
350
+ return Buffer.from(await response.arrayBuffer());
351
+ }
352
+ async listDocuments(query = {}) {
353
+ return this.fetchList(`/documents${this.buildQuery(query)}`);
354
+ }
355
+ async getDocument(id) {
356
+ return this.fetchData("GET", `/documents/${encodeURIComponent(id)}`);
357
+ }
358
+ /** Get a presigned S3 download URL for a stored document (1-hour TTL). */
359
+ async downloadUrl(id) {
360
+ const data = await this.fetchData("GET", `/documents/${encodeURIComponent(id)}/download`);
361
+ return data.url;
362
+ }
363
+ async getVersions(id) {
364
+ return this.fetchData("GET", `/documents/${encodeURIComponent(id)}/versions`);
365
+ }
366
+ /** Re-render a stored document using the original template data. */
367
+ async regenerate(id) {
368
+ return this.fetchData("POST", `/documents/${encodeURIComponent(id)}/regenerate`);
369
+ }
370
+ // ─── PDF Operations ──────────────────────────────────────
371
+ /**
372
+ * Merge two or more PDF buffers into a single PDF.
373
+ * Returns the merged PDF as a Buffer.
374
+ */
375
+ async merge(buffers) {
376
+ if (buffers.length < 2) {
377
+ throw new DocmanError("At least 2 PDF buffers are required for merge", 400, "VALIDATION_ERROR");
378
+ }
379
+ const form = new FormData();
380
+ for (const buf of buffers) {
381
+ form.append("files", new Blob([buf], { type: "application/pdf" }), "file.pdf");
382
+ }
383
+ return this.fetchBinary("POST", "/operations/merge", form);
384
+ }
385
+ /**
386
+ * Split a PDF into parts by page ranges.
387
+ * Returns an array of SplitPart with buffer, range, and size info.
388
+ */
389
+ async split(buffer, ranges) {
390
+ if (ranges.length === 0) {
391
+ throw new DocmanError("At least 1 page range is required", 400, "VALIDATION_ERROR");
392
+ }
393
+ const form = new FormData();
394
+ form.append("file", new Blob([buffer], { type: "application/pdf" }), "file.pdf");
395
+ form.append("ranges", JSON.stringify(ranges));
396
+ const headers = await this.authHeaders();
397
+ const response = await fetch(`${this.baseUrl}/operations/split`, {
398
+ method: "POST",
399
+ headers,
400
+ body: form
401
+ });
402
+ if (!response.ok) {
403
+ const envelope = await response.json();
404
+ const { code, message } = extractError(envelope);
405
+ throw new DocmanError(message, response.status, code);
406
+ }
407
+ const contentType = response.headers.get("content-type") ?? "";
408
+ if (contentType.includes("application/json")) {
409
+ const json = await response.json();
410
+ return json.data.map((part) => ({
411
+ index: part.index,
412
+ range: part.range,
413
+ buffer: Buffer.from(part.base64, "base64"),
414
+ sizeBytes: part.sizeBytes
415
+ }));
416
+ }
417
+ const buf = Buffer.from(await response.arrayBuffer());
418
+ return [{ index: 0, range: ranges[0], buffer: buf, sizeBytes: buf.length }];
419
+ }
420
+ /** Get the page count of a PDF buffer. */
421
+ async pageCount(buffer) {
422
+ const form = new FormData();
423
+ form.append("file", new Blob([buffer], { type: "application/pdf" }), "file.pdf");
424
+ const headers = await this.authHeaders();
425
+ const response = await fetch(`${this.baseUrl}/operations/page-count`, {
426
+ method: "POST",
427
+ headers,
428
+ body: form
429
+ });
430
+ if (!response.ok) {
431
+ const envelope = await response.json();
432
+ const { code, message } = extractError(envelope);
433
+ throw new DocmanError(message, response.status, code);
434
+ }
435
+ const json = await response.json();
436
+ return json.data.pages;
437
+ }
438
+ };
439
+ export {
440
+ DocmanClient,
441
+ DocmanError
442
+ };
443
+ //# sourceMappingURL=index.js.map