@maistik/nuxt-pdf 1.0.17 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.d.mts CHANGED
@@ -7,7 +7,7 @@ interface PdfModuleOptions {
7
7
  enableI18n: boolean;
8
8
  defaultLocale: string;
9
9
  availableLocales: string[];
10
- i18nMessages: Record<string, Record<string, string>>;
10
+ i18nMessages: Record<string, Record<string, unknown>>;
11
11
  providers: {
12
12
  gotenberg: {
13
13
  url: string;
@@ -17,7 +17,7 @@ interface PdfModuleOptions {
17
17
  apiKey: string;
18
18
  };
19
19
  puppeteer: {
20
- launchOptions: Record<string, any>;
20
+ launchOptions: Record<string, unknown>;
21
21
  };
22
22
  };
23
23
  defaultOptions: {
package/dist/module.d.ts CHANGED
@@ -7,7 +7,7 @@ interface PdfModuleOptions {
7
7
  enableI18n: boolean;
8
8
  defaultLocale: string;
9
9
  availableLocales: string[];
10
- i18nMessages: Record<string, Record<string, string>>;
10
+ i18nMessages: Record<string, Record<string, unknown>>;
11
11
  providers: {
12
12
  gotenberg: {
13
13
  url: string;
@@ -17,7 +17,7 @@ interface PdfModuleOptions {
17
17
  apiKey: string;
18
18
  };
19
19
  puppeteer: {
20
- launchOptions: Record<string, any>;
20
+ launchOptions: Record<string, unknown>;
21
21
  };
22
22
  };
23
23
  defaultOptions: {
package/dist/module.json CHANGED
@@ -2,11 +2,11 @@
2
2
  "name": "@maistik/nuxt-pdf",
3
3
  "configKey": "pdf",
4
4
  "compatibility": {
5
- "nuxt": "^3.0.0"
5
+ "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "1.0.17",
7
+ "version": "1.1.4",
8
8
  "builder": {
9
- "@nuxt/module-builder": "1.0.1",
10
- "unbuild": "3.5.0"
9
+ "@nuxt/module-builder": "1.0.2",
10
+ "unbuild": "3.6.1"
11
11
  }
12
12
  }
package/dist/module.mjs CHANGED
@@ -1,13 +1,13 @@
1
- import { defineNuxtModule, createResolver, addServerHandler, addImports } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, addServerTemplate, addServerHandler, addImports } from '@nuxt/kit';
2
2
  import { existsSync, readdirSync, statSync, readFileSync } from 'fs';
3
3
  import { join } from 'path';
4
4
 
5
- const module = defineNuxtModule({
5
+ const module$1 = defineNuxtModule({
6
6
  meta: {
7
7
  name: "@maistik/nuxt-pdf",
8
8
  configKey: "pdf",
9
9
  compatibility: {
10
- nuxt: "^3.0.0"
10
+ nuxt: ">=3.0.0"
11
11
  }
12
12
  },
13
13
  defaults: {
@@ -55,14 +55,15 @@ const module = defineNuxtModule({
55
55
  const resolver = createResolver(import.meta.url);
56
56
  const templateSources = {};
57
57
  const partialSources = {};
58
+ const baseDir = nuxt.options.rootDir;
58
59
  for (const componentDir of options.components) {
59
- const fullPath = join(nuxt.options.srcDir, componentDir);
60
+ const fullPath = join(baseDir, componentDir);
60
61
  if (existsSync(fullPath)) {
61
62
  scanDirectory(fullPath, templateSources, ".hbs");
62
63
  }
63
64
  }
64
65
  for (const sharedDir of options.sharedComponents) {
65
- const fullPath = join(nuxt.options.srcDir, sharedDir);
66
+ const fullPath = join(baseDir, sharedDir);
66
67
  if (existsSync(fullPath)) {
67
68
  scanDirectory(fullPath, partialSources, ".hbs");
68
69
  }
@@ -76,9 +77,12 @@ const module = defineNuxtModule({
76
77
  providers: options.providers,
77
78
  defaultOptions: options.defaultOptions,
78
79
  templateSources,
79
- partialSources,
80
- customHelpers: options.customHelpers || {}
80
+ partialSources
81
81
  };
82
+ addServerTemplate({
83
+ filename: "#pdf-custom-helpers",
84
+ getContents: () => generateCustomHelpersModule(options.customHelpers || {})
85
+ });
82
86
  nuxt.options.runtimeConfig.public.pdf = {
83
87
  enableI18n: options.enableI18n,
84
88
  defaultLocale: options.defaultLocale,
@@ -86,6 +90,7 @@ const module = defineNuxtModule({
86
90
  };
87
91
  addServerHandler({
88
92
  route: "/api/pdf",
93
+ method: "post",
89
94
  handler: resolver.resolve("./runtime/server/api/pdf.post")
90
95
  });
91
96
  addImports({
@@ -95,6 +100,13 @@ const module = defineNuxtModule({
95
100
  });
96
101
  }
97
102
  });
103
+ function generateCustomHelpersModule(helpers) {
104
+ const entries = Object.entries(helpers).filter(([, fn]) => typeof fn === "function").map(([name, fn]) => ` ${JSON.stringify(name)}: ${fn.toString()}`);
105
+ return `export const customHelpers = {
106
+ ${entries.join(",\n")}
107
+ }
108
+ `;
109
+ }
98
110
  function scanDirectory(dir, sources, extension) {
99
111
  if (!existsSync(dir)) return;
100
112
  const files = readdirSync(dir);
@@ -110,4 +122,4 @@ function scanDirectory(dir, sources, extension) {
110
122
  }
111
123
  }
112
124
 
113
- export { module as default };
125
+ export { module$1 as default };
@@ -15,8 +15,8 @@ export interface PdfGenerateOptions {
15
15
  };
16
16
  }
17
17
  export declare function usePdf(): {
18
- generate: (template: string, data: any, options?: PdfGenerateOptions, locale?: string) => Promise<Blob>;
19
- download: (template: string, data: any, options?: PdfGenerateOptions, filename?: string, locale?: string) => Promise<void>;
18
+ generate: (template: string, data: Record<string, unknown>, options?: PdfGenerateOptions, locale?: string) => Promise<Blob>;
19
+ download: (template: string, data: Record<string, unknown>, options?: PdfGenerateOptions, filename?: string, locale?: string) => Promise<void>;
20
20
  getAvailableLocales: () => string[];
21
21
  getDefaultLocale: () => string;
22
22
  };
@@ -1,23 +1,43 @@
1
- import { defineEventHandler, readBody, setHeader } from "h3";
1
+ import { defineEventHandler, readBody, setHeader, createError, isError } from "h3";
2
2
  import { useRuntimeConfig } from "#imports";
3
+ import { customHelpers } from "#pdf-custom-helpers";
3
4
  import { compilePdfComponent } from "../../utils/compiler.js";
4
5
  import { createPdfProvider } from "../../utils/providers.js";
5
6
  export default defineEventHandler(async (event) => {
7
+ const config = useRuntimeConfig();
8
+ const body = await readBody(event);
9
+ const template = body?.template;
10
+ const ctx = body?.ctx;
11
+ if (typeof template !== "string" || template.length === 0) {
12
+ throw createError({
13
+ statusCode: 400,
14
+ statusMessage: 'Missing or invalid "template"'
15
+ });
16
+ }
17
+ if (!ctx || typeof ctx !== "object") {
18
+ throw createError({
19
+ statusCode: 400,
20
+ statusMessage: 'Missing or invalid "ctx"'
21
+ });
22
+ }
23
+ const templateSources = config.pdf.templateSources;
24
+ if (!Object.prototype.hasOwnProperty.call(templateSources, template)) {
25
+ throw createError({
26
+ statusCode: 404,
27
+ statusMessage: `Template "${template}" not found`
28
+ });
29
+ }
30
+ const { data, options = {}, locale } = ctx;
31
+ const mergedOptions = { ...config.pdf.defaultOptions, ...options };
32
+ const messages = config.pdf.enableI18n ? config.pdf.i18nMessages[locale || config.pdf.defaultLocale] || {} : {};
6
33
  try {
7
- const config = useRuntimeConfig();
8
- const { template, ctx } = await readBody(event);
9
- if (!template || !ctx) {
10
- throw new Error("Missing template or context");
11
- }
12
- const { data, options = {}, locale } = ctx;
13
- const mergedOptions = { ...config.pdf.defaultOptions, ...options };
14
- const messages = config.pdf.enableI18n ? config.pdf.i18nMessages[locale || config.pdf.defaultLocale] || {} : {};
15
34
  const html = compilePdfComponent(
16
35
  template,
17
36
  { data, options: mergedOptions, locale },
18
37
  messages,
19
- config.pdf.templateSources,
20
- config.pdf.partialSources
38
+ templateSources,
39
+ config.pdf.partialSources,
40
+ customHelpers
21
41
  );
22
42
  const provider = createPdfProvider(config.pdf.provider, config.pdf.providers);
23
43
  const pdfBuffer = await provider.generatePdf(html, mergedOptions);
@@ -26,6 +46,12 @@ export default defineEventHandler(async (event) => {
26
46
  return pdfBuffer;
27
47
  } catch (error) {
28
48
  console.error("PDF generation error:", error);
29
- throw error;
49
+ if (isError(error)) {
50
+ throw error;
51
+ }
52
+ throw createError({
53
+ statusCode: 500,
54
+ statusMessage: "Failed to generate PDF"
55
+ });
30
56
  }
31
57
  });
@@ -1,5 +1,5 @@
1
1
  export interface PdfContext {
2
- data: any;
2
+ data: Record<string, unknown>;
3
3
  options: PdfOptions;
4
4
  locale?: string;
5
5
  }
@@ -28,9 +28,9 @@ export interface PdfProviderConfig {
28
28
  apiKey: string;
29
29
  };
30
30
  puppeteer: {
31
- launchOptions: Record<string, any>;
31
+ launchOptions: Record<string, unknown>;
32
32
  };
33
33
  }
34
34
  export interface PdfProvider {
35
- generatePdf(html: string, options: any): Promise<Buffer>;
35
+ generatePdf(html: string, options: PdfOptions): Promise<Buffer>;
36
36
  }
@@ -1,5 +1,6 @@
1
+ import type { HelperDelegate } from 'handlebars';
1
2
  export declare function compilePdfComponent(templateName: string, ctx: {
2
- data: any;
3
- options: any;
3
+ data: Record<string, unknown>;
4
+ options: Record<string, unknown>;
4
5
  locale?: string;
5
- }, messages: Record<string, string>, templateSources: Record<string, string>, partialSources: Record<string, string>): string;
6
+ }, messages: Record<string, string>, templateSources: Record<string, string>, partialSources: Record<string, string>, customHelpers?: Record<string, HelperDelegate>): string;
@@ -1,12 +1,11 @@
1
- import { useRuntimeConfig } from "#imports";
2
1
  import Handlebars from "handlebars";
3
- export function compilePdfComponent(templateName, ctx, messages, templateSources, partialSources) {
2
+ export function compilePdfComponent(templateName, ctx, messages, templateSources, partialSources, customHelpers = {}) {
4
3
  const handlebars = Handlebars.create();
5
4
  handlebars.registerHelper("t", function(key) {
6
5
  const keys = key.split(".");
7
6
  let value = messages;
8
7
  for (const k of keys) {
9
- if (value && typeof value === "object" && k in value) {
8
+ if (value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, k)) {
10
9
  value = value[k];
11
10
  } else {
12
11
  return key;
@@ -21,8 +20,11 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
21
20
  let currency = "USD";
22
21
  if (typeof currencyOrOptions === "string") {
23
22
  currency = currencyOrOptions;
24
- } else if (currencyOrOptions && typeof currencyOrOptions.hash?.currency === "string") {
25
- currency = currencyOrOptions.hash.currency;
23
+ } else {
24
+ const hash = currencyOrOptions?.hash;
25
+ if (typeof hash?.currency === "string") {
26
+ currency = hash.currency;
27
+ }
26
28
  }
27
29
  if (!/^[A-Z]{3}$/.test(currency)) {
28
30
  currency = "USD";
@@ -42,20 +44,29 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
42
44
  }
43
45
  return isEqual;
44
46
  });
45
- handlebars.registerHelper(
46
- "ne",
47
- (a, b, opts) => a !== b ? opts.fn(this) : opts.inverse(this)
48
- );
49
- handlebars.registerHelper(
50
- "gt",
51
- (a, b, opts) => a > b ? opts.fn(this) : opts.inverse(this)
52
- );
47
+ handlebars.registerHelper("ne", function(a, b, options) {
48
+ const result = a !== b;
49
+ if (options && typeof options.fn === "function") {
50
+ return result ? options.fn(this) : options.inverse(this);
51
+ }
52
+ return result;
53
+ });
54
+ handlebars.registerHelper("gt", function(a, b, options) {
55
+ const result = a > b;
56
+ if (options && typeof options.fn === "function") {
57
+ return result ? options.fn(this) : options.inverse(this);
58
+ }
59
+ return result;
60
+ });
53
61
  handlebars.registerHelper("formatDate", function(date, formatOrOptions) {
54
62
  let style = "short";
55
63
  if (typeof formatOrOptions === "string") {
56
64
  style = formatOrOptions;
57
- } else if (formatOrOptions && typeof formatOrOptions.hash?.format === "string") {
58
- style = formatOrOptions.hash.format;
65
+ } else {
66
+ const hash = formatOrOptions?.hash;
67
+ if (typeof hash?.format === "string") {
68
+ style = hash.format;
69
+ }
59
70
  }
60
71
  if (!["full", "long", "medium", "short"].includes(style)) {
61
72
  style = "short";
@@ -75,22 +86,17 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
75
86
  dateStyle: style
76
87
  }).format(dateObj);
77
88
  });
78
- handlebars.registerHelper("formatNumber", function(value, options = {}) {
89
+ handlebars.registerHelper("formatNumber", function(value, options) {
79
90
  if (typeof value !== "number") return value;
80
- return new Intl.NumberFormat(ctx.locale || "en-US", options).format(value);
81
- });
82
- try {
83
- const config = useRuntimeConfig();
84
- const customHelpers = config.pdf.customHelpers;
85
- if (customHelpers && typeof customHelpers === "object") {
86
- Object.entries(customHelpers).forEach(([name, helper]) => {
87
- if (typeof helper === "function") {
88
- handlebars.registerHelper(name, helper);
89
- }
90
- });
91
+ const intlOptions = options && typeof options.hash === "object" ? options.hash : {};
92
+ return new Intl.NumberFormat(ctx.locale || "en-US", intlOptions).format(value);
93
+ });
94
+ if (customHelpers && typeof customHelpers === "object") {
95
+ for (const [name, helper] of Object.entries(customHelpers)) {
96
+ if (typeof helper === "function") {
97
+ handlebars.registerHelper(name, helper);
98
+ }
91
99
  }
92
- } catch (error) {
93
- console.warn("Failed to load custom helpers:", error);
94
100
  }
95
101
  handlebars.registerHelper("upper", function(str) {
96
102
  return String(str || "").toUpperCase();
@@ -138,13 +144,15 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
138
144
  function enrichContextForTemplate(templateName, data) {
139
145
  const enriched = { ...data };
140
146
  if (templateName.toLowerCase().includes("invoice")) {
141
- if (enriched.items && Array.isArray(enriched.items)) {
142
- enriched.subtotal = enriched.items.reduce((sum, item) => {
143
- return sum + item.quantity * item.price;
144
- }, 0);
145
- enriched.tax = enriched.subtotal * (enriched.taxRate || 0.1);
146
- enriched.total = enriched.subtotal + enriched.tax;
147
- if (enriched.issueDate && enriched.paymentTerms) {
147
+ if (Array.isArray(enriched.items)) {
148
+ const items = enriched.items;
149
+ const subtotal = items.reduce((sum, item) => sum + item.quantity * item.price, 0);
150
+ const taxRate = typeof enriched.taxRate === "number" ? enriched.taxRate : 0.1;
151
+ const tax = subtotal * taxRate;
152
+ enriched.subtotal = subtotal;
153
+ enriched.tax = tax;
154
+ enriched.total = subtotal + tax;
155
+ if (enriched.issueDate && typeof enriched.paymentTerms === "number") {
148
156
  const issueDate = new Date(enriched.issueDate);
149
157
  const dueDate = new Date(issueDate);
150
158
  dueDate.setDate(dueDate.getDate() + enriched.paymentTerms);
@@ -153,9 +161,10 @@ function enrichContextForTemplate(templateName, data) {
153
161
  }
154
162
  }
155
163
  if (templateName.toLowerCase().includes("salesreport")) {
156
- if (enriched.salesData && Array.isArray(enriched.salesData)) {
157
- enriched.quarters = calculateQuarters(enriched.salesData);
158
- const totalSales = enriched.salesData.reduce((sum, item) => sum + item.amount, 0);
164
+ if (Array.isArray(enriched.salesData)) {
165
+ const salesData = enriched.salesData;
166
+ enriched.quarters = calculateQuarters(salesData);
167
+ const totalSales = salesData.reduce((sum, item) => sum + item.amount, 0);
159
168
  enriched.rating = calculatePerformanceRating(totalSales);
160
169
  }
161
170
  }
@@ -1,2 +1,2 @@
1
- import type { PdfProvider } from '../types.js';
2
- export declare function createPdfProvider(providerType: string, config: any): PdfProvider;
1
+ import type { PdfProvider, PdfProviderConfig } from '../types.js';
2
+ export declare function createPdfProvider(providerType: string, config: Partial<PdfProviderConfig>): PdfProvider;
@@ -29,10 +29,10 @@ class GotenbergProvider {
29
29
  form.append("paperHeight", dimensions.height);
30
30
  }
31
31
  if (options.margin) {
32
- form.append("marginTop", (options.margin.top / 25.4).toString());
33
- form.append("marginBottom", (options.margin.bottom / 25.4).toString());
34
- form.append("marginLeft", (options.margin.left / 25.4).toString());
35
- form.append("marginRight", (options.margin.right / 25.4).toString());
32
+ form.append("marginTop", ((options.margin.top ?? 0) / 25.4).toString());
33
+ form.append("marginBottom", ((options.margin.bottom ?? 0) / 25.4).toString());
34
+ form.append("marginLeft", ((options.margin.left ?? 0) / 25.4).toString());
35
+ form.append("marginRight", ((options.margin.right ?? 0) / 25.4).toString());
36
36
  }
37
37
  if (options.landscape) {
38
38
  form.append("landscape", "true");
@@ -97,22 +97,58 @@ class PuppeteerProvider {
97
97
  constructor(config) {
98
98
  this.config = config;
99
99
  }
100
+ // Launching a full Chromium per request is slow and flaky (especially on CI),
101
+ // so we keep one browser alive and reuse it, relaunching if it disconnects.
102
+ static browser = null;
103
+ static launching = null;
104
+ async getBrowser() {
105
+ const existing = PuppeteerProvider.browser;
106
+ if (existing?.connected) {
107
+ return existing;
108
+ }
109
+ if (!PuppeteerProvider.launching) {
110
+ PuppeteerProvider.launching = (async () => {
111
+ const puppeteer = await import("puppeteer").then((m) => m.default);
112
+ const launchOptions = this.config.launchOptions;
113
+ const browser = await puppeteer.launch({
114
+ // `--disable-dev-shm-usage` avoids Chromium exhausting the small
115
+ // /dev/shm tmpfs in CI/Docker, a common cause of hangs and crashes.
116
+ ...launchOptions,
117
+ args: ["--disable-dev-shm-usage", ...launchOptions?.args ?? []]
118
+ });
119
+ PuppeteerProvider.browser = browser;
120
+ browser.on("disconnected", () => {
121
+ PuppeteerProvider.browser = null;
122
+ });
123
+ return browser;
124
+ })();
125
+ try {
126
+ await PuppeteerProvider.launching;
127
+ } finally {
128
+ PuppeteerProvider.launching = null;
129
+ }
130
+ } else {
131
+ await PuppeteerProvider.launching;
132
+ }
133
+ return PuppeteerProvider.browser;
134
+ }
100
135
  async generatePdf(html, options) {
101
- const puppeteer = await import("puppeteer").then((m) => m.default);
102
- const browser = await puppeteer.launch(this.config.launchOptions);
136
+ const browser = await this.getBrowser();
137
+ const page = await browser.newPage();
103
138
  try {
104
- const page = await browser.newPage();
105
- await page.setContent(html, { waitUntil: "networkidle0" });
139
+ await page.setContent(html, { waitUntil: "domcontentloaded", timeout: 3e4 });
106
140
  const pdfOptions = {
107
141
  format: options.format || "A4",
108
142
  margin: options.margin,
109
143
  landscape: options.landscape || false,
110
- printBackground: options.printBackground !== false
144
+ printBackground: options.printBackground !== false,
145
+ timeout: 3e4
111
146
  };
112
147
  const pdfBuffer = await page.pdf(pdfOptions);
113
148
  return Buffer.from(pdfBuffer);
114
149
  } finally {
115
- await browser.close();
150
+ await page.close().catch(() => {
151
+ });
116
152
  }
117
153
  }
118
154
  }
package/package.json CHANGED
@@ -1,50 +1,39 @@
1
1
  {
2
2
  "name": "@maistik/nuxt-pdf",
3
- "version": "1.0.17",
4
- "description": "A Nuxt 3 module for server-side PDF generation using Handlebars templates",
3
+ "version": "1.1.4",
4
+ "description": "A Nuxt 3 & 4 module for server-side PDF generation using Handlebars templates",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "main": "./dist/module.mjs",
8
8
  "files": [
9
9
  "dist"
10
10
  ],
11
- "scripts": {
12
- "build": "nuxt-module-build prepare && nuxt-module-build build",
13
- "dev": "nuxi dev playground",
14
- "dev:build": "nuxi build playground",
15
- "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
16
- "release": "npm run lint && npm run test:unit && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
17
- "lint": "eslint .",
18
- "lint:fix": "eslint . --fix",
19
- "test": "vitest run && playwright test",
20
- "test:watch": "vitest watch",
21
- "test:unit": "vitest run",
22
- "test:e2e": "playwright test",
23
- "test:e2e:ui": "playwright test --ui",
24
- "prepack": "nuxt-module-build build"
11
+ "engines": {
12
+ "node": ">=22.0.0"
25
13
  },
26
14
  "dependencies": {
27
- "@nuxt/kit": "^3.17.7",
28
- "handlebars": "^4.7.8",
29
- "puppeteer": "^24.14.0",
30
- "form-data": "^4.0.4"
15
+ "@nuxt/kit": "^4.4.8",
16
+ "handlebars": "^4.7.9",
17
+ "puppeteer": "^25.1.0",
18
+ "form-data": "^4.0.6"
31
19
  },
32
20
  "devDependencies": {
33
21
  "@nuxt/devtools": "latest",
34
- "@nuxt/eslint-config": "^1.6.0",
35
- "@nuxt/module-builder": "^1.0.1",
36
- "@nuxt/schema": "^3.17.7",
37
- "@nuxt/test-utils": "^3.19.2",
38
- "@playwright/test": "^1.49.1",
22
+ "@nuxt/eslint-config": "^1.16.0",
23
+ "@nuxt/module-builder": "^1.0.2",
24
+ "@nuxt/schema": "^4.4.8",
25
+ "@nuxt/test-utils": "^4.0.3",
26
+ "@playwright/test": "^1.60.0",
39
27
  "changelogen": "^0.6.2",
40
- "eslint": "^9.31.0",
41
- "nuxt": "^3.17.7",
42
- "unbuild": "^3.5.0",
43
- "vitest": "^3.2.4"
28
+ "eslint": "^10.5.0",
29
+ "nuxt": "^4.4.8",
30
+ "unbuild": "^3.6.1",
31
+ "vitest": "^4.1.8"
44
32
  },
45
33
  "keywords": [
46
34
  "nuxt",
47
35
  "nuxt3",
36
+ "nuxt4",
48
37
  "pdf",
49
38
  "handlebars",
50
39
  "gotenberg",
@@ -57,5 +46,18 @@
57
46
  "type": "git",
58
47
  "url": "https://github.com/Maistik-Studio/nuxt-pdf"
59
48
  },
60
- "packageManager": "pnpm@9.15.3"
61
- }
49
+ "scripts": {
50
+ "build": "nuxt-module-build prepare && nuxt-module-build build",
51
+ "dev": "nuxi dev playground",
52
+ "dev:build": "nuxi build playground",
53
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
54
+ "release": "npm run lint && npm run test:unit && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
55
+ "lint": "eslint .",
56
+ "lint:fix": "eslint . --fix",
57
+ "test": "vitest run && playwright test",
58
+ "test:watch": "vitest watch",
59
+ "test:unit": "vitest run",
60
+ "test:e2e": "playwright test",
61
+ "test:e2e:ui": "playwright test --ui"
62
+ }
63
+ }