siteforge-pdf 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SiteForge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # SiteForge PDF
2
+
3
+ Official Node.js SDK for [SiteForge PDF](https://pdf.siteforge.build) — simple HTML to PDF conversion API.
4
+
5
+ - ⚡ **100 free conversions/month**
6
+ - 💳 **Pay-as-you-go**: $0.02 per conversion after free tier
7
+ - 🚀 **Fast**: Sub-second conversion times
8
+ - 📄 **Simple**: Just send HTML, get PDF
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install siteforge-pdf
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```javascript
19
+ const pdf = require('siteforge-pdf');
20
+ const fs = require('fs');
21
+
22
+ // Initialize with your API key
23
+ const client = pdf('sf_pdf_your_api_key');
24
+
25
+ // Convert HTML to PDF
26
+ const buffer = await client.convert('<h1>Hello World</h1>');
27
+ fs.writeFileSync('hello.pdf', buffer);
28
+ ```
29
+
30
+ ## Get Your API Key
31
+
32
+ 1. Sign up at [pdf.siteforge.build](https://pdf.siteforge.build)
33
+ 2. Get your API key from the dashboard
34
+ 3. Start converting!
35
+
36
+ ## Usage
37
+
38
+ ### Convert HTML
39
+
40
+ ```javascript
41
+ const pdf = require('siteforge-pdf');
42
+ const client = pdf('sf_pdf_your_key');
43
+
44
+ // Simple HTML
45
+ const buffer = await client.convert('<h1>Invoice #123</h1><p>Amount: $100</p>');
46
+
47
+ // With options
48
+ const buffer = await client.convert(html, {
49
+ format: 'Letter', // A4, Letter, Legal
50
+ landscape: true, // Landscape orientation
51
+ margin: 'small', // none, small, default, large
52
+ printBackground: true // Include background colors/images
53
+ });
54
+
55
+ fs.writeFileSync('invoice.pdf', buffer);
56
+ ```
57
+
58
+ ### Convert URL
59
+
60
+ ```javascript
61
+ // Convert any public URL to PDF
62
+ const buffer = await client.convertUrl('https://example.com');
63
+
64
+ // With options
65
+ const buffer = await client.convertUrl('https://example.com', {
66
+ format: 'A4',
67
+ waitMs: 1000 // Wait for JS to render
68
+ });
69
+
70
+ fs.writeFileSync('example.pdf', buffer);
71
+ ```
72
+
73
+ ### Check Usage
74
+
75
+ ```javascript
76
+ const usage = await client.usage();
77
+ console.log(usage);
78
+ // {
79
+ // plan: 'free',
80
+ // period: '2024-01',
81
+ // currentMonth: { conversions: 42, ... },
82
+ // limits: { monthly: 100, remaining: 58 }
83
+ // }
84
+ ```
85
+
86
+ ## CLI
87
+
88
+ The package includes a command-line tool:
89
+
90
+ ```bash
91
+ # Set your API key
92
+ export SITEFORGE_PDF_KEY=sf_pdf_your_key
93
+
94
+ # Convert HTML
95
+ siteforge-pdf --html "<h1>Hello</h1>" -o hello.pdf
96
+
97
+ # Convert a file
98
+ siteforge-pdf --file invoice.html -o invoice.pdf
99
+
100
+ # Convert a URL
101
+ siteforge-pdf --url https://example.com -o example.pdf
102
+
103
+ # With options
104
+ siteforge-pdf --html "<h1>Report</h1>" -o report.pdf --landscape --format Letter
105
+
106
+ # Check usage
107
+ siteforge-pdf --usage
108
+ ```
109
+
110
+ ## TypeScript
111
+
112
+ Full TypeScript support included:
113
+
114
+ ```typescript
115
+ import pdf, { SiteForgePDF, ConvertOptions } from 'siteforge-pdf';
116
+
117
+ const client: SiteForgePDF = pdf('sf_pdf_your_key');
118
+
119
+ const options: ConvertOptions = {
120
+ format: 'A4',
121
+ landscape: false
122
+ };
123
+
124
+ const buffer: Buffer = await client.convert('<h1>Hello</h1>', options);
125
+ ```
126
+
127
+ ## Options
128
+
129
+ ### Client Options
130
+
131
+ | Option | Type | Default | Description |
132
+ |--------|------|---------|-------------|
133
+ | `baseUrl` | string | `https://pdf.siteforge.build` | API base URL |
134
+ | `timeout` | number | `60000` | Request timeout in ms |
135
+
136
+ ### Convert Options
137
+
138
+ | Option | Type | Default | Description |
139
+ |--------|------|---------|-------------|
140
+ | `format` | string | `'A4'` | Page format: A4, Letter, Legal |
141
+ | `landscape` | boolean | `false` | Landscape orientation |
142
+ | `margin` | string | `'default'` | Margin: none, small, default, large |
143
+ | `printBackground` | boolean | `true` | Include background graphics |
144
+ | `waitMs` | number | `0` | Wait before capture (for JS rendering) |
145
+
146
+ ## Error Handling
147
+
148
+ ```javascript
149
+ const pdf = require('siteforge-pdf');
150
+ const client = pdf('sf_pdf_your_key');
151
+
152
+ try {
153
+ const buffer = await client.convert('<h1>Hello</h1>');
154
+ fs.writeFileSync('output.pdf', buffer);
155
+ } catch (err) {
156
+ if (err.statusCode === 401) {
157
+ console.error('Invalid API key');
158
+ } else if (err.statusCode === 429) {
159
+ console.error('Rate limit exceeded');
160
+ } else {
161
+ console.error('Conversion failed:', err.message);
162
+ }
163
+ }
164
+ ```
165
+
166
+ ## Pricing
167
+
168
+ | Plan | Monthly Conversions | Price |
169
+ |------|---------------------|-------|
170
+ | Free | 100 | $0 |
171
+ | Pay-as-you-go | Unlimited | $0.02 each |
172
+
173
+ Free tier includes a small watermark. Upgrade to PAYG for watermark-free PDFs.
174
+
175
+ ## Links
176
+
177
+ - 🌐 [Website](https://pdf.siteforge.build)
178
+ - 📖 [API Docs](https://pdf.siteforge.build/docs)
179
+ - 🐛 [Issues](https://github.com/rmoen/siteforge-pdf-node/issues)
180
+
181
+ ## License
182
+
183
+ MIT © [SiteForge](https://siteforge.build)
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "siteforge-pdf",
3
+ "version": "1.0.0",
4
+ "description": "Official Node.js SDK for SiteForge PDF - HTML to PDF conversion API",
5
+ "main": "src/index.js",
6
+ "types": "src/index.d.ts",
7
+ "bin": {
8
+ "siteforge-pdf": "src/cli.js"
9
+ },
10
+ "scripts": {
11
+ "test": "node test/test.js"
12
+ },
13
+ "keywords": [
14
+ "pdf",
15
+ "html-to-pdf",
16
+ "html2pdf",
17
+ "pdf-generation",
18
+ "siteforge",
19
+ "convert",
20
+ "document",
21
+ "api"
22
+ ],
23
+ "author": "SiteForge <support@siteforge.build>",
24
+ "license": "MIT",
25
+ "homepage": "https://pdf.siteforge.build",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/rmoen/siteforge-pdf-node.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/rmoen/siteforge-pdf-node/issues"
32
+ },
33
+ "engines": {
34
+ "node": ">=14.0.0"
35
+ },
36
+ "files": [
37
+ "src/index.js",
38
+ "src/index.d.ts",
39
+ "src/cli.js",
40
+ "README.md",
41
+ "LICENSE"
42
+ ]
43
+ }
package/src/cli.js ADDED
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SiteForge PDF CLI
5
+ *
6
+ * Usage:
7
+ * siteforge-pdf --html "<h1>Hello</h1>" -o output.pdf
8
+ * siteforge-pdf --url https://example.com -o output.pdf
9
+ * siteforge-pdf --usage
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const createClient = require('./index');
15
+
16
+ const HELP = `
17
+ SiteForge PDF - HTML to PDF Conversion
18
+
19
+ Usage:
20
+ siteforge-pdf [options]
21
+
22
+ Options:
23
+ --html <string> HTML content to convert
24
+ --file <path> HTML file to convert
25
+ --url <url> URL to convert
26
+ -o, --output <path> Output PDF path (default: output.pdf)
27
+ --format <format> Page format: A4, Letter, Legal (default: A4)
28
+ --landscape Use landscape orientation
29
+ --no-background Disable background graphics
30
+ --usage Show usage statistics
31
+ --key <key> API key (or set SITEFORGE_PDF_KEY env var)
32
+ -h, --help Show this help
33
+
34
+ Examples:
35
+ siteforge-pdf --html "<h1>Hello World</h1>" -o hello.pdf
36
+ siteforge-pdf --file invoice.html -o invoice.pdf
37
+ siteforge-pdf --url https://example.com -o example.pdf --landscape
38
+ siteforge-pdf --usage
39
+
40
+ Get your API key at https://pdf.siteforge.build
41
+ `;
42
+
43
+ function parseArgs(args) {
44
+ const opts = {
45
+ output: 'output.pdf',
46
+ format: 'A4',
47
+ landscape: false,
48
+ printBackground: true
49
+ };
50
+
51
+ for (let i = 0; i < args.length; i++) {
52
+ const arg = args[i];
53
+ const next = args[i + 1];
54
+
55
+ switch (arg) {
56
+ case '-h':
57
+ case '--help':
58
+ opts.help = true;
59
+ break;
60
+ case '--html':
61
+ opts.html = next;
62
+ i++;
63
+ break;
64
+ case '--file':
65
+ opts.file = next;
66
+ i++;
67
+ break;
68
+ case '--url':
69
+ opts.url = next;
70
+ i++;
71
+ break;
72
+ case '-o':
73
+ case '--output':
74
+ opts.output = next;
75
+ i++;
76
+ break;
77
+ case '--format':
78
+ opts.format = next;
79
+ i++;
80
+ break;
81
+ case '--landscape':
82
+ opts.landscape = true;
83
+ break;
84
+ case '--no-background':
85
+ opts.printBackground = false;
86
+ break;
87
+ case '--usage':
88
+ opts.usage = true;
89
+ break;
90
+ case '--key':
91
+ opts.key = next;
92
+ i++;
93
+ break;
94
+ }
95
+ }
96
+
97
+ return opts;
98
+ }
99
+
100
+ async function main() {
101
+ const args = process.argv.slice(2);
102
+
103
+ if (args.length === 0) {
104
+ console.log(HELP);
105
+ process.exit(0);
106
+ }
107
+
108
+ const opts = parseArgs(args);
109
+
110
+ if (opts.help) {
111
+ console.log(HELP);
112
+ process.exit(0);
113
+ }
114
+
115
+ // Get API key
116
+ const apiKey = opts.key || process.env.SITEFORGE_PDF_KEY;
117
+ if (!apiKey) {
118
+ console.error('Error: API key required. Use --key or set SITEFORGE_PDF_KEY env var');
119
+ console.error('Get your key at https://pdf.siteforge.build');
120
+ process.exit(1);
121
+ }
122
+
123
+ const client = createClient(apiKey);
124
+
125
+ try {
126
+ // Usage check
127
+ if (opts.usage) {
128
+ const usage = await client.usage();
129
+ console.log('\nSiteForge PDF Usage\n');
130
+ console.log(`Plan: ${usage.plan}`);
131
+ console.log(`Period: ${usage.period}`);
132
+ console.log(`Conversions this month: ${usage.currentMonth.conversions}`);
133
+ if (usage.limits.monthly) {
134
+ console.log(`Remaining: ${usage.limits.remaining}/${usage.limits.monthly}`);
135
+ }
136
+ if (usage.plan === 'payg') {
137
+ console.log(`Estimated cost: $${usage.currentMonth.estimatedCost}`);
138
+ }
139
+ console.log(`All-time conversions: ${usage.allTime.conversions}`);
140
+ return;
141
+ }
142
+
143
+ // Get HTML content
144
+ let html = opts.html;
145
+ if (opts.file) {
146
+ html = fs.readFileSync(opts.file, 'utf8');
147
+ }
148
+
149
+ // Convert
150
+ let buffer;
151
+ const convertOpts = {
152
+ format: opts.format,
153
+ landscape: opts.landscape,
154
+ printBackground: opts.printBackground
155
+ };
156
+
157
+ if (opts.url) {
158
+ console.log(`Converting URL: ${opts.url}`);
159
+ buffer = await client.convertUrl(opts.url, convertOpts);
160
+ } else if (html) {
161
+ console.log('Converting HTML...');
162
+ buffer = await client.convert(html, convertOpts);
163
+ } else {
164
+ console.error('Error: Provide --html, --file, or --url');
165
+ process.exit(1);
166
+ }
167
+
168
+ // Write output
169
+ const outputPath = path.resolve(opts.output);
170
+ fs.writeFileSync(outputPath, buffer);
171
+ console.log(`✓ PDF saved: ${outputPath} (${(buffer.length / 1024).toFixed(1)} KB)`);
172
+
173
+ } catch (err) {
174
+ console.error(`Error: ${err.message}`);
175
+ process.exit(1);
176
+ }
177
+ }
178
+
179
+ main();
package/src/index.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * SiteForge PDF - TypeScript Definitions
3
+ */
4
+
5
+ export interface ConvertOptions {
6
+ /** Page format: A4, Letter, Legal (default: A4) */
7
+ format?: 'A4' | 'Letter' | 'Legal';
8
+ /** Landscape orientation (default: false) */
9
+ landscape?: boolean;
10
+ /** Margin size (default: 'default') */
11
+ margin?: 'none' | 'small' | 'default' | 'large';
12
+ /** Include background graphics (default: true) */
13
+ printBackground?: boolean;
14
+ /** Wait time before capture in ms (for convertUrl) */
15
+ waitMs?: number;
16
+ }
17
+
18
+ export interface ClientOptions {
19
+ /** API base URL (default: https://pdf.siteforge.build) */
20
+ baseUrl?: string;
21
+ /** Request timeout in ms (default: 60000) */
22
+ timeout?: number;
23
+ }
24
+
25
+ export interface UsageStats {
26
+ plan: 'free' | 'payg' | 'pro';
27
+ period: string;
28
+ currentMonth: {
29
+ conversions: number;
30
+ totalBytes: number;
31
+ avgProcessingMs: number;
32
+ estimatedCost: string;
33
+ };
34
+ allTime: {
35
+ conversions: number;
36
+ totalBytes: number;
37
+ };
38
+ limits: {
39
+ monthly: number | null;
40
+ remaining: number | null;
41
+ };
42
+ }
43
+
44
+ export interface HealthStatus {
45
+ status: 'ok' | 'error';
46
+ service: string;
47
+ }
48
+
49
+ export declare class SiteForgePDF {
50
+ constructor(apiKey: string, options?: ClientOptions);
51
+
52
+ /**
53
+ * Convert HTML to PDF
54
+ */
55
+ convert(html: string, options?: ConvertOptions): Promise<Buffer>;
56
+
57
+ /**
58
+ * Convert a URL to PDF
59
+ */
60
+ convertUrl(url: string, options?: ConvertOptions): Promise<Buffer>;
61
+
62
+ /**
63
+ * Get usage statistics
64
+ */
65
+ usage(): Promise<UsageStats>;
66
+
67
+ /**
68
+ * Health check
69
+ */
70
+ health(): Promise<HealthStatus>;
71
+ }
72
+
73
+ /**
74
+ * Create a SiteForge PDF client
75
+ */
76
+ declare function createClient(apiKey: string, options?: ClientOptions): SiteForgePDF;
77
+
78
+ export { createClient };
79
+ export default createClient;
package/src/index.js ADDED
@@ -0,0 +1,179 @@
1
+ /**
2
+ * SiteForge PDF - Official Node.js SDK
3
+ * https://pdf.siteforge.build
4
+ *
5
+ * Simple HTML to PDF conversion API
6
+ */
7
+
8
+ const https = require('https');
9
+ const http = require('http');
10
+
11
+ const DEFAULT_BASE_URL = 'https://pdf.siteforge.build';
12
+
13
+ class SiteForgePDF {
14
+ /**
15
+ * Create a SiteForge PDF client
16
+ * @param {string} apiKey - Your API key (starts with sf_pdf_)
17
+ * @param {object} options - Optional configuration
18
+ * @param {string} options.baseUrl - API base URL (default: https://pdf.siteforge.build)
19
+ * @param {number} options.timeout - Request timeout in ms (default: 60000)
20
+ */
21
+ constructor(apiKey, options = {}) {
22
+ if (!apiKey) {
23
+ throw new Error('API key is required. Get one at https://pdf.siteforge.build');
24
+ }
25
+ if (!apiKey.startsWith('sf_pdf_')) {
26
+ throw new Error('Invalid API key format. Keys start with sf_pdf_');
27
+ }
28
+
29
+ this.apiKey = apiKey;
30
+ this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;
31
+ this.timeout = options.timeout || 60000;
32
+ }
33
+
34
+ /**
35
+ * Make an API request
36
+ * @private
37
+ */
38
+ _request(method, path, body = null, expectBinary = false) {
39
+ return new Promise((resolve, reject) => {
40
+ const url = new URL(path, this.baseUrl);
41
+ const isHttps = url.protocol === 'https:';
42
+ const client = isHttps ? https : http;
43
+
44
+ const options = {
45
+ hostname: url.hostname,
46
+ port: url.port || (isHttps ? 443 : 80),
47
+ path: url.pathname + url.search,
48
+ method,
49
+ headers: {
50
+ 'Authorization': `Bearer ${this.apiKey}`,
51
+ 'Content-Type': 'application/json',
52
+ 'User-Agent': 'siteforge-pdf-node/1.0.0'
53
+ },
54
+ timeout: this.timeout
55
+ };
56
+
57
+ const req = client.request(options, (res) => {
58
+ const chunks = [];
59
+
60
+ res.on('data', chunk => chunks.push(chunk));
61
+ res.on('end', () => {
62
+ const buffer = Buffer.concat(chunks);
63
+
64
+ if (res.statusCode >= 400) {
65
+ let error;
66
+ try {
67
+ const json = JSON.parse(buffer.toString());
68
+ error = new Error(json.error || `HTTP ${res.statusCode}`);
69
+ } catch {
70
+ error = new Error(`HTTP ${res.statusCode}: ${buffer.toString()}`);
71
+ }
72
+ error.statusCode = res.statusCode;
73
+ reject(error);
74
+ return;
75
+ }
76
+
77
+ if (expectBinary) {
78
+ resolve(buffer);
79
+ } else {
80
+ try {
81
+ resolve(JSON.parse(buffer.toString()));
82
+ } catch {
83
+ resolve(buffer.toString());
84
+ }
85
+ }
86
+ });
87
+ });
88
+
89
+ req.on('error', reject);
90
+ req.on('timeout', () => {
91
+ req.destroy();
92
+ reject(new Error('Request timed out'));
93
+ });
94
+
95
+ if (body) {
96
+ req.write(JSON.stringify(body));
97
+ }
98
+ req.end();
99
+ });
100
+ }
101
+
102
+ /**
103
+ * Convert HTML to PDF
104
+ * @param {string} html - HTML content to convert
105
+ * @param {object} options - Conversion options
106
+ * @param {string} options.format - Page format: A4, Letter, Legal (default: A4)
107
+ * @param {boolean} options.landscape - Landscape orientation (default: false)
108
+ * @param {string} options.margin - Margin size: none, small, default, large
109
+ * @param {boolean} options.printBackground - Include background graphics (default: true)
110
+ * @returns {Promise<Buffer>} PDF as a Buffer
111
+ */
112
+ async convert(html, options = {}) {
113
+ if (!html || typeof html !== 'string') {
114
+ throw new Error('HTML content is required');
115
+ }
116
+
117
+ const body = {
118
+ html,
119
+ ...options
120
+ };
121
+
122
+ return this._request('POST', '/v1/convert', body, true);
123
+ }
124
+
125
+ /**
126
+ * Convert a URL to PDF
127
+ * @param {string} url - URL to convert
128
+ * @param {object} options - Conversion options
129
+ * @param {string} options.format - Page format: A4, Letter, Legal (default: A4)
130
+ * @param {boolean} options.landscape - Landscape orientation (default: false)
131
+ * @param {string} options.margin - Margin size: none, small, default, large
132
+ * @param {boolean} options.printBackground - Include background graphics (default: true)
133
+ * @param {number} options.waitMs - Wait time before capture in ms (default: 0)
134
+ * @returns {Promise<Buffer>} PDF as a Buffer
135
+ */
136
+ async convertUrl(url, options = {}) {
137
+ if (!url || typeof url !== 'string') {
138
+ throw new Error('URL is required');
139
+ }
140
+
141
+ const body = {
142
+ url,
143
+ ...options
144
+ };
145
+
146
+ return this._request('POST', '/v1/convert', body, true);
147
+ }
148
+
149
+ /**
150
+ * Get usage statistics
151
+ * @returns {Promise<object>} Usage stats including conversions, limits, costs
152
+ */
153
+ async usage() {
154
+ return this._request('GET', '/v1/usage');
155
+ }
156
+
157
+ /**
158
+ * Health check
159
+ * @returns {Promise<object>} Service status
160
+ */
161
+ async health() {
162
+ return this._request('GET', '/health');
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Create a SiteForge PDF client
168
+ * @param {string} apiKey - Your API key
169
+ * @param {object} options - Optional configuration
170
+ * @returns {SiteForgePDF}
171
+ */
172
+ function createClient(apiKey, options) {
173
+ return new SiteForgePDF(apiKey, options);
174
+ }
175
+
176
+ // Allow both: require('siteforge-pdf')('key') and require('siteforge-pdf').createClient('key')
177
+ module.exports = createClient;
178
+ module.exports.createClient = createClient;
179
+ module.exports.SiteForgePDF = SiteForgePDF;