tailprint 0.0.0-stage → 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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -2
  3. package/dist/config/env.d.ts +77 -0
  4. package/dist/config/env.js +38 -0
  5. package/dist/config/env.js.map +1 -0
  6. package/dist/config/plans.d.ts +15 -0
  7. package/dist/config/plans.js +104 -0
  8. package/dist/config/plans.js.map +1 -0
  9. package/dist/config/templates.d.ts +10 -0
  10. package/dist/config/templates.js +746 -0
  11. package/dist/config/templates.js.map +1 -0
  12. package/dist/mcp/server.d.ts +10 -0
  13. package/dist/mcp/server.js +897 -0
  14. package/dist/mcp/server.js.map +1 -0
  15. package/dist/mcp/stdio.d.ts +2 -0
  16. package/dist/mcp/stdio.js +27 -0
  17. package/dist/mcp/stdio.js.map +1 -0
  18. package/dist/routes/dashboard.d.ts +2 -0
  19. package/dist/routes/dashboard.js +454 -0
  20. package/dist/routes/dashboard.js.map +1 -0
  21. package/dist/routes/mcp.d.ts +2 -0
  22. package/dist/routes/mcp.js +329 -0
  23. package/dist/routes/mcp.js.map +1 -0
  24. package/dist/routes/render.d.ts +2 -0
  25. package/dist/routes/render.js +444 -0
  26. package/dist/routes/render.js.map +1 -0
  27. package/dist/routes/scrape.d.ts +2 -0
  28. package/dist/routes/scrape.js +132 -0
  29. package/dist/routes/scrape.js.map +1 -0
  30. package/dist/routes/templates.d.ts +2 -0
  31. package/dist/routes/templates.js +2449 -0
  32. package/dist/routes/templates.js.map +1 -0
  33. package/dist/routes/usage.d.ts +31 -0
  34. package/dist/routes/usage.js +73 -0
  35. package/dist/routes/usage.js.map +1 -0
  36. package/dist/routes/webhooks.d.ts +2 -0
  37. package/dist/routes/webhooks.js +227 -0
  38. package/dist/routes/webhooks.js.map +1 -0
  39. package/dist/schemas/render.d.ts +422 -0
  40. package/dist/schemas/render.js +91 -0
  41. package/dist/schemas/render.js.map +1 -0
  42. package/dist/schemas/scrape.d.ts +65 -0
  43. package/dist/schemas/scrape.js +24 -0
  44. package/dist/schemas/scrape.js.map +1 -0
  45. package/dist/server.d.ts +2 -0
  46. package/dist/server.js +206 -0
  47. package/dist/server.js.map +1 -0
  48. package/dist/services/browser.d.ts +21 -0
  49. package/dist/services/browser.js +299 -0
  50. package/dist/services/browser.js.map +1 -0
  51. package/dist/services/carousel.d.ts +43 -0
  52. package/dist/services/carousel.js +300 -0
  53. package/dist/services/carousel.js.map +1 -0
  54. package/dist/services/chart.d.ts +29 -0
  55. package/dist/services/chart.js +129 -0
  56. package/dist/services/chart.js.map +1 -0
  57. package/dist/services/eInvoice.d.ts +62 -0
  58. package/dist/services/eInvoice.js +413 -0
  59. package/dist/services/eInvoice.js.map +1 -0
  60. package/dist/services/email.d.ts +24 -0
  61. package/dist/services/email.js +177 -0
  62. package/dist/services/email.js.map +1 -0
  63. package/dist/services/mockup.d.ts +14 -0
  64. package/dist/services/mockup.js +130 -0
  65. package/dist/services/mockup.js.map +1 -0
  66. package/dist/services/pdfStamper.d.ts +16 -0
  67. package/dist/services/pdfStamper.js +47 -0
  68. package/dist/services/pdfStamper.js.map +1 -0
  69. package/dist/services/qr.d.ts +20 -0
  70. package/dist/services/qr.js +44 -0
  71. package/dist/services/qr.js.map +1 -0
  72. package/dist/services/redis.d.ts +65 -0
  73. package/dist/services/redis.js +318 -0
  74. package/dist/services/redis.js.map +1 -0
  75. package/dist/services/scraper.d.ts +16 -0
  76. package/dist/services/scraper.js +138 -0
  77. package/dist/services/scraper.js.map +1 -0
  78. package/dist/services/storage.d.ts +38 -0
  79. package/dist/services/storage.js +123 -0
  80. package/dist/services/storage.js.map +1 -0
  81. package/dist/services/stripe.d.ts +32 -0
  82. package/dist/services/stripe.js +229 -0
  83. package/dist/services/stripe.js.map +1 -0
  84. package/dist/services/visualDiff.d.ts +33 -0
  85. package/dist/services/visualDiff.js +218 -0
  86. package/dist/services/visualDiff.js.map +1 -0
  87. package/package.json +74 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tailprint (tailprint.com)
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 CHANGED
@@ -1,3 +1,161 @@
1
- # Temporary Holding Version
1
+ # Tailprint — Tailwind-Native Render & PDF Engine + AI Web Scraper
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
+ [![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-purple.svg)](https://modelcontextprotocol.io)
5
+ [![Production](https://img.shields.io/badge/Production-tailprint.com-emerald.svg)](https://tailprint.com)
6
+ [![Docs](https://img.shields.io/badge/API_Docs-Scalar-indigo.svg)](https://tailprint.com/docs)
7
+
8
+ **Tailprint** ([tailprint.com](https://tailprint.com)) is a high-performance, developer-first rendering engine and Model Context Protocol (MCP) server. It accepts raw HTML styled with arbitrary **Tailwind CSS** utility classes and compiles print-ready, pixel-perfect vector **PDFs** or high-resolution **Open Graph images** in under 800ms.
9
+
10
+ It also features an intelligent **LLM Web Scraper** that strips ads, trackers, and navigation boilerplate using Mozilla Readability, returning token-efficient structured Markdown.
11
+
12
+ ---
13
+
14
+ ## ⚡ Highlights
15
+
16
+ - **Tailwind-Native:** Built-in Tailwind CSS JIT compilation—no build step, PostCSS config, or bundling required.
17
+ - **Model Context Protocol (MCP):** Connects natively to **Claude Desktop**, **Cursor**, **Windsurf**, and autonomous AI agents via Remote SSE or Stdio CLI.
18
+ - **Sub-800ms Playwright Engine:** Pre-warmed Chromium instances with isolated browser contexts and strict concurrency throttling (`p-limit`).
19
+ - **Interactive Live Playground:** Test markup in real-time in the browser at [tailprint.com](https://tailprint.com).
20
+ - **Free Developer Sandbox:** 100 free monthly renders with zero credit card required.
21
+ - **SHA-256 Deduplication Caching:** Instant cache hits (`X-Cache: HIT`) for repeated image renders.
22
+ - **SSRF & Network Sandboxing:** Automatically blocks local and private IP ranges (`127.0.0.1`, `10.0.0.0/8`, `169.254.169.254`, etc.).
23
+
24
+ ---
25
+
26
+ ## 🤖 Model Context Protocol (MCP) Setup
27
+
28
+ Tailprint provides an official MCP server enabling AI coding assistants and agents to generate documents and scrape web pages on command.
29
+
30
+ ### Capabilities & Tools
31
+ 1. `render_pdf`: Generates vector PDFs from raw HTML + Tailwind CSS (invoices, certificates, summaries).
32
+ 2. `render_image`: Renders 1200x630 social preview cards (PNG/JPEG) with automatic caching.
33
+ 3. `scrape_markdown`: Scrapes any public URL, strips web noise, and returns clean Markdown with token metrics.
34
+
35
+ ### 1. Claude Desktop Setup
36
+ Add this to your Claude Desktop configuration file:
37
+ - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
38
+ - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "tailprint": {
44
+ "url": "https://tailprint.com/v1/mcp/sse",
45
+ "headers": {
46
+ "Authorization": "Bearer YOUR_TAILPRINT_API_KEY"
47
+ }
48
+ }
49
+ }
50
+ }
51
+ ```
52
+ *(Get a free key at [tailprint.com](https://tailprint.com) with 100 renders/month, no credit card required).*
53
+
54
+ ### 2. Cursor IDE Setup
55
+ In Cursor:
56
+ 1. Open **Settings** ➔ **Features** ➔ **MCP Servers**.
57
+ 2. Click **Add New MCP Server**.
58
+ 3. Name: `tailprint`
59
+ 4. Type: `sse`
60
+ 5. URL: `https://tailprint.com/v1/mcp/sse?api_key=YOUR_TAILPRINT_API_KEY`
61
+
62
+ ---
63
+
64
+ ## 💰 Pricing & Plans
65
+
66
+ | Tier | Price | Monthly Limit | Features |
67
+ | :--- | :--- | :--- | :--- |
68
+ | **Developer Free** | **$0** | **100 renders** | No credit card required. Full Tailwind support, MCP access. |
69
+ | **Starter** | **$14 / mo** | **2,500 renders** | Ideal for solo developers, indie projects, and small stores. |
70
+ | **Pro (Most Popular)** | **$39 / mo** | **20,000 renders** | Prioritized Chromium queue, SHA-256 caching, agency ready. |
71
+ | **Business / Scale** | **$99 / mo** | **75,000 renders** | High throughput pool reservation, multi-key team access. |
72
+ | **Enterprise** | **$199+ / mo** | **100,000+ renders** | Dedicated browser instances, 99.9% uptime SLA, Slack channel. |
73
+
74
+ ---
75
+
76
+ ## 🚀 API Quickstart
77
+
78
+ ### 1. Claim a Free API Key (No Credit Card)
79
+ ```bash
80
+ curl -X POST https://tailprint.com/v1/auth/claim-free-key \
81
+ -H "Content-Type: application/json" \
82
+ -d '{"email":"your-email@example.com"}'
83
+ ```
84
+
85
+ ### 2. Render HTML to PDF
86
+ ```bash
87
+ curl -X POST https://tailprint.com/v1/render/pdf \
88
+ -H "Authorization: Bearer sec_live_..." \
89
+ -H "Content-Type: application/json" \
90
+ -d '{
91
+ "html": "<div class=\"p-12 bg-slate-900 text-white font-sans\"><h1 class=\"text-3xl font-bold text-indigo-400\">Invoice #1042</h1><p class=\"text-slate-400 mt-2\">Styled dynamically with Tailwind CSS.</p></div>",
92
+ "format": "A4",
93
+ "landscape": false
94
+ }' \
95
+ --output invoice.pdf
96
+ ```
97
+
98
+ ### 3. Render Open Graph Social Image
99
+ ```bash
100
+ curl -X POST https://tailprint.com/v1/render/image \
101
+ -H "Authorization: Bearer sec_live_..." \
102
+ -H "Content-Type: application/json" \
103
+ -d '{
104
+ "html": "<div class=\"w-full h-full flex flex-col justify-center items-center bg-gradient-to-tr from-indigo-900 to-purple-950 text-white\"><h1 class=\"text-5xl font-black\">Hello Tailprint</h1></div>",
105
+ "width": 1200,
106
+ "height": 630,
107
+ "type": "png"
108
+ }' \
109
+ --output og-card.png
110
+ ```
111
+
112
+ ### 4. Scrape Web Page to LLM-Clean Markdown
113
+ ```bash
114
+ curl -X POST https://tailprint.com/v1/scrape/markdown \
115
+ -H "Authorization: Bearer sec_live_..." \
116
+ -H "Content-Type: application/json" \
117
+ -d '{
118
+ "url": "https://techcrunch.com/2026/02/10/example-article",
119
+ "strip_images": true
120
+ }'
121
+ ```
122
+
123
+ ---
124
+
125
+ ## 🛠 Local Development & Self-Hosting
126
+
127
+ ### Requirements
128
+ - Node.js 20+
129
+ - Playwright Chromium (`npx playwright install chromium`)
130
+ - Upstash Redis or local Redis (optional, includes in-memory dev fallback)
131
+
132
+ ### Installation
133
+ ```bash
134
+ # Clone the repository
135
+ git clone https://github.com/coheroseb/tailprint.git
136
+ cd tailprint
137
+
138
+ # Install dependencies
139
+ npm install
140
+ npx playwright install chromium
141
+
142
+ # Copy environment variables
143
+ cp .env.example .env
144
+
145
+ # Run development server with hot-reload
146
+ npm run dev
147
+
148
+ # Run unit & integration test suite
149
+ npm test
150
+ ```
151
+
152
+ ### Docker
153
+ ```bash
154
+ docker compose up -d --build
155
+ ```
156
+
157
+ ---
158
+
159
+ ## 📄 License
160
+
161
+ MIT © [Tailprint](https://tailprint.com)
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod';
2
+ declare const envSchema: z.ZodObject<{
3
+ NODE_ENV: z.ZodDefault<z.ZodEnum<["development", "production", "test"]>>;
4
+ PORT: z.ZodDefault<z.ZodNumber>;
5
+ HOST: z.ZodDefault<z.ZodString>;
6
+ UPSTASH_REDIS_REST_URL: z.ZodOptional<z.ZodString>;
7
+ UPSTASH_REDIS_REST_TOKEN: z.ZodOptional<z.ZodString>;
8
+ STRIPE_SECRET_KEY: z.ZodDefault<z.ZodOptional<z.ZodString>>;
9
+ STRIPE_WEBHOOK_SECRET: z.ZodDefault<z.ZodOptional<z.ZodString>>;
10
+ STRIPE_PRICE_STARTER: z.ZodDefault<z.ZodOptional<z.ZodString>>;
11
+ STRIPE_PRICE_PRO: z.ZodDefault<z.ZodOptional<z.ZodString>>;
12
+ STRIPE_PRICE_BUSINESS: z.ZodDefault<z.ZodOptional<z.ZodString>>;
13
+ STRIPE_PRICE_ENTERPRISE: z.ZodDefault<z.ZodOptional<z.ZodString>>;
14
+ APP_URL: z.ZodDefault<z.ZodString>;
15
+ CONCURRENCY_LIMIT: z.ZodDefault<z.ZodNumber>;
16
+ RENDER_TIMEOUT_MS: z.ZodDefault<z.ZodNumber>;
17
+ CACHE_TTL_SECONDS: z.ZodDefault<z.ZodNumber>;
18
+ STORAGE_PATH: z.ZodDefault<z.ZodString>;
19
+ TAILWIND_CDN_URL: z.ZodDefault<z.ZodString>;
20
+ DEV_DEFAULT_API_KEY: z.ZodDefault<z.ZodOptional<z.ZodString>>;
21
+ SMTP_HOST: z.ZodDefault<z.ZodString>;
22
+ SMTP_PORT: z.ZodDefault<z.ZodNumber>;
23
+ SMTP_USER: z.ZodOptional<z.ZodString>;
24
+ SMTP_PASS: z.ZodOptional<z.ZodString>;
25
+ SMTP_FROM: z.ZodDefault<z.ZodString>;
26
+ }, "strip", z.ZodTypeAny, {
27
+ NODE_ENV: "development" | "production" | "test";
28
+ PORT: number;
29
+ HOST: string;
30
+ STRIPE_SECRET_KEY: string;
31
+ STRIPE_WEBHOOK_SECRET: string;
32
+ STRIPE_PRICE_STARTER: string;
33
+ STRIPE_PRICE_PRO: string;
34
+ STRIPE_PRICE_BUSINESS: string;
35
+ STRIPE_PRICE_ENTERPRISE: string;
36
+ APP_URL: string;
37
+ CONCURRENCY_LIMIT: number;
38
+ RENDER_TIMEOUT_MS: number;
39
+ CACHE_TTL_SECONDS: number;
40
+ STORAGE_PATH: string;
41
+ TAILWIND_CDN_URL: string;
42
+ DEV_DEFAULT_API_KEY: string;
43
+ SMTP_HOST: string;
44
+ SMTP_PORT: number;
45
+ SMTP_FROM: string;
46
+ UPSTASH_REDIS_REST_URL?: string | undefined;
47
+ UPSTASH_REDIS_REST_TOKEN?: string | undefined;
48
+ SMTP_USER?: string | undefined;
49
+ SMTP_PASS?: string | undefined;
50
+ }, {
51
+ NODE_ENV?: "development" | "production" | "test" | undefined;
52
+ PORT?: number | undefined;
53
+ HOST?: string | undefined;
54
+ UPSTASH_REDIS_REST_URL?: string | undefined;
55
+ UPSTASH_REDIS_REST_TOKEN?: string | undefined;
56
+ STRIPE_SECRET_KEY?: string | undefined;
57
+ STRIPE_WEBHOOK_SECRET?: string | undefined;
58
+ STRIPE_PRICE_STARTER?: string | undefined;
59
+ STRIPE_PRICE_PRO?: string | undefined;
60
+ STRIPE_PRICE_BUSINESS?: string | undefined;
61
+ STRIPE_PRICE_ENTERPRISE?: string | undefined;
62
+ APP_URL?: string | undefined;
63
+ CONCURRENCY_LIMIT?: number | undefined;
64
+ RENDER_TIMEOUT_MS?: number | undefined;
65
+ CACHE_TTL_SECONDS?: number | undefined;
66
+ STORAGE_PATH?: string | undefined;
67
+ TAILWIND_CDN_URL?: string | undefined;
68
+ DEV_DEFAULT_API_KEY?: string | undefined;
69
+ SMTP_HOST?: string | undefined;
70
+ SMTP_PORT?: number | undefined;
71
+ SMTP_USER?: string | undefined;
72
+ SMTP_PASS?: string | undefined;
73
+ SMTP_FROM?: string | undefined;
74
+ }>;
75
+ export type Env = z.infer<typeof envSchema>;
76
+ export declare const env: Env;
77
+ export {};
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+ const envSchema = z.object({
5
+ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
6
+ PORT: z.coerce.number().int().positive().default(3000),
7
+ HOST: z.string().default('0.0.0.0'),
8
+ // Upstash Redis
9
+ UPSTASH_REDIS_REST_URL: z.string().url().optional(),
10
+ UPSTASH_REDIS_REST_TOKEN: z.string().optional(),
11
+ // Stripe
12
+ STRIPE_SECRET_KEY: z.string().optional().default('sk_test_placeholder'),
13
+ STRIPE_WEBHOOK_SECRET: z.string().optional().default('whsec_placeholder'),
14
+ STRIPE_PRICE_STARTER: z.string().optional().default('price_starter_test'),
15
+ STRIPE_PRICE_PRO: z.string().optional().default('price_pro_test'),
16
+ STRIPE_PRICE_BUSINESS: z.string().optional().default('price_business_test'),
17
+ STRIPE_PRICE_ENTERPRISE: z.string().optional().default('price_enterprise_test'),
18
+ APP_URL: z.string().default('http://localhost:3000'),
19
+ // Browser & Rendering limits
20
+ CONCURRENCY_LIMIT: z.coerce.number().int().positive().default(5),
21
+ RENDER_TIMEOUT_MS: z.coerce.number().int().positive().default(8000),
22
+ // Caching
23
+ CACHE_TTL_SECONDS: z.coerce.number().int().positive().default(604800), // 7 days
24
+ // Cloud Storage / Hosted Delivery Directory
25
+ STORAGE_PATH: z.string().default(process.env.STORAGE_PATH || 'storage'),
26
+ // Tailwind CDN
27
+ TAILWIND_CDN_URL: z.string().url().default('https://cdn.tailwindcss.com'),
28
+ // Dev bypass (for quick local testing without Redis if needed)
29
+ DEV_DEFAULT_API_KEY: z.string().optional().default('sec_live_dev_test_key_12345'),
30
+ // SMTP Email Server (Fortrolig.dk)
31
+ SMTP_HOST: z.string().default('mail.fortrolig.dk'),
32
+ SMTP_PORT: z.coerce.number().default(465),
33
+ SMTP_USER: z.string().optional(),
34
+ SMTP_PASS: z.string().optional(),
35
+ SMTP_FROM: z.string().default('Tailprint <noreply@tailprint.com>'),
36
+ });
37
+ export const env = envSchema.parse(process.env);
38
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/config/env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface PlanConfig {
2
+ id: string;
3
+ name: string;
4
+ priceUsd: number;
5
+ monthlyLimit: number;
6
+ stripePriceId?: string;
7
+ badge?: string;
8
+ targetAudience: string;
9
+ description: string;
10
+ features: string[];
11
+ }
12
+ export declare const PLANS: Record<string, PlanConfig>;
13
+ export declare const DEFAULT_PLAN: PlanConfig;
14
+ export declare function getPlanById(planId?: string | null): PlanConfig;
15
+ export declare function getPlanByStripePriceId(priceId?: string | null): PlanConfig;
@@ -0,0 +1,104 @@
1
+ import { env } from './env.js';
2
+ export const PLANS = {
3
+ free: {
4
+ id: 'free',
5
+ name: 'Developer Free',
6
+ priceUsd: 0,
7
+ monthlyLimit: 100,
8
+ badge: '100% FREE',
9
+ targetAudience: 'Testing in development, indie hacking & local integration',
10
+ description: 'Instant API key to test Tailprint in your local codebase with zero credit card.',
11
+ features: [
12
+ '100 PDF & image renders / month',
13
+ 'Full Tailwind CSS v3 & v4 support',
14
+ 'LLM Web Scraper & Markdown API',
15
+ 'Model Context Protocol (MCP) access',
16
+ 'No credit card required (via Stripe)',
17
+ '1-click instant upgrade to paid',
18
+ ],
19
+ },
20
+ starter: {
21
+ id: 'starter',
22
+ name: 'Starter',
23
+ priceUsd: 14,
24
+ monthlyLimit: 2500,
25
+ stripePriceId: env.STRIPE_PRICE_STARTER,
26
+ targetAudience: 'Solo developers, hobby projects, small e-commerce stores',
27
+ description: 'Zero purchase friction. Get production-grade rendering up and running in minutes.',
28
+ features: [
29
+ '2,500 PDF & image renders / month',
30
+ 'Full Tailwind CSS v3 & v4 support',
31
+ 'Instant sub-500ms execution',
32
+ 'SSRF & network sandbox security',
33
+ 'Community & documentation access',
34
+ ],
35
+ },
36
+ pro: {
37
+ id: 'pro',
38
+ name: 'Pro',
39
+ priceUsd: 39,
40
+ monthlyLimit: 20000,
41
+ stripePriceId: env.STRIPE_PRICE_PRO,
42
+ badge: 'MOST POPULAR',
43
+ targetAudience: 'Growing SaaS, agencies with multiple client projects',
44
+ description: 'Higher priority in the Chromium pool with aggressive deduplication caching.',
45
+ features: [
46
+ '20,000 PDF & image renders / month',
47
+ 'Prioritized Chromium concurrency queue',
48
+ '7-day SHA-256 image caching (Instant HIT)',
49
+ 'Custom paper sizes & print margins',
50
+ 'Priority developer support',
51
+ ],
52
+ },
53
+ business: {
54
+ id: 'business',
55
+ name: 'Business / Scale',
56
+ priceUsd: 99,
57
+ monthlyLimit: 75000,
58
+ stripePriceId: env.STRIPE_PRICE_BUSINESS,
59
+ badge: 'BEST VALUE FOR SCALE',
60
+ targetAudience: 'Fast-growing platforms needing scale without sales friction',
61
+ description: 'High-throughput scaling with elevated pool limits and self-service onboarding.',
62
+ features: [
63
+ '75,000 PDF & image renders / month',
64
+ 'Elevated concurrency pool reservation',
65
+ 'Full webhook & billing automation',
66
+ 'Multi-key team access support',
67
+ 'Direct Slack / Discord technical channel',
68
+ ],
69
+ },
70
+ enterprise: {
71
+ id: 'enterprise',
72
+ name: 'Enterprise',
73
+ priceUsd: 199,
74
+ monthlyLimit: 100000,
75
+ stripePriceId: env.STRIPE_PRICE_ENTERPRISE,
76
+ targetAudience: 'Large platforms, high volume, custom compliance & SLA',
77
+ description: 'Heavy volume with dedicated browser instances and strict uptime SLA guarantees.',
78
+ features: [
79
+ '100,000+ renders / month',
80
+ 'Dedicated Playwright Chromium workers',
81
+ '99.9% availability SLA agreement',
82
+ 'Custom pre-loaded font sets & brand assets',
83
+ 'Dedicated technical account engineer',
84
+ ],
85
+ },
86
+ };
87
+ export const DEFAULT_PLAN = PLANS.starter;
88
+ export function getPlanById(planId) {
89
+ if (!planId)
90
+ return DEFAULT_PLAN;
91
+ const normalized = planId.toLowerCase().trim();
92
+ return PLANS[normalized] ?? DEFAULT_PLAN;
93
+ }
94
+ export function getPlanByStripePriceId(priceId) {
95
+ if (!priceId)
96
+ return DEFAULT_PLAN;
97
+ for (const plan of Object.values(PLANS)) {
98
+ if (plan.stripePriceId && plan.stripePriceId === priceId) {
99
+ return plan;
100
+ }
101
+ }
102
+ return DEFAULT_PLAN;
103
+ }
104
+ //# sourceMappingURL=plans.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans.js","sourceRoot":"","sources":["../../src/config/plans.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAc/B,MAAM,CAAC,MAAM,KAAK,GAA+B;IAC/C,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,CAAC;QACX,YAAY,EAAE,GAAG;QACjB,KAAK,EAAE,WAAW;QAClB,cAAc,EAAE,2DAA2D;QAC3E,WAAW,EAAE,iFAAiF;QAC9F,QAAQ,EAAE;YACR,iCAAiC;YACjC,mCAAmC;YACnC,gCAAgC;YAChC,qCAAqC;YACrC,sCAAsC;YACtC,iCAAiC;SAClC;KACF;IACD,OAAO,EAAE;QACP,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,EAAE;QACZ,YAAY,EAAE,IAAI;QAClB,aAAa,EAAE,GAAG,CAAC,oBAAoB;QACvC,cAAc,EAAE,0DAA0D;QAC1E,WAAW,EAAE,mFAAmF;QAChG,QAAQ,EAAE;YACR,mCAAmC;YACnC,mCAAmC;YACnC,6BAA6B;YAC7B,iCAAiC;YACjC,kCAAkC;SACnC;KACF;IACD,GAAG,EAAE;QACH,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,KAAK;QACX,QAAQ,EAAE,EAAE;QACZ,YAAY,EAAE,KAAK;QACnB,aAAa,EAAE,GAAG,CAAC,gBAAgB;QACnC,KAAK,EAAE,cAAc;QACrB,cAAc,EAAE,sDAAsD;QACtE,WAAW,EAAE,6EAA6E;QAC1F,QAAQ,EAAE;YACR,oCAAoC;YACpC,wCAAwC;YACxC,2CAA2C;YAC3C,oCAAoC;YACpC,4BAA4B;SAC7B;KACF;IACD,QAAQ,EAAE;QACR,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,kBAAkB;QACxB,QAAQ,EAAE,EAAE;QACZ,YAAY,EAAE,KAAK;QACnB,aAAa,EAAE,GAAG,CAAC,qBAAqB;QACxC,KAAK,EAAE,sBAAsB;QAC7B,cAAc,EAAE,6DAA6D;QAC7E,WAAW,EAAE,gFAAgF;QAC7F,QAAQ,EAAE;YACR,oCAAoC;YACpC,uCAAuC;YACvC,mCAAmC;YACnC,+BAA+B;YAC/B,0CAA0C;SAC3C;KACF;IACD,UAAU,EAAE;QACV,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,QAAQ,EAAE,GAAG;QACb,YAAY,EAAE,MAAM;QACpB,aAAa,EAAE,GAAG,CAAC,uBAAuB;QAC1C,cAAc,EAAE,uDAAuD;QACvE,WAAW,EAAE,iFAAiF;QAC9F,QAAQ,EAAE;YACR,0BAA0B;YAC1B,uCAAuC;YACvC,kCAAkC;YAClC,4CAA4C;YAC5C,sCAAsC;SACvC;KACF;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;AAE1C,MAAM,UAAU,WAAW,CAAC,MAAsB;IAChD,IAAI,CAAC,MAAM;QAAE,OAAO,YAAY,CAAC;IACjC,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAC/C,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,YAAY,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAuB;IAC5D,IAAI,CAAC,OAAO;QAAE,OAAO,YAAY,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface TemplateItem {
2
+ id: string;
3
+ title: string;
4
+ category: string;
5
+ description: string;
6
+ format: 'A4' | 'Letter';
7
+ landscape: boolean;
8
+ html: string;
9
+ }
10
+ export declare const TEMPLATES: TemplateItem[];