@c9up/vellum 0.1.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/LICENSE +21 -0
- package/README.md +473 -0
- package/dist/Vellum.d.ts +460 -0
- package/dist/Vellum.d.ts.map +1 -0
- package/dist/Vellum.js +479 -0
- package/dist/Vellum.js.map +1 -0
- package/dist/VellumProvider.d.ts +28 -0
- package/dist/VellumProvider.d.ts.map +1 -0
- package/dist/VellumProvider.js +33 -0
- package/dist/VellumProvider.js.map +1 -0
- package/dist/augmentations.d.ts +22 -0
- package/dist/augmentations.d.ts.map +1 -0
- package/dist/augmentations.js +16 -0
- package/dist/augmentations.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +31 -0
- package/dist/config.js.map +1 -0
- package/dist/configure.d.ts +17 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +78 -0
- package/dist/configure.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +19 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/native/generated.d.ts +255 -0
- package/dist/native/generated.d.ts.map +1 -0
- package/dist/native/generated.js +7 -0
- package/dist/native/generated.js.map +1 -0
- package/dist/native.d.ts +50 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +194 -0
- package/dist/native.js.map +1 -0
- package/dist/responder.d.ts +29 -0
- package/dist/responder.d.ts.map +1 -0
- package/dist/responder.js +101 -0
- package/dist/responder.js.map +1 -0
- package/dist/services/main.d.ts +15 -0
- package/dist/services/main.d.ts.map +1 -0
- package/dist/services/main.js +39 -0
- package/dist/services/main.js.map +1 -0
- package/dist/signers.d.ts +81 -0
- package/dist/signers.d.ts.map +1 -0
- package/dist/signers.js +98 -0
- package/dist/signers.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +67 -0
- package/scripts/build-napi-types.mjs +69 -0
- package/scripts/copy-napi.mjs +48 -0
- package/scripts/generate-metrics.py +150 -0
- package/scripts/generate-napi-types.mjs +156 -0
- package/src/Vellum.ts +829 -0
- package/src/VellumProvider.ts +51 -0
- package/src/augmentations.ts +25 -0
- package/src/config.ts +47 -0
- package/src/configure.ts +92 -0
- package/src/errors.ts +20 -0
- package/src/index.ts +74 -0
- package/src/native/generated.ts +375 -0
- package/src/native.ts +358 -0
- package/src/responder.ts +116 -0
- package/src/services/main.ts +48 -0
- package/src/signers.ts +149 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wires `config/vellum.ts` into the container.
|
|
3
|
+
*
|
|
4
|
+
* Vellum does not import `@c9up/ream`: the slice of the host it needs is
|
|
5
|
+
* duck-typed below, which is what keeps the package publishable on its own and
|
|
6
|
+
* usable from a host that is not Ream.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { setVellum } from "./services/main.js";
|
|
10
|
+
import "./augmentations.js";
|
|
11
|
+
import type { VellumConfig } from "./Vellum.js";
|
|
12
|
+
import { Vellum } from "./Vellum.js";
|
|
13
|
+
|
|
14
|
+
interface VellumContainer {
|
|
15
|
+
singleton(token: unknown, factory: () => unknown): void;
|
|
16
|
+
resolve<T = unknown>(token: unknown): Promise<T>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface VellumConfigStore {
|
|
20
|
+
get<T = unknown>(key: string): T | undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface VellumAppContext {
|
|
24
|
+
container: VellumContainer;
|
|
25
|
+
config: VellumConfigStore;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default class VellumProvider {
|
|
29
|
+
constructor(protected app: VellumAppContext) {}
|
|
30
|
+
|
|
31
|
+
register(): void {
|
|
32
|
+
this.app.container.singleton(Vellum, () => {
|
|
33
|
+
// An absent config is not an error: every rendering option has a
|
|
34
|
+
// defensible default, so a provider registered without
|
|
35
|
+
// `config/vellum.ts` still renders PNG at natural size.
|
|
36
|
+
const config = this.app.config.get<VellumConfig>("vellum") ?? {};
|
|
37
|
+
return new Vellum(config);
|
|
38
|
+
});
|
|
39
|
+
// String alias, so a consumer that cannot import Vellum still resolves
|
|
40
|
+
// it — the same convention the other providers follow.
|
|
41
|
+
this.app.container.singleton("vellum", () =>
|
|
42
|
+
this.app.container.resolve<Vellum>(Vellum),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async boot(): Promise<void> {
|
|
47
|
+
setVellum(await this.app.container.resolve<Vellum>(Vellum));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async shutdown(): Promise<void> {}
|
|
51
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Teach ream's `ContainerBindings` what `container.make('vellum')` returns.
|
|
3
|
+
*
|
|
4
|
+
* ream declares that interface open on purpose: it registers its own entries
|
|
5
|
+
* and expects each package to contribute its own — the comment on the
|
|
6
|
+
* interface names `auth` (warden), `logger` (spectrum) and `db` (atlas) as
|
|
7
|
+
* exactly this. Without the augmentation, resolving by the string token falls
|
|
8
|
+
* back to `unknown` and every call site has to assert a type it cannot prove.
|
|
9
|
+
*
|
|
10
|
+
* AdonisJS does the same from its own packages' providers.
|
|
11
|
+
*
|
|
12
|
+
* Loaded from the package barrel and from the provider, so registering vellum
|
|
13
|
+
* is enough — an application writes no `declare module` of its own.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Referenced so the augmentation below resolves the module it augments.
|
|
17
|
+
import type {} from "@c9up/ream/types";
|
|
18
|
+
import type { Vellum } from "./Vellum.js";
|
|
19
|
+
|
|
20
|
+
declare module "@c9up/ream/types" {
|
|
21
|
+
interface ContainerBindings {
|
|
22
|
+
/** The PDF service, bound by `VellumProvider`. */
|
|
23
|
+
vellum: Vellum;
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ImageFormat, VellumConfig } from "./Vellum.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The config as it is WRITTEN, before validation.
|
|
5
|
+
*
|
|
6
|
+
* `format` is a plain string here because that is what an environment yields:
|
|
7
|
+
* `env.get('VELLUM_FORMAT', 'png')` is a `string`, and a config that only
|
|
8
|
+
* accepted the union could not read one — the generated `config/vellum.ts` did
|
|
9
|
+
* not typecheck in the project it was written into.
|
|
10
|
+
*/
|
|
11
|
+
export interface VellumConfigInput extends Omit<VellumConfig, "format"> {
|
|
12
|
+
format?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Define the rendering defaults, in `config/vellum.ts`.
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { defineConfig } from '@c9up/vellum'
|
|
20
|
+
*
|
|
21
|
+
* export default defineConfig({
|
|
22
|
+
* format: 'jpeg',
|
|
23
|
+
* quality: 82,
|
|
24
|
+
* width: 1200,
|
|
25
|
+
* })
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Named deviation: there is no `default` + service list here, because there is
|
|
29
|
+
* one rendering engine rather than several. Should a second one ever exist,
|
|
30
|
+
* that is when the manager gains `use()` — not before, when it would only be
|
|
31
|
+
* an indirection over a single implementation.
|
|
32
|
+
*/
|
|
33
|
+
export function defineConfig(config: VellumConfigInput): VellumConfig {
|
|
34
|
+
const { format, ...rest } = config;
|
|
35
|
+
if (format === undefined) return rest;
|
|
36
|
+
if (format !== "png" && format !== "jpeg") {
|
|
37
|
+
// Named at boot, with the value, rather than at the first render of a
|
|
38
|
+
// document nobody was looking at.
|
|
39
|
+
throw new Error(
|
|
40
|
+
`[vellum] config/vellum.ts asks for format ${JSON.stringify(format)}; ` +
|
|
41
|
+
'it is "png" or "jpeg".',
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return { ...rest, format: format as ImageFormat };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type { VellumConfig };
|
package/src/configure.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ream configure @c9up/vellum` — wire PDF rendering in one command.
|
|
3
|
+
*
|
|
4
|
+
* The provider alone is not enough: it reads `config/vellum.ts`, and a package
|
|
5
|
+
* registered without one renders with defaults the application never chose.
|
|
6
|
+
* Writing both together is what makes `ream add` mean installed AND working.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
interface Codemods {
|
|
10
|
+
addProvider(importPath: string): Promise<void>;
|
|
11
|
+
addEnvVars(vars: Record<string, string>): Promise<void>;
|
|
12
|
+
writeFile(
|
|
13
|
+
filePath: string,
|
|
14
|
+
content: string,
|
|
15
|
+
options?: { force?: boolean },
|
|
16
|
+
): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function configure(codemods: Codemods): Promise<void> {
|
|
20
|
+
// The config below reads these, so they are declared here. Writing the file
|
|
21
|
+
// without them leaves an application whose config asks the environment for
|
|
22
|
+
// something nothing ever put there.
|
|
23
|
+
await codemods.addEnvVars({
|
|
24
|
+
VELLUM_FORMAT: "png",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await codemods.addProvider("@c9up/vellum/provider");
|
|
28
|
+
await codemods.writeFile(
|
|
29
|
+
"config/vellum.ts",
|
|
30
|
+
`import { defineConfig } from '@c9up/vellum'
|
|
31
|
+
import env from '#start/env'
|
|
32
|
+
|
|
33
|
+
export default defineConfig({
|
|
34
|
+
// Defaults for every render. Any call can override them.
|
|
35
|
+
format: env.get('VELLUM_FORMAT', 'png'),
|
|
36
|
+
|
|
37
|
+
// 1 is 72 DPI — the page's natural size. Raise it for print, or set
|
|
38
|
+
// \`width\` instead when what matters is the pixel width of a preview.
|
|
39
|
+
scale: 1,
|
|
40
|
+
|
|
41
|
+
// Only read when the format is 'jpeg'.
|
|
42
|
+
quality: 82,
|
|
43
|
+
|
|
44
|
+
// A PDF paints no background of its own, so rendering it transparent
|
|
45
|
+
// makes black text invisible over a dark viewer.
|
|
46
|
+
background: '#ffffff',
|
|
47
|
+
|
|
48
|
+
// Fonts to write text with, by the name you ask for them by. A font
|
|
49
|
+
// declared here is embedded in the document, subsetted to the characters
|
|
50
|
+
// written, which lifts the WinAnsi limit of the standard fonts.
|
|
51
|
+
//
|
|
52
|
+
// fonts: {
|
|
53
|
+
// body: app.makePath('resources/fonts/Inter-Regular.ttf'),
|
|
54
|
+
// },
|
|
55
|
+
|
|
56
|
+
// Who may sign a document. A signer is handed the digest of what the
|
|
57
|
+
// signature covers and returns the CMS to embed — it never sees the
|
|
58
|
+
// document, which is what makes a key you hold and a key held by a
|
|
59
|
+
// certified provider the same interface.
|
|
60
|
+
//
|
|
61
|
+
// Wrap a signer in timestamped() to add a trusted timestamp, without which
|
|
62
|
+
// a signature stops being verifiable once its certificate expires.
|
|
63
|
+
//
|
|
64
|
+
// signers: {
|
|
65
|
+
// internal: pkcs8Signer({
|
|
66
|
+
// key: readFileSync(app.makePath('storage/signing.key.der')),
|
|
67
|
+
// certificate: readFileSync(app.makePath('storage/signing.crt.der')),
|
|
68
|
+
// }),
|
|
69
|
+
// stamped: timestamped(pkcs8Signer({ ... }), {
|
|
70
|
+
// url: 'https://freetsa.org/tsr',
|
|
71
|
+
// }),
|
|
72
|
+
// qualified: myProviderAdapter({ ... }),
|
|
73
|
+
// },
|
|
74
|
+
|
|
75
|
+
// Certificates to trust when CHECKING a signature — typically the roots
|
|
76
|
+
// your jurisdiction's supervisory body publishes as a trusted list. With
|
|
77
|
+
// none, every signature comes back untrusted, which is the honest answer.
|
|
78
|
+
//
|
|
79
|
+
// trustedAnchors: [
|
|
80
|
+
// readFileSync(app.makePath('storage/anchors/authority.pem')),
|
|
81
|
+
// ],
|
|
82
|
+
|
|
83
|
+
// Which revocation responders may be contacted when checkRevocation is
|
|
84
|
+
// asked for. The address comes out of the certificate inside the document
|
|
85
|
+
// being checked, so by default only public hosts are asked — a document
|
|
86
|
+
// does not get to point this server at your own network. Name yours here
|
|
87
|
+
// when your authority answers somewhere that rule excludes.
|
|
88
|
+
//
|
|
89
|
+
// allowedResponders: ['ocsp.internal.example'],
|
|
90
|
+
})`,
|
|
91
|
+
);
|
|
92
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VellumError — structured error for PDF operations.
|
|
3
|
+
*/
|
|
4
|
+
export class VellumError extends Error {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
|
|
7
|
+
constructor(code: string, message: string, options?: ErrorOptions) {
|
|
8
|
+
super(message, options);
|
|
9
|
+
this.name = "VellumError";
|
|
10
|
+
// One namespace, one prefix. `E_` is what every framework code carries,
|
|
11
|
+
// and the package name after it says which package raised it. A code
|
|
12
|
+
// that already starts with `E_` passes through untouched, so a shared
|
|
13
|
+
// identifier keeps its exact spelling.
|
|
14
|
+
this.code = code.startsWith("E_") ? code : `E_VELLUM_${code}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
override toString(): string {
|
|
18
|
+
return `${this.name} [${this.code}]: ${this.message}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @c9up/vellum — PDF toolkit.
|
|
3
|
+
*
|
|
4
|
+
* Rendering pages to images, reading text and metadata, reshaping documents,
|
|
5
|
+
* stamping them, filling and flattening their forms, and signing them. The
|
|
6
|
+
* engine is Rust behind NAPI, because PDF has no adequate JavaScript
|
|
7
|
+
* implementation — a capability the platform lacks, not an optimisation.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import vellum from '@c9up/vellum/services/main'
|
|
11
|
+
*
|
|
12
|
+
* const preview = await vellum.render(pdf, { page: 1, width: 1200 })
|
|
13
|
+
* const pages = await vellum.renderAll(pdf, { format: 'jpeg' })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import "./augmentations.js";
|
|
18
|
+
|
|
19
|
+
export { defineConfig } from "./config.js";
|
|
20
|
+
export { VellumError } from "./errors.js";
|
|
21
|
+
export type {
|
|
22
|
+
DocumentInfo,
|
|
23
|
+
DocumentMetadata,
|
|
24
|
+
FormField,
|
|
25
|
+
PageDimensions,
|
|
26
|
+
PageSize,
|
|
27
|
+
RevocationAnswer,
|
|
28
|
+
SignatureReport,
|
|
29
|
+
} from "./native.js";
|
|
30
|
+
export { isNativeAvailable, VellumNativeRequiredError } from "./native.js";
|
|
31
|
+
export type { ResponderPolicy } from "./responder.js";
|
|
32
|
+
export type { Pkcs8SignerOptions, TimestampOptions } from "./signers.js";
|
|
33
|
+
export { pkcs8Signer, timestamped } from "./signers.js";
|
|
34
|
+
export type {
|
|
35
|
+
CheckedSignature,
|
|
36
|
+
ImageFormat,
|
|
37
|
+
PageOptions,
|
|
38
|
+
RenderOptions,
|
|
39
|
+
Signer,
|
|
40
|
+
SignOptions,
|
|
41
|
+
StampOptions,
|
|
42
|
+
StandardFont,
|
|
43
|
+
TextStampOptions,
|
|
44
|
+
VellumConfig,
|
|
45
|
+
VerifyOptions,
|
|
46
|
+
} from "./Vellum.js";
|
|
47
|
+
export { Vellum } from "./Vellum.js";
|
|
48
|
+
|
|
49
|
+
import type { DocumentInfo, PageSize } from "./native.js";
|
|
50
|
+
import { createBlankNative, inspectNative } from "./native.js";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Report the shape of a PDF: how many pages it has, which version of the
|
|
54
|
+
* format it claims, and whether it is encrypted.
|
|
55
|
+
*
|
|
56
|
+
* The `/Info` strings are read by {@link Vellum.metadata} instead, which has
|
|
57
|
+
* the decoder they need: they are stored in UTF-16BE, UTF-8 or
|
|
58
|
+
* PDFDocEncoding, and guessing between them mangles every accent.
|
|
59
|
+
*/
|
|
60
|
+
export function inspect(pdf: Buffer): DocumentInfo {
|
|
61
|
+
return inspectNative(pdf);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Author a document of blank pages, sized in points (72 per inch).
|
|
66
|
+
*
|
|
67
|
+
* Draw onto them with {@link Vellum.stamp} and {@link Vellum.stampText}.
|
|
68
|
+
*/
|
|
69
|
+
export function createBlank(pages: ReadonlyArray<PageSize>): Buffer {
|
|
70
|
+
return createBlankNative(pages);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** A4 in points, the size every document here starts from. */
|
|
74
|
+
export const A4: PageSize = { width: 595.28, height: 841.89 };
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
// GENERATED FROM THE RUST — do not edit.
|
|
2
|
+
//
|
|
3
|
+
// Produced by scripts/generate-napi-types.mjs from napi-derive's type-def
|
|
4
|
+
// output. Editing this file by hand puts it back where it started: a
|
|
5
|
+
// description that can disagree with the code it describes.
|
|
6
|
+
|
|
7
|
+
export interface DocumentInfo {
|
|
8
|
+
pageCount: number;
|
|
9
|
+
version: string;
|
|
10
|
+
encrypted: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface PageSize {
|
|
14
|
+
/** Width in points (72 per inch). A4 is 595.28. */
|
|
15
|
+
width: number;
|
|
16
|
+
/** Height in points. A4 is 841.89. */
|
|
17
|
+
height: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Rasterising options, as a plain JavaScript object. */
|
|
21
|
+
|
|
22
|
+
export interface RenderOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Multiplier over the page's natural size, 1 being 72 DPI. Default 1.
|
|
25
|
+
* Ignored when `width` is given.
|
|
26
|
+
*/
|
|
27
|
+
scale?: number;
|
|
28
|
+
/** Target width in pixels. Wins over `scale`. */
|
|
29
|
+
width?: number;
|
|
30
|
+
/** `"png"` (default) or `"jpeg"`. */
|
|
31
|
+
format?: string;
|
|
32
|
+
/** JPEG quality, 1-100. Only valid alongside `format: "jpeg"`. */
|
|
33
|
+
quality?: number;
|
|
34
|
+
/** `#rgb`, `#rrggbb`, `#rrggbbaa` or `"transparent"`. Default opaque white. */
|
|
35
|
+
background?: string;
|
|
36
|
+
/**
|
|
37
|
+
* The most pixels one page may rasterise to. 50 million by default —
|
|
38
|
+
* room for A4 at 600 DPI. A page declares its own size, so without a
|
|
39
|
+
* ceiling a document alone could ask for gigabytes.
|
|
40
|
+
*/
|
|
41
|
+
maxPixels?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PageDimensions {
|
|
45
|
+
/** Width in points, before scaling. */
|
|
46
|
+
width: number;
|
|
47
|
+
/** Height in points, before scaling. */
|
|
48
|
+
height: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** What the `/Info` dictionary says about a document. */
|
|
52
|
+
|
|
53
|
+
export interface DocumentMetadata {
|
|
54
|
+
title?: string;
|
|
55
|
+
author?: string;
|
|
56
|
+
subject?: string;
|
|
57
|
+
keywords?: string;
|
|
58
|
+
/** The application that authored the content. */
|
|
59
|
+
creator?: string;
|
|
60
|
+
/** The application that wrote the PDF. */
|
|
61
|
+
producer?: string;
|
|
62
|
+
/**
|
|
63
|
+
* ISO 8601 when the producer wrote a conforming date, otherwise the raw
|
|
64
|
+
* string it did write.
|
|
65
|
+
*/
|
|
66
|
+
createdAt?: string;
|
|
67
|
+
modifiedAt?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Where and how an image is laid onto a page. */
|
|
71
|
+
|
|
72
|
+
export interface StampOptions {
|
|
73
|
+
/** Which page, counting from zero. Absent stamps every page. */
|
|
74
|
+
page?: number;
|
|
75
|
+
/** Points from the left edge. Default 0. */
|
|
76
|
+
x?: number;
|
|
77
|
+
/** Points from the TOP edge. Default 0. */
|
|
78
|
+
y?: number;
|
|
79
|
+
/** Drawn width in points. With `height` absent, the ratio is kept. */
|
|
80
|
+
width?: number;
|
|
81
|
+
/** Drawn height in points. With `width` absent, the ratio is kept. */
|
|
82
|
+
height?: number;
|
|
83
|
+
/** 0 is invisible, 1 is opaque. Default 1. */
|
|
84
|
+
opacity?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Where and how a line of text is written onto a page. */
|
|
88
|
+
|
|
89
|
+
export interface TextStampOptions {
|
|
90
|
+
/** Which page, counting from zero. Absent writes on every page. */
|
|
91
|
+
page?: number;
|
|
92
|
+
/** Points from the left edge. Default 0. */
|
|
93
|
+
x?: number;
|
|
94
|
+
/** Points from the TOP edge, to the text's baseline. Default 0. */
|
|
95
|
+
y?: number;
|
|
96
|
+
/** Type size in points. Default 12. */
|
|
97
|
+
size?: number;
|
|
98
|
+
/**
|
|
99
|
+
* One of the 14 standard fonts, e.g. `"Helvetica"`, `"Times-Roman"`.
|
|
100
|
+
* Ignored when `fontData` is given.
|
|
101
|
+
*/
|
|
102
|
+
font?: string;
|
|
103
|
+
/**
|
|
104
|
+
* A TrueType or OpenType file to embed, subsetted to the text. Lifts the
|
|
105
|
+
* WinAnsi limit of the standard fonts, at the cost of carrying the glyphs
|
|
106
|
+
* in the document.
|
|
107
|
+
*/
|
|
108
|
+
fontData?: Buffer;
|
|
109
|
+
/** `#rgb` or `#rrggbb`. Default black. */
|
|
110
|
+
color?: string;
|
|
111
|
+
/** 0 is invisible, 1 is opaque. Default 1. */
|
|
112
|
+
opacity?: number;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** One interactive field of a document's form. */
|
|
116
|
+
|
|
117
|
+
export interface FormField {
|
|
118
|
+
/**
|
|
119
|
+
* The fully qualified name — every ancestor's partial name joined with
|
|
120
|
+
* dots. This is the name used to fill the field in.
|
|
121
|
+
*/
|
|
122
|
+
name: string;
|
|
123
|
+
/**
|
|
124
|
+
* `"text"`, `"checkbox"`, `"radio"`, `"pushButton"`, `"dropdown"`,
|
|
125
|
+
* `"listBox"` or `"signature"`.
|
|
126
|
+
*/
|
|
127
|
+
kind: string;
|
|
128
|
+
value?: string;
|
|
129
|
+
/**
|
|
130
|
+
* What a choice field offers, or the states a checkbox and radio accept.
|
|
131
|
+
* A checkbox's "on" state is chosen by the document, so ticking it means
|
|
132
|
+
* writing one of these.
|
|
133
|
+
*/
|
|
134
|
+
options: Array<string>;
|
|
135
|
+
readOnly: boolean;
|
|
136
|
+
required: boolean;
|
|
137
|
+
multiline: boolean;
|
|
138
|
+
password: boolean;
|
|
139
|
+
maxLength?: number;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** What the signature says about itself. */
|
|
143
|
+
|
|
144
|
+
export interface SignatureOptions {
|
|
145
|
+
/** Why the document was signed. */
|
|
146
|
+
reason?: string;
|
|
147
|
+
/** Where it was signed. */
|
|
148
|
+
location?: string;
|
|
149
|
+
/** How to reach the signatory. */
|
|
150
|
+
contact?: string;
|
|
151
|
+
/** Who signed, as it should be displayed. */
|
|
152
|
+
name?: string;
|
|
153
|
+
/** When, as an ISO 8601 instant. */
|
|
154
|
+
signedAt?: string;
|
|
155
|
+
/** Bytes reserved for the signature value. Default 16384. */
|
|
156
|
+
capacity?: number;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** A document with room for a signature, and the digest to sign. */
|
|
160
|
+
|
|
161
|
+
export interface PreparedSignature {
|
|
162
|
+
document: Buffer;
|
|
163
|
+
/** SHA-256 of everything the signature covers. */
|
|
164
|
+
digest: Buffer;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** A query for a timestamp authority, and the nonce it has to echo back. */
|
|
168
|
+
|
|
169
|
+
export interface TimestampQuery {
|
|
170
|
+
/** The DER to post to the authority. */
|
|
171
|
+
query: Buffer;
|
|
172
|
+
/** Opaque: hand it back to `attachTimestamp` unchanged. */
|
|
173
|
+
nonce: Buffer;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** What one signature on a document turns out to be. */
|
|
177
|
+
|
|
178
|
+
export interface SignatureReport {
|
|
179
|
+
/** The field the signature sits in. */
|
|
180
|
+
field: string;
|
|
181
|
+
/** The signed range runs to the last byte, so nothing was appended after. */
|
|
182
|
+
coversWholeDocument: boolean;
|
|
183
|
+
/** The document's bytes hash to what the signature committed to. */
|
|
184
|
+
digestMatches: boolean;
|
|
185
|
+
/** The signature verifies against the certificate it carries. */
|
|
186
|
+
signatureVerifies: boolean;
|
|
187
|
+
/** Who the certificate says signed. */
|
|
188
|
+
signer?: string;
|
|
189
|
+
/** When the signature says it was made. */
|
|
190
|
+
signedAt?: string;
|
|
191
|
+
/** An authority has vouched for when, so it outlives the certificate. */
|
|
192
|
+
timestamped: boolean;
|
|
193
|
+
/** A path was found from the signer's certificate to a trusted anchor. */
|
|
194
|
+
trusted: boolean;
|
|
195
|
+
/** That path, the signer first and the anchor last. */
|
|
196
|
+
chain: Array<string>;
|
|
197
|
+
/**
|
|
198
|
+
* Where the instant used to judge the path came from: `"timestamp"`,
|
|
199
|
+
* `"claimed"` or `"unknown"`.
|
|
200
|
+
*/
|
|
201
|
+
moment: string;
|
|
202
|
+
/** That instant, in seconds since the epoch. */
|
|
203
|
+
momentAt?: number;
|
|
204
|
+
/** The certificate that signed, DER. */
|
|
205
|
+
signerCertificate?: Buffer;
|
|
206
|
+
/** The certificate that issued it, DER — who answers about revocation. */
|
|
207
|
+
issuerCertificate?: Buffer;
|
|
208
|
+
/** Everything that could not be checked, or checked out wrong. */
|
|
209
|
+
problems: Array<string>;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** What a caller is willing to believe. */
|
|
213
|
+
|
|
214
|
+
export interface TrustOptions {
|
|
215
|
+
/**
|
|
216
|
+
* Certificates to trust as roots, DER or PEM. Without them nothing can be
|
|
217
|
+
* trusted, which is what the report will say.
|
|
218
|
+
*/
|
|
219
|
+
anchors?: Array<Buffer>;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** What a responder's answer says. */
|
|
223
|
+
|
|
224
|
+
export interface RevocationAnswer {
|
|
225
|
+
/** `"good"`, `"revoked"` or `"unknown"`. */
|
|
226
|
+
status: string;
|
|
227
|
+
/** When it was withdrawn, or why nobody could be believed. */
|
|
228
|
+
detail?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export declare function inspect(bytes: Buffer): DocumentInfo;
|
|
232
|
+
|
|
233
|
+
export declare function createBlank(pages: Array<PageSize>): Buffer;
|
|
234
|
+
|
|
235
|
+
export declare function renderPage(
|
|
236
|
+
bytes: Buffer,
|
|
237
|
+
pageIndex: number,
|
|
238
|
+
options?: RenderOptions | undefined | null,
|
|
239
|
+
): Promise<Buffer>;
|
|
240
|
+
|
|
241
|
+
export declare function renderAll(
|
|
242
|
+
bytes: Buffer,
|
|
243
|
+
options?: RenderOptions | undefined | null,
|
|
244
|
+
): Promise<Buffer[]>;
|
|
245
|
+
|
|
246
|
+
export declare function pageDimensions(bytes: Buffer): Array<PageDimensions>;
|
|
247
|
+
|
|
248
|
+
export declare function metadata(bytes: Buffer): DocumentMetadata;
|
|
249
|
+
|
|
250
|
+
export declare function extractText(
|
|
251
|
+
bytes: Buffer,
|
|
252
|
+
pageIndex: number,
|
|
253
|
+
): Promise<string>;
|
|
254
|
+
|
|
255
|
+
export declare function extractTextAll(bytes: Buffer): Promise<string[]>;
|
|
256
|
+
|
|
257
|
+
export declare function merge(documents: Array<Buffer>): Promise<Buffer>;
|
|
258
|
+
|
|
259
|
+
export declare function selectPages(
|
|
260
|
+
bytes: Buffer,
|
|
261
|
+
pages: Array<number>,
|
|
262
|
+
): Promise<Buffer>;
|
|
263
|
+
|
|
264
|
+
export declare function split(bytes: Buffer): Promise<Buffer[]>;
|
|
265
|
+
|
|
266
|
+
export declare function rotate(
|
|
267
|
+
bytes: Buffer,
|
|
268
|
+
degrees: number,
|
|
269
|
+
pages?: Array<number> | undefined | null,
|
|
270
|
+
): Promise<Buffer>;
|
|
271
|
+
|
|
272
|
+
export declare function stamp(
|
|
273
|
+
pdf: Buffer,
|
|
274
|
+
image: Buffer,
|
|
275
|
+
options?: StampOptions | undefined | null,
|
|
276
|
+
): Promise<Buffer>;
|
|
277
|
+
|
|
278
|
+
export declare function stampText(
|
|
279
|
+
pdf: Buffer,
|
|
280
|
+
text: string,
|
|
281
|
+
options?: TextStampOptions | undefined | null,
|
|
282
|
+
): Promise<Buffer>;
|
|
283
|
+
|
|
284
|
+
export declare function formFields(bytes: Buffer): Array<FormField>;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Fill the named fields. Keys are the fully qualified names `formFields`
|
|
288
|
+
* reports.
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
export declare function fillForm(
|
|
292
|
+
pdf: Buffer,
|
|
293
|
+
values: Record<string, string>,
|
|
294
|
+
): Promise<Buffer>;
|
|
295
|
+
|
|
296
|
+
/** Paint every field into the page and drop the interactive layer. */
|
|
297
|
+
|
|
298
|
+
export declare function flattenForm(pdf: Buffer): Promise<Buffer>;
|
|
299
|
+
|
|
300
|
+
/** Write a document with room for a signature, and say what has to be signed. */
|
|
301
|
+
|
|
302
|
+
export declare function prepareSignature(
|
|
303
|
+
pdf: Buffer,
|
|
304
|
+
options?: SignatureOptions | undefined | null,
|
|
305
|
+
): Promise<PreparedSignature>;
|
|
306
|
+
|
|
307
|
+
/** Put the signature value into the space that was reserved for it. */
|
|
308
|
+
|
|
309
|
+
export declare function embedSignature(
|
|
310
|
+
prepared: Buffer,
|
|
311
|
+
value: Buffer,
|
|
312
|
+
): Promise<Buffer>;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Turn a digest into the CMS a PDF signature carries, with a key we hold.
|
|
316
|
+
*
|
|
317
|
+
* The key is PKCS#8 DER and the certificates are DER, the signer's first.
|
|
318
|
+
*/
|
|
319
|
+
|
|
320
|
+
export declare function signCms(
|
|
321
|
+
digest: Buffer,
|
|
322
|
+
key: Buffer,
|
|
323
|
+
certificates: Array<Buffer>,
|
|
324
|
+
signedAt: string,
|
|
325
|
+
): Promise<Buffer>;
|
|
326
|
+
|
|
327
|
+
/** Build the query to post to a timestamp authority. */
|
|
328
|
+
|
|
329
|
+
export declare function timestampQuery(cms: Buffer): TimestampQuery;
|
|
330
|
+
|
|
331
|
+
/** Attach the authority's answer to the signature. */
|
|
332
|
+
|
|
333
|
+
export declare function attachTimestamp(
|
|
334
|
+
cms: Buffer,
|
|
335
|
+
response: Buffer,
|
|
336
|
+
nonce: Buffer,
|
|
337
|
+
): Buffer;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Report on every signature the document carries.
|
|
341
|
+
*
|
|
342
|
+
* This establishes integrity and authorship, not trust: it does not ask
|
|
343
|
+
* whether the certificate comes from an authority you accept, nor whether it
|
|
344
|
+
* has been revoked.
|
|
345
|
+
*/
|
|
346
|
+
|
|
347
|
+
export declare function verifySignatures(
|
|
348
|
+
pdf: Buffer,
|
|
349
|
+
trust?: TrustOptions | undefined | null,
|
|
350
|
+
): Promise<SignatureReport[]>;
|
|
351
|
+
|
|
352
|
+
/** The responder a certificate names, if it names one. */
|
|
353
|
+
|
|
354
|
+
export declare function responderUrl(certificate: Buffer): string | null;
|
|
355
|
+
|
|
356
|
+
/** Build the question to post to a revocation responder. */
|
|
357
|
+
|
|
358
|
+
export declare function revocationQuery(
|
|
359
|
+
certificate: Buffer,
|
|
360
|
+
issuer: Buffer,
|
|
361
|
+
): Buffer;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Read a responder's answer about a certificate.
|
|
365
|
+
*
|
|
366
|
+
* `at` is the instant the document was signed: a certificate withdrawn after
|
|
367
|
+
* that does not taint what it signed before.
|
|
368
|
+
*/
|
|
369
|
+
|
|
370
|
+
export declare function readRevocation(
|
|
371
|
+
response: Buffer,
|
|
372
|
+
certificate: Buffer,
|
|
373
|
+
issuer: Buffer,
|
|
374
|
+
at?: number | undefined | null,
|
|
375
|
+
): RevocationAnswer;
|