@beeblock/svelar 0.4.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 +110 -0
- package/dist/actions/index.d.ts +101 -0
- package/dist/actions/index.js +1 -0
- package/dist/api-keys/index.d.ts +58 -0
- package/dist/api-keys/index.js +1 -0
- package/dist/audit/index.d.ts +52 -0
- package/dist/audit/index.js +1 -0
- package/dist/auth/Auth.d.ts +283 -0
- package/dist/auth/Gate.d.ts +166 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +80 -0
- package/dist/broadcasting/client.d.ts +195 -0
- package/dist/broadcasting/client.js +1 -0
- package/dist/broadcasting/index.d.ts +318 -0
- package/dist/broadcasting/index.js +20 -0
- package/dist/cache/index.d.ts +77 -0
- package/dist/cache/index.js +1 -0
- package/dist/cli/Cli.d.ts +23 -0
- package/dist/cli/Command.d.ts +36 -0
- package/dist/cli/bin.d.ts +8 -0
- package/dist/cli/bin.js +5856 -0
- package/dist/cli/commands/KeyGenerateCommand.d.ts +16 -0
- package/dist/cli/commands/MakeActionCommand.d.ts +15 -0
- package/dist/cli/commands/MakeBroadcastingCommand.d.ts +29 -0
- package/dist/cli/commands/MakeChannelCommand.d.ts +18 -0
- package/dist/cli/commands/MakeCommandCommand.d.ts +16 -0
- package/dist/cli/commands/MakeConfigCommand.d.ts +13 -0
- package/dist/cli/commands/MakeControllerCommand.d.ts +28 -0
- package/dist/cli/commands/MakeDashboardCommand.d.ts +34 -0
- package/dist/cli/commands/MakeDockerCommand.d.ts +32 -0
- package/dist/cli/commands/MakeEventCommand.d.ts +11 -0
- package/dist/cli/commands/MakeJobCommand.d.ts +11 -0
- package/dist/cli/commands/MakeListenerCommand.d.ts +16 -0
- package/dist/cli/commands/MakeMiddlewareCommand.d.ts +11 -0
- package/dist/cli/commands/MakeMigrationCommand.d.ts +17 -0
- package/dist/cli/commands/MakeModelCommand.d.ts +25 -0
- package/dist/cli/commands/MakeObserverCommand.d.ts +23 -0
- package/dist/cli/commands/MakePluginCommand.d.ts +11 -0
- package/dist/cli/commands/MakeProviderCommand.d.ts +11 -0
- package/dist/cli/commands/MakeRepositoryCommand.d.ts +22 -0
- package/dist/cli/commands/MakeRequestCommand.d.ts +15 -0
- package/dist/cli/commands/MakeResourceCommand.d.ts +30 -0
- package/dist/cli/commands/MakeRouteCommand.d.ts +42 -0
- package/dist/cli/commands/MakeSchemaCommand.d.ts +20 -0
- package/dist/cli/commands/MakeSeederCommand.d.ts +11 -0
- package/dist/cli/commands/MakeServiceCommand.d.ts +28 -0
- package/dist/cli/commands/MakeTaskCommand.d.ts +12 -0
- package/dist/cli/commands/MigrateCommand.d.ts +26 -0
- package/dist/cli/commands/NewCommand.d.ts +21 -0
- package/dist/cli/commands/NewCommandTemplates.d.ts +123 -0
- package/dist/cli/commands/PluginInstallCommand.d.ts +16 -0
- package/dist/cli/commands/PluginListCommand.d.ts +11 -0
- package/dist/cli/commands/PluginPublishCommand.d.ts +22 -0
- package/dist/cli/commands/QueueFailedCommand.d.ts +9 -0
- package/dist/cli/commands/QueueFlushCommand.d.ts +9 -0
- package/dist/cli/commands/QueueRetryCommand.d.ts +16 -0
- package/dist/cli/commands/QueueWorkCommand.d.ts +25 -0
- package/dist/cli/commands/RoutesListCommand.d.ts +30 -0
- package/dist/cli/commands/ScheduleRunCommand.d.ts +15 -0
- package/dist/cli/commands/SeedCommand.d.ts +14 -0
- package/dist/cli/commands/TinkerCommand.d.ts +10 -0
- package/dist/cli/index.d.ts +36 -0
- package/dist/cli/index.js +1973 -0
- package/dist/cli/ts-resolve-hook.mjs +74 -0
- package/dist/cli/ts-resolver.mjs +8 -0
- package/dist/config/Config.d.ts +65 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +1 -0
- package/dist/container/Application.d.ts +33 -0
- package/dist/container/Container.d.ts +70 -0
- package/dist/container/ServiceProvider.d.ts +21 -0
- package/dist/container/index.d.ts +3 -0
- package/dist/container/index.js +1 -0
- package/dist/dashboard/index.d.ts +123 -0
- package/dist/dashboard/index.js +5 -0
- package/dist/database/Connection.d.ts +80 -0
- package/dist/database/Migration.d.ts +76 -0
- package/dist/database/SchemaBuilder.d.ts +91 -0
- package/dist/database/Seeder.d.ts +9 -0
- package/dist/database/index.d.ts +4 -0
- package/dist/database/index.js +4 -0
- package/dist/email-templates/index.d.ts +51 -0
- package/dist/email-templates/index.js +57 -0
- package/dist/errors/Handler.d.ts +100 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +5 -0
- package/dist/events/EventServiceProvider.d.ts +82 -0
- package/dist/events/Listener.d.ts +28 -0
- package/dist/events/index.d.ts +80 -0
- package/dist/events/index.js +1 -0
- package/dist/excel/index.d.ts +154 -0
- package/dist/excel/index.js +1 -0
- package/dist/feature-flags/index.d.ts +158 -0
- package/dist/feature-flags/index.js +59 -0
- package/dist/forms/index.d.ts +81 -0
- package/dist/forms/index.js +1 -0
- package/dist/hashing/Hash.d.ts +51 -0
- package/dist/hashing/index.d.ts +1 -0
- package/dist/hashing/index.js +1 -0
- package/dist/hooks/index.d.ts +135 -0
- package/dist/hooks/index.js +5 -0
- package/dist/http/index.d.ts +201 -0
- package/dist/http/index.js +2 -0
- package/dist/i18n/index.d.ts +81 -0
- package/dist/i18n/index.js +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +127 -0
- package/dist/logging/LogViewer.d.ts +95 -0
- package/dist/logging/LogViewer.js +1 -0
- package/dist/logging/index.d.ts +83 -0
- package/dist/logging/index.js +3 -0
- package/dist/mail/index.d.ts +149 -0
- package/dist/mail/index.js +1 -0
- package/dist/middleware/Middleware.d.ts +208 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +1 -0
- package/dist/notifications/index.d.ts +85 -0
- package/dist/notifications/index.js +2 -0
- package/dist/orm/Model.d.ts +123 -0
- package/dist/orm/Observer.d.ts +34 -0
- package/dist/orm/QueryBuilder.d.ts +119 -0
- package/dist/orm/Relationship.d.ts +58 -0
- package/dist/orm/index.d.ts +4 -0
- package/dist/orm/index.js +1 -0
- package/dist/pagination/index.d.ts +8 -0
- package/dist/pagination/index.js +0 -0
- package/dist/pdf/GeneratePdfJob.d.ts +99 -0
- package/dist/pdf/GeneratePdfJob.js +41 -0
- package/dist/pdf/index.d.ts +328 -0
- package/dist/pdf/index.js +41 -0
- package/dist/permissions/index.d.ts +161 -0
- package/dist/permissions/index.js +60 -0
- package/dist/plugins/BootstrapPlugins.d.ts +11 -0
- package/dist/plugins/PluginInstaller.d.ts +30 -0
- package/dist/plugins/PluginInstaller.js +1 -0
- package/dist/plugins/PluginPublisher.d.ts +32 -0
- package/dist/plugins/PluginPublisher.js +1 -0
- package/dist/plugins/PluginRegistry.d.ts +55 -0
- package/dist/plugins/PluginRegistry.js +1 -0
- package/dist/plugins/index.d.ts +206 -0
- package/dist/plugins/index.js +1 -0
- package/dist/queue/JobMonitor.d.ts +109 -0
- package/dist/queue/JobMonitor.js +5 -0
- package/dist/queue/index.d.ts +279 -0
- package/dist/queue/index.js +5 -0
- package/dist/repositories/index.d.ts +147 -0
- package/dist/repositories/index.js +1 -0
- package/dist/routing/Controller.d.ts +115 -0
- package/dist/routing/FormRequest.d.ts +94 -0
- package/dist/routing/Resource.d.ts +213 -0
- package/dist/routing/Response.d.ts +138 -0
- package/dist/routing/index.d.ts +4 -0
- package/dist/routing/index.js +5 -0
- package/dist/scheduler/ScheduleMonitor.d.ts +141 -0
- package/dist/scheduler/ScheduleMonitor.js +1 -0
- package/dist/scheduler/SchedulerLock.d.ts +33 -0
- package/dist/scheduler/index.d.ts +208 -0
- package/dist/scheduler/index.js +34 -0
- package/dist/services/index.d.ts +79 -0
- package/dist/services/index.js +1 -0
- package/dist/session/Session.d.ts +166 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.js +16 -0
- package/dist/storage/index.d.ts +154 -0
- package/dist/storage/index.js +1 -0
- package/dist/support/Pipeline.d.ts +65 -0
- package/dist/support/date.d.ts +136 -0
- package/dist/support/date.js +1 -0
- package/dist/support/index.d.ts +8 -0
- package/dist/support/index.js +1 -0
- package/dist/support/singleton.d.ts +10 -0
- package/dist/support/uuid.d.ts +40 -0
- package/dist/teams/index.d.ts +91 -0
- package/dist/teams/index.js +78 -0
- package/dist/uploads/index.d.ts +63 -0
- package/dist/uploads/index.js +2 -0
- package/dist/validation/index.d.ts +46 -0
- package/dist/validation/index.js +1 -0
- package/dist/webhooks/index.d.ts +66 -0
- package/dist/webhooks/index.js +1 -0
- package/package.json +338 -0
- package/src/i18n/LanguageSwitcher.svelte +47 -0
- package/src/i18n/index.ts +113 -0
- package/src/ui/Alert.svelte +22 -0
- package/src/ui/Avatar.svelte +18 -0
- package/src/ui/AvatarFallback.svelte +18 -0
- package/src/ui/AvatarImage.svelte +12 -0
- package/src/ui/Badge.svelte +27 -0
- package/src/ui/Button.svelte +51 -0
- package/src/ui/Card.svelte +15 -0
- package/src/ui/CardContent.svelte +15 -0
- package/src/ui/CardDescription.svelte +15 -0
- package/src/ui/CardFooter.svelte +15 -0
- package/src/ui/CardHeader.svelte +15 -0
- package/src/ui/CardTitle.svelte +15 -0
- package/src/ui/Icon.svelte +81 -0
- package/src/ui/Input.svelte +40 -0
- package/src/ui/Label.svelte +20 -0
- package/src/ui/Separator.svelte +10 -0
- package/src/ui/Tabs.svelte +23 -0
- package/src/ui/TabsContent.svelte +27 -0
- package/src/ui/TabsList.svelte +19 -0
- package/src/ui/TabsTrigger.svelte +28 -0
- package/src/ui/Toaster.svelte +279 -0
- package/src/ui/index.ts +31 -0
- package/src/ui/toast.ts +212 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var pe=Object.defineProperty;var y=(a,e)=>()=>(a&&(e=a(a=0)),e);var S=(a,e)=>{for(var t in e)pe(a,t,{get:e[t],enumerable:!0})};function v(a,e){let t=Symbol.for(a),r=globalThis;return r[t]||(r[t]=e()),r[t]}var F=y(()=>{"use strict"});var j={};S(j,{Connection:()=>me});var O,me,J=y(()=>{"use strict";F();O=class{connections=new Map;config=null;defaultName="default";configure(e){this.config=e,this.defaultName=e.default}async connection(e){let t=e??this.defaultName;if(this.connections.has(t))return this.connections.get(t).drizzle;if(!this.config)throw new Error("Database not configured. Call Connection.configure() first, or register DatabaseServiceProvider.");let r=this.config.connections[t];if(!r)throw new Error(`Database connection "${t}" is not defined in configuration.`);let n=await this.createConnection(r);return this.connections.set(t,n),n.drizzle}async rawClient(e){let t=e??this.defaultName;return await this.connection(t),this.connections.get(t).rawClient}async raw(e,t=[],r){let n=await this.connection(r),i=this.getConfig(r);switch(i.driver){case"sqlite":{let s=await this.rawClient(r),d=t.map(l=>typeof l=="boolean"?l?1:0:l instanceof Date?l.toISOString():l),o=s.prepare(e),c=e.trimStart().toUpperCase();return c.startsWith("SELECT")||c.startsWith("PRAGMA")||c.startsWith("WITH")?o.all(...d):o.run(...d)}case"postgres":return(await this.rawClient(r))(e,...t);case"mysql":{let s=await this.rawClient(r),[d]=await s.execute(e,t);return d}default:throw new Error(`Unsupported driver: ${i.driver}`)}}getDriver(e){return this.getConfig(e).driver}getConfig(e){let t=e??this.defaultName;if(!this.config)throw new Error("Database not configured.");let r=this.config.connections[t];if(!r)throw new Error(`Database connection "${t}" is not defined.`);return r}async disconnect(e){if(e){let t=this.connections.get(e);t&&(await this.closeConnection(t),this.connections.delete(e))}else{for(let[t,r]of this.connections)await this.closeConnection(r);this.connections.clear()}}isConnected(e){return this.connections.has(e??this.defaultName)}async transaction(e,t){let r=this.getConfig(t),n=await this.rawClient(t);switch(r.driver){case"sqlite":{n.exec("BEGIN");try{let i=await e();return n.exec("COMMIT"),i}catch(i){throw n.exec("ROLLBACK"),i}}case"postgres":{await n`BEGIN`;try{let i=await e();return await n`COMMIT`,i}catch(i){throw await n`ROLLBACK`,i}}case"mysql":{let i=await n.getConnection();await i.beginTransaction();try{let s=await e();return await i.commit(),i.release(),s}catch(s){throw await i.rollback(),i.release(),s}}default:throw new Error(`Unsupported driver: ${r.driver}`)}}async createConnection(e){switch(e.driver){case"sqlite":return this.createSQLiteConnection(e);case"postgres":return this.createPostgresConnection(e);case"mysql":return this.createMySQLConnection(e);default:throw new Error(`Unsupported database driver: ${e.driver}`)}}async createSQLiteConnection(e){let t=e.filename??e.database??":memory:";try{let r=(await import("better-sqlite3")).default,{drizzle:n}=await import("drizzle-orm/better-sqlite3"),i=new r(t);return i.pragma("journal_mode = WAL"),i.pragma("foreign_keys = ON"),{drizzle:n(i),config:e,rawClient:i}}catch(r){let n;try{n=(await new Function("mod","return import(mod)")("node:sqlite")).DatabaseSync}catch{throw new Error(`No SQLite driver available. Install better-sqlite3 (npm install better-sqlite3) or use Node.js v22+ which includes built-in SQLite support. Original error: ${r instanceof Error?r.message:String(r)}`)}let i=new n(t);i.exec("PRAGMA journal_mode = WAL"),i.exec("PRAGMA foreign_keys = ON");let s={prepare(o){let c=i.prepare(o);return{all(...l){return c.all(...l)},run(...l){return c.run(...l)},get(...l){return c.get(...l)}}},exec(o){i.exec(o)},pragma(o){return i.prepare(`PRAGMA ${o}`).all()},close(){i.close()}},d;try{let{drizzle:o}=await import("drizzle-orm/better-sqlite3");d=o(s)}catch{d=s}return{drizzle:d,config:e,rawClient:s}}}async createPostgresConnection(e){let t=(await import("postgres")).default,{drizzle:r}=await import("drizzle-orm/postgres-js"),n=e.url??`postgres://${e.user}:${e.password}@${e.host??"localhost"}:${e.port??5432}/${e.database}`,i=t(n);return{drizzle:r(i),config:e,rawClient:i}}async createMySQLConnection(e){let t=await import("mysql2/promise"),{drizzle:r}=await import("drizzle-orm/mysql2"),n=t.createPool({host:e.host??"localhost",port:e.port??3306,database:e.database,user:e.user,password:e.password,uri:e.url});return{drizzle:r(n),config:e,rawClient:n}}async closeConnection(e){try{switch(e.config.driver){case"sqlite":e.rawClient.close();break;case"postgres":await e.rawClient.end();break;case"mysql":await e.rawClient.end();break}}catch{}}},me=v("svelar.connection",()=>new O)});var ne={};S(ne,{Job:()=>$,Queue:()=>be});var $,z,I,C,A,Q,U,W,G,be,se=y(()=>{"use strict";F();$=class{attempts=0;maxAttempts=3;retryDelay=60;queue="default";failed(e){console.error(`[Queue] Job ${this.constructor.name} permanently failed:`,e.message)}retrying(e){}serialize(){let e={};for(let[t,r]of Object.entries(this))typeof r!="function"&&(e[t]=r);return JSON.stringify(e)}restore(e){for(let[t,r]of Object.entries(e))t!=="attempts"&&t!=="maxAttempts"&&t!=="retryDelay"&&t!=="queue"&&(this[t]=r)}},z=class{async push(e){try{e.job.attempts=1,await e.job.handle()}catch(t){if(e.attempts+1<e.maxAttempts)return e.attempts++,e.job.attempts=e.attempts+1,e.job.retrying(e.job.attempts),this.push(e);e.job.failed(t)}}async pop(){return null}async size(){return 0}async clear(){}},I=class{queues=new Map;async push(e){let t=e.queue;this.queues.has(t)||this.queues.set(t,[]),this.queues.get(t).push(e)}async pop(e="default"){let t=this.queues.get(e)??[],r=Date.now(),n=t.findIndex(i=>i.availableAt<=r);return n===-1?null:t.splice(n,1)[0]}async size(e="default"){return this.queues.get(e)?.length??0}async clear(e){e?this.queues.delete(e):this.queues.clear()}},C=class{constructor(e,t){this.table=e;this.registry=t}async getConnection(){let{Connection:e}=await Promise.resolve().then(()=>(J(),j));return e}async push(e){await(await this.getConnection()).raw(`INSERT INTO ${this.table} (id, queue, payload, attempts, max_attempts, available_at, created_at)
|
|
2
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,[e.id,e.queue,JSON.stringify({jobClass:e.jobClass,payload:e.payload}),e.attempts,e.maxAttempts,Math.floor(e.availableAt/1e3),Math.floor(e.createdAt/1e3)])}async pop(e="default"){let t=await this.getConnection(),r=Math.floor(Date.now()/1e3),n=await t.raw(`SELECT * FROM ${this.table}
|
|
3
|
+
WHERE queue = ? AND available_at <= ? AND reserved_at IS NULL
|
|
4
|
+
ORDER BY created_at ASC LIMIT 1`,[e,r]);if(!n||n.length===0)return null;let i=n[0];await t.raw(`UPDATE ${this.table} SET reserved_at = ?, attempts = attempts + 1 WHERE id = ?`,[r,i.id]);let s=JSON.parse(i.payload),d=this.registry.resolve(s.jobClass,s.payload);return{id:i.id,jobClass:s.jobClass,payload:s.payload,queue:i.queue,attempts:i.attempts+1,maxAttempts:i.max_attempts,availableAt:i.available_at*1e3,createdAt:i.created_at*1e3,job:d}}async size(e="default"){return(await(await this.getConnection()).raw(`SELECT COUNT(*) as count FROM ${this.table} WHERE queue = ? AND reserved_at IS NULL`,[e]))?.[0]?.count??0}async clear(e){let t=await this.getConnection();e?await t.raw(`DELETE FROM ${this.table} WHERE queue = ?`,[e]):await t.raw(`DELETE FROM ${this.table}`,[])}async delete(e){await(await this.getConnection()).raw(`DELETE FROM ${this.table} WHERE id = ?`,[e])}async release(e,t=0){let r=await this.getConnection(),n=Math.floor(Date.now()/1e3)+t;await r.raw(`UPDATE ${this.table} SET reserved_at = NULL, available_at = ? WHERE id = ?`,[n,e])}},A=class{queues=new Map;config;registry;_bullmq=null;constructor(e,t){this.config=e,this.registry=t}async getBullMQ(){if(this._bullmq)return this._bullmq;try{return this._bullmq=await Function('return import("bullmq")')(),this._bullmq}catch{throw new Error("bullmq is required for the Redis queue driver. Install it with: npm install bullmq")}}getRedisConnection(){if(this.config.url){let e=new URL(this.config.url);return{host:e.hostname||"localhost",port:parseInt(e.port)||6379,password:e.password||this.config.password||void 0,db:parseInt(e.pathname?.slice(1)||"0")||this.config.db||0}}return{host:this.config.host??"localhost",port:this.config.port??6379,password:this.config.password,db:this.config.db??0}}async getQueue(e){if(this.queues.has(e))return this.queues.get(e);let t=await this.getBullMQ(),r=this.getRedisConnection(),n=this.config.prefix??"svelar",i=new t.Queue(e,{connection:r,prefix:n,defaultJobOptions:{removeOnComplete:this.config.defaultJobOptions?.removeOnComplete??100,removeOnFail:this.config.defaultJobOptions?.removeOnFail??500}});return this.queues.set(e,i),i}async push(e){let t=await this.getQueue(e.queue),r=Math.max(0,e.availableAt-Date.now());await t.add(e.jobClass,{jobClass:e.jobClass,payload:e.payload},{jobId:e.id,delay:r>0?r:void 0,attempts:e.maxAttempts,backoff:{type:"fixed",delay:(e.job.retryDelay??60)*1e3}})}async pop(e){return null}async size(e="default"){let r=await(await this.getQueue(e)).getJobCounts("waiting","delayed","active");return r.waiting+r.delayed+r.active}async clear(e){if(e)await(await this.getQueue(e)).obliterate({force:!0});else for(let t of this.queues.values())await t.obliterate({force:!0})}async createWorker(e,t,r,n){let i=await this.getBullMQ(),s=this.getRedisConnection(),d=this.config.prefix??"svelar",o=new i.Worker(e,async c=>{let l=c.data,u=t.resolve(l.jobClass,l.payload);u.attempts=c.attemptsMade+1,await u.handle()},{connection:s,prefix:d,concurrency:n?.concurrency??1});return o.on("failed",async(c,l)=>{let u=c?.data;if(u)try{let h=t.resolve(u.jobClass,u.payload);c.attemptsMade>=(c.opts?.attempts??3)&&(h.failed(l),await r.store({id:c.id,jobClass:u.jobClass,payload:u.payload,queue:e,attempts:c.attemptsMade,maxAttempts:c.opts?.attempts??3,availableAt:Date.now(),createdAt:c.timestamp??Date.now(),job:h},l))}catch{console.error("[Queue] Failed to resolve job for failure handler:",l.message)}}),o}},Q=class{table="svelar_failed_jobs";async getConnection(){let{Connection:e}=await Promise.resolve().then(()=>(J(),j));return e}async store(e,t){try{await(await this.getConnection()).raw(`INSERT INTO ${this.table} (id, queue, job_class, payload, exception, failed_at)
|
|
5
|
+
VALUES (?, ?, ?, ?, ?, ?)`,[crypto.randomUUID(),e.queue,e.jobClass,e.payload,t.stack??t.message,Math.floor(Date.now()/1e3)])}catch{console.error("[Queue] Could not persist failed job (run migration to create svelar_failed_jobs table)")}}async all(){return(await(await this.getConnection()).raw(`SELECT * FROM ${this.table} ORDER BY failed_at DESC`,[])??[]).map(r=>({id:r.id,queue:r.queue,jobClass:r.job_class,payload:r.payload,exception:r.exception,failedAt:r.failed_at}))}async find(e){let r=await(await this.getConnection()).raw(`SELECT * FROM ${this.table} WHERE id = ? LIMIT 1`,[e]);if(!r||r.length===0)return null;let n=r[0];return{id:n.id,queue:n.queue,jobClass:n.job_class,payload:n.payload,exception:n.exception,failedAt:n.failed_at}}async forget(e){return await(await this.getConnection()).raw(`DELETE FROM ${this.table} WHERE id = ?`,[e]),!0}async flush(){let e=await this.getConnection(),r=(await e.raw(`SELECT COUNT(*) as count FROM ${this.table}`,[]))?.[0]?.count??0;return await e.raw(`DELETE FROM ${this.table}`,[]),r}},U=class{jobs=new Map;register(e){this.jobs.set(e.name,e)}registerAll(e){for(let t of e)this.register(t)}resolve(e,t){let r=this.jobs.get(e);if(!r)throw new Error(`Job class "${e}" is not registered. Call Queue.register(${e}) in your app bootstrap. Registered jobs: [${[...this.jobs.keys()].join(", ")}]`);let n=Object.create(r.prototype);n.attempts=0,n.maxAttempts=3,n.retryDelay=60,n.queue="default";try{let i=JSON.parse(t);n.restore(i)}catch{}return n}has(e){return this.jobs.has(e)}},W=class{config={default:"sync",connections:{sync:{driver:"sync"}}};drivers=new Map;processing=!1;jobRegistry=new U;failedStore=new Q;_activeWorker=null;configure(e){this.config=e,this.drivers.clear()}register(e){this.jobRegistry.register(e)}registerAll(e){this.jobRegistry.registerAll(e)}async dispatch(e,t){let r=this.config.default,n=this.config.connections[r],i=this.resolveDriver(r);t?.queue&&(e.queue=t.queue),t?.maxAttempts!==void 0&&(e.maxAttempts=t.maxAttempts);let s={id:crypto.randomUUID(),jobClass:e.constructor.name,payload:e.serialize(),queue:e.queue??n?.queue??"default",attempts:0,maxAttempts:e.maxAttempts,availableAt:Date.now()+(t?.delay??0)*1e3,createdAt:Date.now(),job:e};await i.push(s)}async dispatchSync(e){let t=new z,r={id:crypto.randomUUID(),jobClass:e.constructor.name,payload:e.serialize(),queue:e.queue,attempts:0,maxAttempts:e.maxAttempts,availableAt:Date.now(),createdAt:Date.now(),job:e};await t.push(r)}async chain(e,t){if(e.length===0)return;let r=new G(e);t?.queue&&(r.queue=t.queue),t?.maxAttempts!==void 0&&(r.maxAttempts=t.maxAttempts),await this.dispatch(r,t)}async work(e){let t=this.config.default,r=this.resolveDriver(t),n=e?.queue??"default";if(r instanceof A){let o=await r.createWorker(n,this.jobRegistry,this.failedStore,{concurrency:e?.concurrency??1});return this.processing=!0,this._activeWorker=o,await new Promise(c=>{let l=()=>{this.processing?setTimeout(l,500):o.close().then(c).catch(c)};l()}),0}let i=e?.maxJobs??1/0,s=(e?.sleep??1)*1e3,d=0;for(this.processing=!0;this.processing&&d<i;){let o=await r.pop(n);if(!o){if(i===1/0){await new Promise(c=>setTimeout(c,s));continue}break}o.attempts++,o.job.attempts=o.attempts;try{await o.job.handle(),d++,r instanceof C&&await r.delete(o.id)}catch(c){if(o.attempts<o.maxAttempts){o.job.retrying(o.attempts);let l=o.job.retryDelay??60;r instanceof C?await r.release(o.id,l):(o.availableAt=Date.now()+l*1e3,await r.push(o))}else o.job.failed(c),await this.failedStore.store(o,c),r instanceof C&&await r.delete(o.id)}}return d}async stop(){this.processing=!1,this._activeWorker&&(await this._activeWorker.close(),this._activeWorker=null)}async size(e){return this.resolveDriver(this.config.default).size(e)}async clear(e){return this.resolveDriver(this.config.default).clear(e)}async failed(){return this.failedStore.all()}async retry(e){let t=await this.failedStore.find(e);if(!t)return!1;let r=this.jobRegistry.resolve(t.jobClass,t.payload);return r.queue=t.queue,await this.dispatch(r,{queue:t.queue}),await this.failedStore.forget(e),!0}async retryAll(){let e=await this.failedStore.all(),t=0;for(let r of e)try{let n=this.jobRegistry.resolve(r.jobClass,r.payload);n.queue=r.queue,await this.dispatch(n,{queue:r.queue}),await this.failedStore.forget(r.id),t++}catch{}return t}async forgetFailed(e){return this.failedStore.forget(e)}async flushFailed(){return this.failedStore.flush()}resolveDriver(e){if(this.drivers.has(e))return this.drivers.get(e);let t=this.config.connections[e];if(!t)throw new Error(`Queue connection "${e}" is not defined.`);let r;switch(t.driver){case"sync":r=new z;break;case"memory":r=new I;break;case"database":r=new C(t.table??"svelar_jobs",this.jobRegistry);break;case"redis":r=new A(t,this.jobRegistry);break;default:throw new Error(`Unknown queue driver: ${t.driver}`)}return this.drivers.set(e,r),r}},G=class extends ${remainingJobs;constructor(e){super(),this.remainingJobs=[...e],this.maxAttempts=1}async handle(){for(let e of this.remainingJobs){let t=null,r=!1;for(let n=1;n<=e.maxAttempts;n++){e.attempts=n;try{await e.handle(),r=!0;break}catch(i){t=i,n<e.maxAttempts&&(e.retrying(n),e.retryDelay>0&&await new Promise(s=>setTimeout(s,e.retryDelay*1e3)))}}if(!r&&t)throw e.failed(t),new Error(`Chain stopped: ${e.constructor.name} failed after ${e.maxAttempts} attempt(s). Remaining jobs: [${this.remainingJobs.slice(this.remainingJobs.indexOf(e)+1).map(n=>n.constructor.name).join(", ")}]`)}}serialize(){return JSON.stringify({jobs:this.remainingJobs.map(e=>({jobClass:e.constructor.name,payload:e.serialize()}))})}},be=v("svelar.queue",()=>new W)});var de={};S(de,{GeneratePdfJob:()=>D,PDF:()=>ye});import{readFileSync as ae}from"fs";import{basename as oe}from"path";function g(){return x.driver||"pdfkit"}function _(){return x.gotenberg||{}}function R(){return x.pdfkit||{}}function P(a){if(!a)return;let e=a.match(/^([\d.]+)\s*(in|mm|cm|pt|px)?$/);if(!e)return;let t=parseFloat(e[1]);switch(e[2]||"pt"){case"in":return t*72;case"mm":return t*(72/25.4);case"cm":return t*(72/2.54);case"pt":return t;case"px":return t*.75;default:return t}}async function ce(a,e,t){let r=t.font||"Helvetica",n=t.fontSize||12;a.font(r).fontSize(n);let i=e,s=e.match(/<body[^>]*>([\s\S]*?)<\/body>/i);s&&(i=s[1]),i=i.replace(/<style[^>]*>[\s\S]*?<\/style>/gi,""),i=i.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,""),i=i.replace(/<head[^>]*>[\s\S]*?<\/head>/gi,"");let d=i.split(/\n/);for(let o of d){let c=o.trim();if(!c)continue;let l=c.match(/<h1[^>]*>(.*?)<\/h1>/i);if(l){a.fontSize(28).font(`${r}-Bold`).text(m(l[1]),{paragraphGap:8}),a.font(r).fontSize(n);continue}let u=c.match(/<h2[^>]*>(.*?)<\/h2>/i);if(u){a.fontSize(22).font(`${r}-Bold`).text(m(u[1]),{paragraphGap:6}),a.font(r).fontSize(n);continue}let h=c.match(/<h3[^>]*>(.*?)<\/h3>/i);if(h){a.fontSize(18).font(`${r}-Bold`).text(m(h[1]),{paragraphGap:4}),a.font(r).fontSize(n);continue}let k=c.match(/<h4[^>]*>(.*?)<\/h4>/i);if(k){a.fontSize(15).font(`${r}-Bold`).text(m(k[1]),{paragraphGap:3}),a.font(r).fontSize(n);continue}if(/<hr\s*\/?>/i.test(c)){a.moveDown(.5);let ie=a.y;a.moveTo(a.page.margins.left,ie).lineTo(a.page.width-a.page.margins.right,ie).stroke("#cccccc"),a.moveDown(.5);continue}if(/<br\s*\/?>/i.test(c)){a.moveDown(.5);continue}let w=c.match(/<li[^>]*>(.*?)<\/li>/i);if(w){a.text(` \u2022 ${m(w[1])}`,{paragraphGap:2});continue}let E=c.match(/<p[^>]*>(.*?)<\/p>/i);if(E){a.text(m(E[1]),{paragraphGap:4});continue}let re=m(c);re&&a.text(re,{paragraphGap:2})}}function m(a){return a.replace(/<[^>]+>/g,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").trim()}async function T(a,e={}){let t;try{t=(await import("pdfkit")).default}catch{throw new Error(`PDFKit is not installed. Install it with: npm install pdfkit
|
|
6
|
+
Or switch to the Gotenberg driver: PDF.configure({ driver: 'gotenberg' })`)}let r=R(),n={bufferPages:!0};e.landscape&&(n.layout="landscape"),e.pageSize?.width&&e.pageSize?.height?n.size=[P(e.pageSize.width)||595.28,P(e.pageSize.height)||841.89]:n.size=r.pageSize||"A4";let i=P(e.margins?.top)??r.margins?.top??72,s=P(e.margins?.bottom)??r.margins?.bottom??72,d=P(e.margins?.left)??r.margins?.left??72,o=P(e.margins?.right)??r.margins?.right??72;n.margins={top:i,bottom:s,left:d,right:o};let c=new t(n),l=[];if(c.on("data",u=>l.push(u)),await a(c),r.pageNumbers){let u=c.bufferedPageRange().count;for(let h=0;h<u;h++)c.switchToPage(h),c.fontSize(9).font("Helvetica").text(`Page ${h+1} of ${u}`,0,c.page.height-n.margins.bottom+20,{align:"center",width:c.page.width})}return new Promise((u,h)=>{c.on("end",()=>u(Buffer.concat(l))),c.on("error",h),c.end()})}function le(){return _().url??process.env.GOTENBERG_URL??"http://localhost:3000"}async function p(a,e,t){let r=`${le()}${a}`,n=e.build(),i=_(),s=i.timeout??6e4,d=t&&Object.keys(t).length>0,o=new AbortController,c=setTimeout(()=>o.abort(),s);try{let l=await fetch(r,{method:"POST",headers:{"Content-Type":e.contentType,...i.headers??{},...t??{}},body:new Uint8Array(n),signal:o.signal});if(d){if(l.status!==204&&!l.ok){let h=await l.text().catch(()=>"");throw new Error(`Gotenberg webhook error ${l.status}: ${h||l.statusText}`)}return Buffer.alloc(0)}if(!l.ok){let h=await l.text().catch(()=>"");throw new Error(`Gotenberg error ${l.status}: ${h||l.statusText}`)}let u=await l.arrayBuffer();return Buffer.from(u)}finally{clearTimeout(c)}}async function we(){if(g()==="pdfkit")try{return await import("pdfkit"),{status:"up",driver:"pdfkit",details:{installed:!0}}}catch{return{status:"down",driver:"pdfkit",details:{installed:!1,fix:"npm install pdfkit"}}}let e=`${le()}/health`;try{let t=await fetch(e),r=await t.json();return{status:t.ok?"up":"down",driver:"gotenberg",details:r}}catch(t){return{status:"unreachable",driver:"gotenberg",details:t.message}}}var x,f,b,q,L,N,K,Y,B,V,ye,ue=y(()=>{"use strict";X();x={driver:"pdfkit"};f=class{boundary=`----SvelarBoundary${Date.now()}${Math.random().toString(36).slice(2)}`;parts=[];get contentType(){return`multipart/form-data; boundary=${this.boundary}`}addField(e,t){let r=`--${this.boundary}\r
|
|
7
|
+
Content-Disposition: form-data; name="${e}"\r
|
|
8
|
+
\r
|
|
9
|
+
`;return this.parts.push(Buffer.from(r+t+`\r
|
|
10
|
+
`)),this}addFile(e,t,r,n="application/octet-stream"){let i=typeof r=="string"?Buffer.from(r):r,s=`--${this.boundary}\r
|
|
11
|
+
Content-Disposition: form-data; name="${e}"; filename="${t}"\r
|
|
12
|
+
Content-Type: ${n}\r
|
|
13
|
+
\r
|
|
14
|
+
`;return this.parts.push(Buffer.concat([Buffer.from(s),i,Buffer.from(`\r
|
|
15
|
+
`)])),this}build(){return this.parts.push(Buffer.from(`--${this.boundary}--\r
|
|
16
|
+
`)),Buffer.concat(this.parts)}};b=class{_margins={};_pageSize={};_landscape=!1;_scale;_headerHtml;_footerHtml;_printBackground=!0;_preferCssPageSize=!1;_waitDelay;_waitExpression;_extraHeaders={};_pdfFormat;_metadata={};_webhook;_downloadFrom=[];margins(e){return this._margins=e,this}pageSize(e){return this._pageSize=e,this}landscape(e=!0){return this._landscape=e,this}scale(e){return this._scale=e,this}header(e){return this._headerHtml=e,this}footer(e){return this._footerHtml=e,this}printBackground(e=!0){return this._printBackground=e,this}preferCssPageSize(e=!0){return this._preferCssPageSize=e,this}waitDelay(e){return this._waitDelay=e,this}waitForExpression(e){return this._waitExpression=e,this}pdfFormat(e){return this._pdfFormat=e,this}meta(e,t){return this._metadata[e]=t,this}webhook(e){return this._webhook=e,this}downloadFrom(e){return this._downloadFrom=e,this}async generateAsync(){if(g()!=="gotenberg")throw new Error("generateAsync() is only available with the Gotenberg driver.");let e=_();if(!this._webhook&&!e.webhookUrl)throw new Error("Webhook not configured. Call .webhook({ url, errorUrl }) or set webhookUrl in PDF.configure().");await this.generate()}applyChromiumFields(e){this._margins.top&&e.addField("marginTop",this._margins.top),this._margins.bottom&&e.addField("marginBottom",this._margins.bottom),this._margins.left&&e.addField("marginLeft",this._margins.left),this._margins.right&&e.addField("marginRight",this._margins.right),this._pageSize.width&&e.addField("paperWidth",this._pageSize.width),this._pageSize.height&&e.addField("paperHeight",this._pageSize.height),this._landscape&&e.addField("landscape","true"),this._scale!==void 0&&e.addField("scale",String(this._scale)),this._printBackground&&e.addField("printBackground","true"),this._preferCssPageSize&&e.addField("preferCssPageSize","true"),this._waitDelay&&e.addField("waitDelay",this._waitDelay),this._waitExpression&&e.addField("waitForExpression",this._waitExpression),this._pdfFormat&&e.addField("pdfa",this._pdfFormat);for(let[t,r]of Object.entries(this._metadata))e.addField(`metadata[${t}]`,r);this._downloadFrom.length>0&&e.addField("downloadFrom",JSON.stringify(this._downloadFrom))}getWebhookHeaders(){let e=_(),t=this._webhook??(e.webhookUrl?{url:e.webhookUrl,errorUrl:e.webhookErrorUrl??e.webhookUrl}:void 0);if(!t)return{};let r={"Gotenberg-Webhook-Url":t.url,"Gotenberg-Webhook-Error-Url":t.errorUrl};return t.method&&(r["Gotenberg-Webhook-Method"]=t.method),t.errorMethod&&(r["Gotenberg-Webhook-Error-Method"]=t.errorMethod),t.extraHeaders&&(r["Gotenberg-Webhook-Extra-Http-Headers"]=JSON.stringify(t.extraHeaders)),r}get isAsync(){let e=_();return!!(this._webhook||e.webhookUrl)}async store(e){let{writeFileSync:t,mkdirSync:r}=await import("fs"),{dirname:n}=await import("path"),i=await this.generate();return r(n(e),{recursive:!0}),t(e,i),i}},q=class extends b{constructor(t){super();this.htmlContent=t}async generate(){if(g()==="pdfkit")return T(async r=>{await ce(r,this.htmlContent,R())},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape,headerHtml:this._headerHtml,footerHtml:this._footerHtml});let t=new f;return t.addFile("files","index.html",this.htmlContent,"text/html"),this._headerHtml&&t.addFile("files","header.html",this._headerHtml,"text/html"),this._footerHtml&&t.addFile("files","footer.html",this._footerHtml,"text/html"),this.applyChromiumFields(t),p("/forms/chromium/convert/html",t,this.getWebhookHeaders())}},L=class extends b{constructor(t){super();this.targetUrl=t}async generate(){if(g()==="pdfkit"){let r=await fetch(this.targetUrl,{headers:this._extraHeaders});if(!r.ok)throw new Error(`Failed to fetch ${this.targetUrl}: ${r.status}`);let n=await r.text();return T(async i=>{await ce(i,n,R())},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape})}let t=new f;t.addField("url",this.targetUrl),this._headerHtml&&t.addFile("files","header.html",this._headerHtml,"text/html"),this._footerHtml&&t.addFile("files","footer.html",this._footerHtml,"text/html");for(let[r,n]of Object.entries(this._extraHeaders))t.addField(`extraHttpHeaders[${r}]`,n);return this.applyChromiumFields(t),p("/forms/chromium/convert/url",t,this.getWebhookHeaders())}httpHeaders(t){return this._extraHeaders={...this._extraHeaders,...t},this}},N=class extends b{constructor(t,r){super();this.markdownContent=t;this.wrapperHtml=r??`<!DOCTYPE html>
|
|
17
|
+
<html><head><meta charset="utf-8"></head>
|
|
18
|
+
<body>{{ toHTML "file.md" }}</body></html>`}wrapperHtml;async generate(){if(g()==="pdfkit")return T(async r=>{let n=R(),i=n.font||"Helvetica",s=n.fontSize||12;r.font(i).fontSize(s);let d=this.markdownContent.split(`
|
|
19
|
+
`);for(let o of d)if(o.startsWith("### "))r.fontSize(16).font(`${i}-Bold`).text(o.slice(4),{paragraphGap:3}),r.font(i).fontSize(s);else if(o.startsWith("## "))r.fontSize(20).font(`${i}-Bold`).text(o.slice(3),{paragraphGap:5}),r.font(i).fontSize(s);else if(o.startsWith("# "))r.fontSize(26).font(`${i}-Bold`).text(o.slice(2),{paragraphGap:7}),r.font(i).fontSize(s);else if(o.startsWith("- ")||o.startsWith("* "))r.text(` \u2022 ${o.slice(2)}`,{paragraphGap:2});else if(o.startsWith("---")||o.startsWith("***")){r.moveDown(.5);let c=r.y;r.moveTo(r.page.margins.left,c).lineTo(r.page.width-r.page.margins.right,c).stroke("#cccccc"),r.moveDown(.5)}else if(o.trim()==="")r.moveDown(.5);else{let c=o.replace(/\*\*(.+?)\*\*/g,"$1").replace(/\*(.+?)\*/g,"$1");r.text(c,{paragraphGap:2})}},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape});let t=new f;return t.addFile("files","index.html",this.wrapperHtml,"text/html"),t.addFile("files","file.md",this.markdownContent,"text/markdown"),this._headerHtml&&t.addFile("files","header.html",this._headerHtml,"text/html"),this._footerHtml&&t.addFile("files","footer.html",this._footerHtml,"text/html"),this.applyChromiumFields(t),p("/forms/chromium/convert/markdown",t,this.getWebhookHeaders())}},K=class extends b{filePaths=[];fileBuffers=[];constructor(e,t){super(),typeof e=="string"?this.filePaths.push(e):Buffer.isBuffer(e)&&t&&this.fileBuffers.push({name:t,buffer:e})}addFile(e,t){return typeof e=="string"?this.filePaths.push(e):Buffer.isBuffer(e)&&t&&this.fileBuffers.push({name:t,buffer:e}),this}async generate(){if(g()==="pdfkit")throw new Error(`Office document conversion requires the Gotenberg driver.
|
|
20
|
+
Switch with: PDF.configure({ driver: 'gotenberg', gotenberg: { url: 'http://localhost:3000' } })`);let e=new f;for(let t of this.filePaths){let r=ae(t);e.addFile("files",oe(t),r)}for(let{name:t,buffer:r}of this.fileBuffers)e.addFile("files",t,r);return this._landscape&&e.addField("landscape","true"),this._pdfFormat&&e.addField("pdfa",this._pdfFormat),this._downloadFrom.length>0&&e.addField("downloadFrom",JSON.stringify(this._downloadFrom)),p("/forms/libreoffice/convert",e,this.getWebhookHeaders())}},Y=class extends b{htmlFiles=[];pdfBuffers=[];addHtml(e,t=`page${this.htmlFiles.length+1}.html`){return this.htmlFiles.push({name:t,content:e}),this}addPdf(e,t=`doc${this.pdfBuffers.length+1}.pdf`){return this.pdfBuffers.push({name:t,buffer:e}),this}addPdfFile(e){let t=ae(e);return this.pdfBuffers.push({name:oe(e),buffer:t}),this}async generate(){if(g()==="pdfkit")throw new Error(`PDF merging requires the Gotenberg driver.
|
|
21
|
+
Switch with: PDF.configure({ driver: 'gotenberg', gotenberg: { url: 'http://localhost:3000' } })`);if(this.htmlFiles.length===0&&this.pdfBuffers.length>0){let n=new f;for(let{name:i,buffer:s}of this.pdfBuffers)n.addFile("files",i,s,"application/pdf");return p("/forms/pdfengines/merge",n,this.getWebhookHeaders())}if(this.htmlFiles.length>0&&this.pdfBuffers.length===0){let n=new f;for(let{name:i,content:s}of this.htmlFiles)n.addFile("files",i,s,"text/html");return this.applyChromiumFields(n),p("/forms/chromium/convert/html",n,this.getWebhookHeaders())}let e=[];for(let{content:n}of this.htmlFiles){let i=await new q(n).generate();e.push(i)}let t=new f,r=0;for(let n of e)t.addFile("files",`converted_${r++}.pdf`,n,"application/pdf");for(let{name:n,buffer:i}of this.pdfBuffers)t.addFile("files",n,i,"application/pdf");return p("/forms/pdfengines/merge",t,this.getWebhookHeaders())}},B=class{constructor(e,t){this.mode=e;this.content=t}_format="png";_quality=100;_width=1920;_height=1080;_clipSelector;format(e){return this._format=e,this}quality(e){return this._quality=e,this}viewport(e,t){return this._width=e,this._height=t,this}clip(e){return this._clipSelector=e,this}async generate(){if(g()==="pdfkit")throw new Error(`Screenshots require the Gotenberg driver.
|
|
22
|
+
Switch with: PDF.configure({ driver: 'gotenberg', gotenberg: { url: 'http://localhost:3000' } })`);let e=new f;this.mode==="html"?e.addFile("files","index.html",this.content,"text/html"):e.addField("url",this.content),e.addField("format",this._format),e.addField("quality",String(this._quality)),e.addField("width",String(this._width)),e.addField("height",String(this._height)),this._clipSelector&&e.addField("clipSelector",this._clipSelector);let t=this.mode==="html"?"/forms/chromium/screenshot/html":"/forms/chromium/screenshot/url";return p(t,e)}},V=class{_margins={};_pageSize={};_landscape=!1;margins(e){return this._margins=e,this}pageSize(e){return this._pageSize=e,this}landscape(e=!0){return this._landscape=e,this}async build(e){return T(async t=>{await e(t)},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape})}async store(e,t){let{writeFileSync:r,mkdirSync:n}=await import("fs"),{dirname:i}=await import("path"),s=await this.build(t);return n(i(e),{recursive:!0}),r(e,s),s}};ye={configure(a){x={...x,...a}},get driver(){return g()},html(a){return new q(a)},url(a){return new L(a)},markdown(a,e){return new N(a,e)},office(a,e){return new K(a,e)},merge(){return new Y},create(){return new V},screenshotHtml(a){return new B("html",a)},screenshotUrl(a){return new B("url",a)},health:we,async dispatch(a){let{GeneratePdfJob:e}=await Promise.resolve().then(()=>(X(),he)),{Queue:t}=await Promise.resolve().then(()=>(se(),ne));await t.dispatch(new e(a))}}});var fe={};S(fe,{Broadcast:()=>ve,channelType:()=>H});function H(a){return a.startsWith("private-")?"private":a.startsWith("presence-")?"presence":"public"}var Z,M,ee,te,ve,ge=y(()=>{"use strict";F();Z=class{subscribers=[];name;type;constructor(e){this.name=e,this.type=H(e)}stream(e,t){let r=this,n=new ReadableStream({start(i){let s={channel:r.name};r.type==="presence"&&(s.members=r.getMembers());let d=`event: connected
|
|
23
|
+
data: ${JSON.stringify(s)}
|
|
24
|
+
id: ${Date.now()}
|
|
25
|
+
|
|
26
|
+
`;i.enqueue(new TextEncoder().encode(d));let o={controller:i,userId:e,userInfo:t};r.subscribers.push(o),r.type==="presence"&&e!==void 0&&r.sendInternal("member:joined",{id:e,...t},o)},cancel(){let i=r.subscribers.findIndex(d=>d.controller===this._controller),s=r.subscribers.length;r.subscribers=r.subscribers.filter(d=>{try{return d.controller.enqueue(new TextEncoder().encode(`:
|
|
27
|
+
|
|
28
|
+
`)),!0}catch{return!1}}),r.type==="presence"&&e!==void 0&&r.subscribers.length<s&&r.sendInternal("member:left",{id:e,...t})}});return new Response(n,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"}})}send(e,t,r){let n=`event: ${e}
|
|
29
|
+
data: ${JSON.stringify(t)}
|
|
30
|
+
id: ${Date.now()}
|
|
31
|
+
|
|
32
|
+
`,i=new TextEncoder().encode(n);for(let s of this.subscribers)if(!(r!==void 0&&s.userId!==r))try{s.controller.enqueue(i)}catch{}}sendInternal(e,t,r){let n=`event: ${e}
|
|
33
|
+
data: ${JSON.stringify(t)}
|
|
34
|
+
id: ${Date.now()}
|
|
35
|
+
|
|
36
|
+
`,i=new TextEncoder().encode(n);for(let s of this.subscribers)if(s!==r)try{s.controller.enqueue(i)}catch{}}toUser(e){return{send:(t,r)=>this.send(t,r,e)}}subscriberCount(){return this.subscribers.length}getMembers(){return this.type!=="presence"?[]:this.subscribers.filter(e=>e.userId!==void 0).map(e=>({id:e.userId,...e.userInfo??{}}))}hasMember(e){return this.subscribers.some(t=>t.userId===e)}whisper(e,t,r){let n=`event: client-${e}
|
|
37
|
+
data: ${JSON.stringify(t)}
|
|
38
|
+
id: ${Date.now()}
|
|
39
|
+
|
|
40
|
+
`,i=new TextEncoder().encode(n);for(let s of this.subscribers)if(s.userId!==r)try{s.controller.enqueue(i)}catch{}}},M=class{config;constructor(e){this.config=e}async send(e,t,r){let n=Array.isArray(e)?e:[e],i=JSON.stringify({name:t,channels:n,data:JSON.stringify(r)}),s=Math.floor(Date.now()/1e3).toString(),d=await this.md5(i),o=["POST",`/apps/${this.config.appId}/events`,[`auth_key=${this.config.key}`,`auth_timestamp=${s}`,"auth_version=1.0",`body_md5=${d}`].join("&")].join(`
|
|
41
|
+
`),c=await this.hmacSha256(this.config.secret,o),l=this.config.useTLS!==!1?"https":"http",u=this.config.host??`api-${this.config.cluster??"mt1"}.pusher.com`,h=this.config.port??(this.config.useTLS!==!1?443:80),k=`${l}://${u}:${h}/apps/${this.config.appId}/events?auth_key=${this.config.key}&auth_timestamp=${s}&auth_version=1.0&body_md5=${d}&auth_signature=${c}`,w=await fetch(k,{method:"POST",headers:{"Content-Type":"application/json"},body:i});if(!w.ok){let E=await w.text();throw new Error(`Pusher API error (${w.status}): ${E}`)}}async authenticate(e,t,r){let n=`${e}:${t}`,i;r&&(i=JSON.stringify(r),n+=`:${i}`);let s=await this.hmacSha256(this.config.secret,n),d=`${this.config.key}:${s}`;return i?{auth:d,channel_data:i}:{auth:d}}get key(){return this.config.key}clientConfig(){let e={key:this.config.key,cluster:this.config.cluster??"mt1"};return this.config.host&&(e.wsHost=this.config.host,e.wsPort=this.config.port??6001,e.wssPort=this.config.port??6001,e.forceTLS=this.config.useTLS??!1,e.enabledTransports=["ws","wss"],e.disableStats=!0),e}async md5(e){let{createHash:t}=await import("crypto");return t("md5").update(e).digest("hex")}async hmacSha256(e,t){let{createHmac:r}=await import("crypto");return r("sha256",e).update(t).digest("hex")}},ee=class{constructor(e,t,r){this.manager=e;this.eventName=t;this.eventData=r}channels=[];on(...e){return this.channels.push(...e),this}async send(){for(let e of this.channels)await this.manager.sendToChannel(e,this.eventName,this.eventData)}},te=class{config={default:"sse",drivers:{sse:{driver:"sse"}}};sseChannels=new Map;channelAuth=new Map;pusherDriver=null;configure(e){this.config=e;let t=Object.values(e.drivers).find(r=>r.driver==="pusher");t&&t.driver==="pusher"&&(this.pusherDriver=new M(t))}channel(e,t){if(t){this.channelAuth.set(e,t);return}return this.sseChannels.has(e)||this.sseChannels.set(e,new Z(e)),this.sseChannels.get(e)}async authorize(e,t){if(H(e)==="public")return!0;for(let[n,i]of this.channelAuth){let s=this.matchPattern(n,e);if(s!==null)return await i(t,s)}return!1}async authenticatePusher(e,t,r){if(!this.pusherDriver)throw new Error("Pusher driver is not configured. Call Broadcast.configure() first.");let n=H(e);if(n==="public")return!1;let i=await this.authorize(e,r);if(i===!1)return!1;if(n==="presence"){let s=typeof i=="object"?{user_id:i.id??r.id,user_info:i}:{user_id:r.id,user_info:{id:r.id}};return this.pusherDriver.authenticate(t,e,s)}return this.pusherDriver.authenticate(t,e)}event(e,t){return new ee(this,e,t)}to(e,t){return{send:async(r,n)=>{await this.sendToChannel(e,r,n,t)}}}async sendToChannel(e,t,r,n){let i=this.config.drivers[this.config.default];switch(i?.driver){case"pusher":this.pusherDriver||(this.pusherDriver=new M(i)),await this.pusherDriver.send(e,t,r);break;case"log":console.log(`[Broadcast] ${e} \u2192 ${t}:`,JSON.stringify(r));break;default:for(let[,s]of this.sseChannels)s.name===e&&s.send(t,r,n);break}}subscribe(e,t,r){return this.channel(e).stream(t,r)}members(e){let t=this.sseChannels.get(e);return t?t.getMembers():[]}pusher(){if(!this.pusherDriver)throw new Error("Pusher driver is not configured.");return this.pusherDriver}activeChannels(){return[...new Set([...this.sseChannels.values()].map(e=>e.name))]}totalSubscribers(){let e=0;for(let t of this.sseChannels.values())e+=t.subscriberCount();return e}prune(){for(let[e,t]of this.sseChannels)t.subscriberCount()===0&&this.sseChannels.delete(e)}matchPattern(e,t){let r=[],n=e.replace(/[.*+?^${}()|[\]\\]/g,o=>o==="{"||o==="}"?o:`\\${o}`).replace(/\\\{(\w+)\\\}/g,(o,c)=>(r.push(c),"([^.]+)")).replace(/\{(\w+)\}/g,(o,c)=>(r.push(c),"([^.]+)")),i=new RegExp(`^${n}$`),s=t.match(i);if(!s)return null;let d={};for(let o=0;o<r.length;o++)d[r[o]]=s[o+1];return d}},ve=v("svelar.broadcast",()=>new te)});var he={};S(he,{GeneratePdfJob:()=>D});var D,X=y(()=>{D=class{constructor(e){this.payload=e}static jobName="GeneratePdfJob";maxAttempts=3;retryDelay=30;queue="default";async handle(){let{PDF:e}=await Promise.resolve().then(()=>(ue(),de)),{type:t,content:r,outputPath:n,options:i,webhook:s,broadcastEvent:d,broadcastChannel:o,meta:c}=this.payload,l;switch(t){case"html":l=e.html(r);break;case"url":l=e.url(r);break;case"markdown":l=e.markdown(r);break;case"office":l=e.office(r);break;default:throw new Error(`Unknown PDF type: ${t}`)}if(i&&(i.margins&&l.margins(i.margins),i.landscape&&l.landscape(),i.scale&&l.scale(i.scale),i.headerHtml&&l.header(i.headerHtml),i.footerHtml&&l.footer(i.footerHtml),i.printBackground!==void 0&&l.printBackground(i.printBackground),i.waitDelay&&l.waitDelay(i.waitDelay),i.waitForExpression&&l.waitForExpression(i.waitForExpression),i.pdfFormat&&l.pdfFormat(i.pdfFormat),i.pageSize&&l.pageSize(i.pageSize)),s){l.webhook({url:s.url,errorUrl:s.errorUrl,method:s.method,extraHeaders:{...s.extraHeaders??{},...c?{"X-Svelar-Pdf-Meta":JSON.stringify(c)}:{}}}),await l.generateAsync();return}if(n?await l.store(n):await l.generate(),d&&o)try{let{Broadcast:u}=await Promise.resolve().then(()=>(ge(),fe));await u.to(o).send(d,{outputPath:n,meta:c,completedAt:new Date().toISOString()})}catch{}}failed(e){console.error("[GeneratePdfJob] Failed:",e.message,this.payload)}serialize(){return{payload:this.payload}}restore(e){this.payload=e.payload}}});X();export{D as GeneratePdfJob};
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar PDF Module
|
|
3
|
+
*
|
|
4
|
+
* Provides a fluent API for generating PDFs with swappable drivers.
|
|
5
|
+
* Ships with two drivers out of the box:
|
|
6
|
+
*
|
|
7
|
+
* - **pdfkit** (default) — Pure JavaScript, zero external dependencies.
|
|
8
|
+
* Great for invoices, reports, tickets, and programmatic documents.
|
|
9
|
+
* Install: `npm install pdfkit`
|
|
10
|
+
*
|
|
11
|
+
* - **gotenberg** — Docker-based service using Chromium & LibreOffice.
|
|
12
|
+
* Great for pixel-perfect HTML→PDF, URL→PDF, and office document conversion.
|
|
13
|
+
* Requires a running Gotenberg container.
|
|
14
|
+
*
|
|
15
|
+
* Swap drivers at any time — the `PDF` facade API stays the same.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { PDF } from '@beeblock/svelar/pdf';
|
|
20
|
+
*
|
|
21
|
+
* // PDFKit (default — no Docker needed)
|
|
22
|
+
* PDF.configure({ driver: 'pdfkit' });
|
|
23
|
+
* const buffer = await PDF.html('<h1>Hello</h1>').generate();
|
|
24
|
+
*
|
|
25
|
+
* // Gotenberg (Docker service)
|
|
26
|
+
* PDF.configure({ driver: 'gotenberg', gotenberg: { url: 'http://localhost:3000' } });
|
|
27
|
+
* const buffer = await PDF.html('<h1>Hello</h1>').generate();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface PdfMargins {
|
|
31
|
+
top?: string;
|
|
32
|
+
bottom?: string;
|
|
33
|
+
left?: string;
|
|
34
|
+
right?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface PdfPageSize {
|
|
37
|
+
width?: string;
|
|
38
|
+
height?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface GotenbergConfig {
|
|
41
|
+
/** Gotenberg API base URL (default: http://localhost:3000 or GOTENBERG_URL env) */
|
|
42
|
+
url?: string;
|
|
43
|
+
/** Request timeout in ms (default: 60000) */
|
|
44
|
+
timeout?: number;
|
|
45
|
+
/** Custom headers to send with every request */
|
|
46
|
+
headers?: Record<string, string>;
|
|
47
|
+
/** Default webhook URL for async generation */
|
|
48
|
+
webhookUrl?: string;
|
|
49
|
+
/** Default webhook error URL */
|
|
50
|
+
webhookErrorUrl?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface PdfKitConfig {
|
|
53
|
+
/** Default page size (default: 'A4') */
|
|
54
|
+
pageSize?: string;
|
|
55
|
+
/** Default margins in points (72 points = 1 inch) */
|
|
56
|
+
margins?: {
|
|
57
|
+
top?: number;
|
|
58
|
+
bottom?: number;
|
|
59
|
+
left?: number;
|
|
60
|
+
right?: number;
|
|
61
|
+
};
|
|
62
|
+
/** Whether to auto-add page numbers (default: false) */
|
|
63
|
+
pageNumbers?: boolean;
|
|
64
|
+
/** Default font (default: 'Helvetica') */
|
|
65
|
+
font?: string;
|
|
66
|
+
/** Default font size in points (default: 12) */
|
|
67
|
+
fontSize?: number;
|
|
68
|
+
}
|
|
69
|
+
export interface PdfConfig {
|
|
70
|
+
/** Which driver to use: 'pdfkit' (default) or 'gotenberg' */
|
|
71
|
+
driver?: 'pdfkit' | 'gotenberg';
|
|
72
|
+
/** PDFKit-specific options */
|
|
73
|
+
pdfkit?: PdfKitConfig;
|
|
74
|
+
/** Gotenberg-specific options */
|
|
75
|
+
gotenberg?: GotenbergConfig;
|
|
76
|
+
}
|
|
77
|
+
export interface WebhookOptions {
|
|
78
|
+
/** URL where the generated PDF will be POSTed on success */
|
|
79
|
+
url: string;
|
|
80
|
+
/** URL called if the conversion fails */
|
|
81
|
+
errorUrl: string;
|
|
82
|
+
/** HTTP method for the success callback (default: POST) */
|
|
83
|
+
method?: 'POST' | 'PUT' | 'PATCH';
|
|
84
|
+
/** HTTP method for the error callback (default: POST) */
|
|
85
|
+
errorMethod?: 'POST' | 'PUT' | 'PATCH';
|
|
86
|
+
/** Extra HTTP headers sent with the webhook callback */
|
|
87
|
+
extraHeaders?: Record<string, string>;
|
|
88
|
+
}
|
|
89
|
+
export interface DownloadFromEntry {
|
|
90
|
+
/** Remote URL to fetch the file from */
|
|
91
|
+
url: string;
|
|
92
|
+
/** Extra HTTP headers for fetching this specific URL */
|
|
93
|
+
extraHttpHeaders?: Record<string, string>;
|
|
94
|
+
/** Route to a specific form field: "embedded", "watermark", "stamp" */
|
|
95
|
+
field?: 'embedded' | 'watermark' | 'stamp';
|
|
96
|
+
}
|
|
97
|
+
declare class MultipartBuilder {
|
|
98
|
+
private boundary;
|
|
99
|
+
private parts;
|
|
100
|
+
get contentType(): string;
|
|
101
|
+
addField(name: string, value: string): this;
|
|
102
|
+
addFile(fieldName: string, filename: string, content: Buffer | string, contentType?: string): this;
|
|
103
|
+
build(): Buffer;
|
|
104
|
+
}
|
|
105
|
+
declare abstract class PdfBuilder {
|
|
106
|
+
protected _margins: PdfMargins;
|
|
107
|
+
protected _pageSize: PdfPageSize;
|
|
108
|
+
protected _landscape: boolean;
|
|
109
|
+
protected _scale: number | undefined;
|
|
110
|
+
protected _headerHtml: string | undefined;
|
|
111
|
+
protected _footerHtml: string | undefined;
|
|
112
|
+
protected _printBackground: boolean;
|
|
113
|
+
protected _preferCssPageSize: boolean;
|
|
114
|
+
protected _waitDelay: string | undefined;
|
|
115
|
+
protected _waitExpression: string | undefined;
|
|
116
|
+
protected _extraHeaders: Record<string, string>;
|
|
117
|
+
protected _pdfFormat: string | undefined;
|
|
118
|
+
protected _metadata: Record<string, string>;
|
|
119
|
+
protected _webhook: WebhookOptions | undefined;
|
|
120
|
+
protected _downloadFrom: DownloadFromEntry[];
|
|
121
|
+
/** Set page margins (e.g. '1in', '25mm', '2cm') */
|
|
122
|
+
margins(m: PdfMargins): this;
|
|
123
|
+
/** Set custom page dimensions */
|
|
124
|
+
pageSize(size: PdfPageSize): this;
|
|
125
|
+
/** Use landscape orientation */
|
|
126
|
+
landscape(value?: boolean): this;
|
|
127
|
+
/** Scale factor (0.1 to 2.0) */
|
|
128
|
+
scale(value: number): this;
|
|
129
|
+
/** Add a header to every page (HTML string) */
|
|
130
|
+
header(html: string): this;
|
|
131
|
+
/** Add a footer to every page (HTML string) */
|
|
132
|
+
footer(html: string): this;
|
|
133
|
+
/** Print background graphics (default: true) */
|
|
134
|
+
printBackground(value?: boolean): this;
|
|
135
|
+
/** Prefer CSS @page size over paperWidth/paperHeight */
|
|
136
|
+
preferCssPageSize(value?: boolean): this;
|
|
137
|
+
/** Wait for a duration before conversion (e.g. '5s', '1000ms') */
|
|
138
|
+
waitDelay(duration: string): this;
|
|
139
|
+
/** Wait until a JS expression evaluates to true */
|
|
140
|
+
waitForExpression(expression: string): this;
|
|
141
|
+
/** Set PDF/A format (e.g. 'PDF/A-1b', 'PDF/A-2b', 'PDF/A-3b') */
|
|
142
|
+
pdfFormat(format: string): this;
|
|
143
|
+
/** Set PDF metadata */
|
|
144
|
+
meta(key: string, value: string): this;
|
|
145
|
+
/**
|
|
146
|
+
* Enable async webhook mode. Gotenberg will return 204 immediately
|
|
147
|
+
* and POST the resulting PDF to your webhook URL when done.
|
|
148
|
+
* Only available with the Gotenberg driver.
|
|
149
|
+
*/
|
|
150
|
+
webhook(options: WebhookOptions): this;
|
|
151
|
+
/**
|
|
152
|
+
* Add remote files for Gotenberg to fetch (instead of uploading them).
|
|
153
|
+
* Only available with the Gotenberg driver.
|
|
154
|
+
*/
|
|
155
|
+
downloadFrom(entries: DownloadFromEntry[]): this;
|
|
156
|
+
/**
|
|
157
|
+
* Generate the PDF asynchronously via webhook (Gotenberg only).
|
|
158
|
+
*/
|
|
159
|
+
generateAsync(): Promise<void>;
|
|
160
|
+
/** Apply common Chromium form fields to the multipart builder */
|
|
161
|
+
protected applyChromiumFields(form: MultipartBuilder): void;
|
|
162
|
+
/** Build webhook headers for the HTTP request */
|
|
163
|
+
protected getWebhookHeaders(): Record<string, string>;
|
|
164
|
+
/** Whether this builder is configured for async webhook mode */
|
|
165
|
+
protected get isAsync(): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Generate the PDF and save it to a file path.
|
|
168
|
+
* Returns the Buffer for further processing.
|
|
169
|
+
*/
|
|
170
|
+
store(filePath: string): Promise<Buffer>;
|
|
171
|
+
/** Generate the PDF and return a Buffer */
|
|
172
|
+
abstract generate(): Promise<Buffer>;
|
|
173
|
+
}
|
|
174
|
+
declare class HtmlPdfBuilder extends PdfBuilder {
|
|
175
|
+
private htmlContent;
|
|
176
|
+
constructor(htmlContent: string);
|
|
177
|
+
generate(): Promise<Buffer>;
|
|
178
|
+
}
|
|
179
|
+
declare class UrlPdfBuilder extends PdfBuilder {
|
|
180
|
+
private targetUrl;
|
|
181
|
+
constructor(targetUrl: string);
|
|
182
|
+
generate(): Promise<Buffer>;
|
|
183
|
+
/** Add extra HTTP headers for the URL request */
|
|
184
|
+
httpHeaders(headers: Record<string, string>): this;
|
|
185
|
+
}
|
|
186
|
+
declare class MarkdownPdfBuilder extends PdfBuilder {
|
|
187
|
+
private markdownContent;
|
|
188
|
+
private wrapperHtml;
|
|
189
|
+
constructor(markdownContent: string, wrapperHtml?: string);
|
|
190
|
+
generate(): Promise<Buffer>;
|
|
191
|
+
}
|
|
192
|
+
declare class OfficePdfBuilder extends PdfBuilder {
|
|
193
|
+
private filePaths;
|
|
194
|
+
private fileBuffers;
|
|
195
|
+
constructor(filePathOrBuffer?: string | Buffer, filename?: string);
|
|
196
|
+
/** Add another file to convert (for merging multiple office docs) */
|
|
197
|
+
addFile(pathOrBuffer: string | Buffer, filename?: string): this;
|
|
198
|
+
generate(): Promise<Buffer>;
|
|
199
|
+
}
|
|
200
|
+
declare class MergePdfBuilder extends PdfBuilder {
|
|
201
|
+
private htmlFiles;
|
|
202
|
+
private pdfBuffers;
|
|
203
|
+
/** Add an HTML page to the merge */
|
|
204
|
+
addHtml(content: string, filename?: string): this;
|
|
205
|
+
/** Add an existing PDF buffer to merge */
|
|
206
|
+
addPdf(buffer: Buffer, filename?: string): this;
|
|
207
|
+
/** Add an existing PDF file to merge */
|
|
208
|
+
addPdfFile(path: string): this;
|
|
209
|
+
generate(): Promise<Buffer>;
|
|
210
|
+
}
|
|
211
|
+
declare class ScreenshotBuilder {
|
|
212
|
+
private mode;
|
|
213
|
+
private content;
|
|
214
|
+
private _format;
|
|
215
|
+
private _quality;
|
|
216
|
+
private _width;
|
|
217
|
+
private _height;
|
|
218
|
+
private _clipSelector;
|
|
219
|
+
constructor(mode: 'html' | 'url', content: string);
|
|
220
|
+
format(fmt: 'png' | 'jpeg' | 'webp'): this;
|
|
221
|
+
quality(q: number): this;
|
|
222
|
+
viewport(width: number, height: number): this;
|
|
223
|
+
clip(selector: string): this;
|
|
224
|
+
generate(): Promise<Buffer>;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Programmatic PDF builder using PDFKit directly.
|
|
228
|
+
* Use this for full control over the document layout (tables, images, etc.)
|
|
229
|
+
* without going through HTML conversion.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* const buffer = await PDF.create()
|
|
234
|
+
* .margins({ top: '1in', bottom: '1in' })
|
|
235
|
+
* .build(async (doc) => {
|
|
236
|
+
* doc.fontSize(24).text('Invoice #1234', { align: 'center' });
|
|
237
|
+
* doc.moveDown();
|
|
238
|
+
* doc.fontSize(12).text('Total: $99.00');
|
|
239
|
+
* doc.addPage();
|
|
240
|
+
* doc.text('Page 2 content');
|
|
241
|
+
* });
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
declare class PdfKitDocumentBuilder {
|
|
245
|
+
private _margins;
|
|
246
|
+
private _pageSize;
|
|
247
|
+
private _landscape;
|
|
248
|
+
margins(m: PdfMargins): this;
|
|
249
|
+
pageSize(size: PdfPageSize): this;
|
|
250
|
+
landscape(value?: boolean): this;
|
|
251
|
+
/**
|
|
252
|
+
* Build the PDF by providing a callback that receives the raw PDFKit document.
|
|
253
|
+
* Call any PDFKit method on `doc` — text, images, vectors, tables, etc.
|
|
254
|
+
*/
|
|
255
|
+
build(callback: (doc: any) => Promise<void> | void): Promise<Buffer>;
|
|
256
|
+
/** Build and save to file in one call */
|
|
257
|
+
store(filePath: string, callback: (doc: any) => Promise<void> | void): Promise<Buffer>;
|
|
258
|
+
}
|
|
259
|
+
declare function checkHealth(): Promise<{
|
|
260
|
+
status: string;
|
|
261
|
+
driver: string;
|
|
262
|
+
details?: any;
|
|
263
|
+
}>;
|
|
264
|
+
export declare const PDF: {
|
|
265
|
+
/**
|
|
266
|
+
* Configure the PDF module.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```ts
|
|
270
|
+
* // PDFKit (default — no Docker)
|
|
271
|
+
* PDF.configure({ driver: 'pdfkit' });
|
|
272
|
+
*
|
|
273
|
+
* // PDFKit with custom defaults
|
|
274
|
+
* PDF.configure({
|
|
275
|
+
* driver: 'pdfkit',
|
|
276
|
+
* pdfkit: { pageSize: 'Letter', font: 'Helvetica', fontSize: 11, pageNumbers: true },
|
|
277
|
+
* });
|
|
278
|
+
*
|
|
279
|
+
* // Gotenberg (Docker service)
|
|
280
|
+
* PDF.configure({
|
|
281
|
+
* driver: 'gotenberg',
|
|
282
|
+
* gotenberg: { url: 'http://localhost:3000', timeout: 60000 },
|
|
283
|
+
* });
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
configure(config: PdfConfig): void;
|
|
287
|
+
/** Get the current driver name */
|
|
288
|
+
readonly driver: string;
|
|
289
|
+
/** Convert HTML string to PDF */
|
|
290
|
+
html(content: string): HtmlPdfBuilder;
|
|
291
|
+
/** Convert a URL to PDF */
|
|
292
|
+
url(targetUrl: string): UrlPdfBuilder;
|
|
293
|
+
/** Convert Markdown to PDF */
|
|
294
|
+
markdown(content: string, wrapperHtml?: string): MarkdownPdfBuilder;
|
|
295
|
+
/** Convert office documents (docx, xlsx, pptx, odt, etc.) to PDF. Requires Gotenberg driver. */
|
|
296
|
+
office(pathOrBuffer: string | Buffer, filename?: string): OfficePdfBuilder;
|
|
297
|
+
/** Merge multiple PDFs or HTML pages into one PDF. Requires Gotenberg driver. */
|
|
298
|
+
merge(): MergePdfBuilder;
|
|
299
|
+
/**
|
|
300
|
+
* Create a programmatic PDF using the raw PDFKit API.
|
|
301
|
+
* Available regardless of the configured driver.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```ts
|
|
305
|
+
* const buffer = await PDF.create()
|
|
306
|
+
* .margins({ top: '1in', bottom: '1in' })
|
|
307
|
+
* .build(async (doc) => {
|
|
308
|
+
* doc.fontSize(24).text('Invoice #1234', { align: 'center' });
|
|
309
|
+
* doc.moveDown();
|
|
310
|
+
* doc.fontSize(12).text('Total: $99.00');
|
|
311
|
+
* });
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
create(): PdfKitDocumentBuilder;
|
|
315
|
+
/** Take a screenshot of HTML content. Requires Gotenberg driver. */
|
|
316
|
+
screenshotHtml(content: string): ScreenshotBuilder;
|
|
317
|
+
/** Take a screenshot of a URL. Requires Gotenberg driver. */
|
|
318
|
+
screenshotUrl(targetUrl: string): ScreenshotBuilder;
|
|
319
|
+
/** Check if the configured driver is healthy and available */
|
|
320
|
+
health: typeof checkHealth;
|
|
321
|
+
/**
|
|
322
|
+
* Dispatch PDF generation as a background queue job.
|
|
323
|
+
*/
|
|
324
|
+
dispatch(payload: import("./GeneratePdfJob.js").PdfJobPayload): Promise<void>;
|
|
325
|
+
};
|
|
326
|
+
export type { HtmlPdfBuilder, UrlPdfBuilder, MarkdownPdfBuilder, OfficePdfBuilder, MergePdfBuilder, ScreenshotBuilder, PdfKitDocumentBuilder };
|
|
327
|
+
export { GeneratePdfJob } from './GeneratePdfJob.js';
|
|
328
|
+
export type { PdfJobPayload } from './GeneratePdfJob.js';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var pe=Object.defineProperty;var y=(a,e)=>()=>(a&&(e=a(a=0)),e);var S=(a,e)=>{for(var t in e)pe(a,t,{get:e[t],enumerable:!0})};function v(a,e){let t=Symbol.for(a),r=globalThis;return r[t]||(r[t]=e()),r[t]}var F=y(()=>{"use strict"});var ne={};S(ne,{Broadcast:()=>me,channelType:()=>$});function $(a){return a.startsWith("private-")?"private":a.startsWith("presence-")?"presence":"public"}var O,z,j,J,me,se=y(()=>{"use strict";F();O=class{subscribers=[];name;type;constructor(e){this.name=e,this.type=$(e)}stream(e,t){let r=this,n=new ReadableStream({start(i){let s={channel:r.name};r.type==="presence"&&(s.members=r.getMembers());let d=`event: connected
|
|
2
|
+
data: ${JSON.stringify(s)}
|
|
3
|
+
id: ${Date.now()}
|
|
4
|
+
|
|
5
|
+
`;i.enqueue(new TextEncoder().encode(d));let o={controller:i,userId:e,userInfo:t};r.subscribers.push(o),r.type==="presence"&&e!==void 0&&r.sendInternal("member:joined",{id:e,...t},o)},cancel(){let i=r.subscribers.findIndex(d=>d.controller===this._controller),s=r.subscribers.length;r.subscribers=r.subscribers.filter(d=>{try{return d.controller.enqueue(new TextEncoder().encode(`:
|
|
6
|
+
|
|
7
|
+
`)),!0}catch{return!1}}),r.type==="presence"&&e!==void 0&&r.subscribers.length<s&&r.sendInternal("member:left",{id:e,...t})}});return new Response(n,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"}})}send(e,t,r){let n=`event: ${e}
|
|
8
|
+
data: ${JSON.stringify(t)}
|
|
9
|
+
id: ${Date.now()}
|
|
10
|
+
|
|
11
|
+
`,i=new TextEncoder().encode(n);for(let s of this.subscribers)if(!(r!==void 0&&s.userId!==r))try{s.controller.enqueue(i)}catch{}}sendInternal(e,t,r){let n=`event: ${e}
|
|
12
|
+
data: ${JSON.stringify(t)}
|
|
13
|
+
id: ${Date.now()}
|
|
14
|
+
|
|
15
|
+
`,i=new TextEncoder().encode(n);for(let s of this.subscribers)if(s!==r)try{s.controller.enqueue(i)}catch{}}toUser(e){return{send:(t,r)=>this.send(t,r,e)}}subscriberCount(){return this.subscribers.length}getMembers(){return this.type!=="presence"?[]:this.subscribers.filter(e=>e.userId!==void 0).map(e=>({id:e.userId,...e.userInfo??{}}))}hasMember(e){return this.subscribers.some(t=>t.userId===e)}whisper(e,t,r){let n=`event: client-${e}
|
|
16
|
+
data: ${JSON.stringify(t)}
|
|
17
|
+
id: ${Date.now()}
|
|
18
|
+
|
|
19
|
+
`,i=new TextEncoder().encode(n);for(let s of this.subscribers)if(s.userId!==r)try{s.controller.enqueue(i)}catch{}}},z=class{config;constructor(e){this.config=e}async send(e,t,r){let n=Array.isArray(e)?e:[e],i=JSON.stringify({name:t,channels:n,data:JSON.stringify(r)}),s=Math.floor(Date.now()/1e3).toString(),d=await this.md5(i),o=["POST",`/apps/${this.config.appId}/events`,[`auth_key=${this.config.key}`,`auth_timestamp=${s}`,"auth_version=1.0",`body_md5=${d}`].join("&")].join(`
|
|
20
|
+
`),c=await this.hmacSha256(this.config.secret,o),l=this.config.useTLS!==!1?"https":"http",u=this.config.host??`api-${this.config.cluster??"mt1"}.pusher.com`,h=this.config.port??(this.config.useTLS!==!1?443:80),k=`${l}://${u}:${h}/apps/${this.config.appId}/events?auth_key=${this.config.key}&auth_timestamp=${s}&auth_version=1.0&body_md5=${d}&auth_signature=${c}`,w=await fetch(k,{method:"POST",headers:{"Content-Type":"application/json"},body:i});if(!w.ok){let E=await w.text();throw new Error(`Pusher API error (${w.status}): ${E}`)}}async authenticate(e,t,r){let n=`${e}:${t}`,i;r&&(i=JSON.stringify(r),n+=`:${i}`);let s=await this.hmacSha256(this.config.secret,n),d=`${this.config.key}:${s}`;return i?{auth:d,channel_data:i}:{auth:d}}get key(){return this.config.key}clientConfig(){let e={key:this.config.key,cluster:this.config.cluster??"mt1"};return this.config.host&&(e.wsHost=this.config.host,e.wsPort=this.config.port??6001,e.wssPort=this.config.port??6001,e.forceTLS=this.config.useTLS??!1,e.enabledTransports=["ws","wss"],e.disableStats=!0),e}async md5(e){let{createHash:t}=await import("crypto");return t("md5").update(e).digest("hex")}async hmacSha256(e,t){let{createHmac:r}=await import("crypto");return r("sha256",e).update(t).digest("hex")}},j=class{constructor(e,t,r){this.manager=e;this.eventName=t;this.eventData=r}channels=[];on(...e){return this.channels.push(...e),this}async send(){for(let e of this.channels)await this.manager.sendToChannel(e,this.eventName,this.eventData)}},J=class{config={default:"sse",drivers:{sse:{driver:"sse"}}};sseChannels=new Map;channelAuth=new Map;pusherDriver=null;configure(e){this.config=e;let t=Object.values(e.drivers).find(r=>r.driver==="pusher");t&&t.driver==="pusher"&&(this.pusherDriver=new z(t))}channel(e,t){if(t){this.channelAuth.set(e,t);return}return this.sseChannels.has(e)||this.sseChannels.set(e,new O(e)),this.sseChannels.get(e)}async authorize(e,t){if($(e)==="public")return!0;for(let[n,i]of this.channelAuth){let s=this.matchPattern(n,e);if(s!==null)return await i(t,s)}return!1}async authenticatePusher(e,t,r){if(!this.pusherDriver)throw new Error("Pusher driver is not configured. Call Broadcast.configure() first.");let n=$(e);if(n==="public")return!1;let i=await this.authorize(e,r);if(i===!1)return!1;if(n==="presence"){let s=typeof i=="object"?{user_id:i.id??r.id,user_info:i}:{user_id:r.id,user_info:{id:r.id}};return this.pusherDriver.authenticate(t,e,s)}return this.pusherDriver.authenticate(t,e)}event(e,t){return new j(this,e,t)}to(e,t){return{send:async(r,n)=>{await this.sendToChannel(e,r,n,t)}}}async sendToChannel(e,t,r,n){let i=this.config.drivers[this.config.default];switch(i?.driver){case"pusher":this.pusherDriver||(this.pusherDriver=new z(i)),await this.pusherDriver.send(e,t,r);break;case"log":console.log(`[Broadcast] ${e} \u2192 ${t}:`,JSON.stringify(r));break;default:for(let[,s]of this.sseChannels)s.name===e&&s.send(t,r,n);break}}subscribe(e,t,r){return this.channel(e).stream(t,r)}members(e){let t=this.sseChannels.get(e);return t?t.getMembers():[]}pusher(){if(!this.pusherDriver)throw new Error("Pusher driver is not configured.");return this.pusherDriver}activeChannels(){return[...new Set([...this.sseChannels.values()].map(e=>e.name))]}totalSubscribers(){let e=0;for(let t of this.sseChannels.values())e+=t.subscriberCount();return e}prune(){for(let[e,t]of this.sseChannels)t.subscriberCount()===0&&this.sseChannels.delete(e)}matchPattern(e,t){let r=[],n=e.replace(/[.*+?^${}()|[\]\\]/g,o=>o==="{"||o==="}"?o:`\\${o}`).replace(/\\\{(\w+)\\\}/g,(o,c)=>(r.push(c),"([^.]+)")).replace(/\{(\w+)\}/g,(o,c)=>(r.push(c),"([^.]+)")),i=new RegExp(`^${n}$`),s=t.match(i);if(!s)return null;let d={};for(let o=0;o<r.length;o++)d[r[o]]=s[o+1];return d}},me=v("svelar.broadcast",()=>new J)});var ae={};S(ae,{GeneratePdfJob:()=>_});var _,I=y(()=>{"use strict";_=class{constructor(e){this.payload=e}static jobName="GeneratePdfJob";maxAttempts=3;retryDelay=30;queue="default";async handle(){let{PDF:e}=await Promise.resolve().then(()=>(ce(),oe)),{type:t,content:r,outputPath:n,options:i,webhook:s,broadcastEvent:d,broadcastChannel:o,meta:c}=this.payload,l;switch(t){case"html":l=e.html(r);break;case"url":l=e.url(r);break;case"markdown":l=e.markdown(r);break;case"office":l=e.office(r);break;default:throw new Error(`Unknown PDF type: ${t}`)}if(i&&(i.margins&&l.margins(i.margins),i.landscape&&l.landscape(),i.scale&&l.scale(i.scale),i.headerHtml&&l.header(i.headerHtml),i.footerHtml&&l.footer(i.footerHtml),i.printBackground!==void 0&&l.printBackground(i.printBackground),i.waitDelay&&l.waitDelay(i.waitDelay),i.waitForExpression&&l.waitForExpression(i.waitForExpression),i.pdfFormat&&l.pdfFormat(i.pdfFormat),i.pageSize&&l.pageSize(i.pageSize)),s){l.webhook({url:s.url,errorUrl:s.errorUrl,method:s.method,extraHeaders:{...s.extraHeaders??{},...c?{"X-Svelar-Pdf-Meta":JSON.stringify(c)}:{}}}),await l.generateAsync();return}if(n?await l.store(n):await l.generate(),d&&o)try{let{Broadcast:u}=await Promise.resolve().then(()=>(se(),ne));await u.to(o).send(d,{outputPath:n,meta:c,completedAt:new Date().toISOString()})}catch{}}failed(e){console.error("[GeneratePdfJob] Failed:",e.message,this.payload)}serialize(){return{payload:this.payload}}restore(e){this.payload=e.payload}}});var U={};S(U,{Connection:()=>be});var Q,be,W=y(()=>{"use strict";F();Q=class{connections=new Map;config=null;defaultName="default";configure(e){this.config=e,this.defaultName=e.default}async connection(e){let t=e??this.defaultName;if(this.connections.has(t))return this.connections.get(t).drizzle;if(!this.config)throw new Error("Database not configured. Call Connection.configure() first, or register DatabaseServiceProvider.");let r=this.config.connections[t];if(!r)throw new Error(`Database connection "${t}" is not defined in configuration.`);let n=await this.createConnection(r);return this.connections.set(t,n),n.drizzle}async rawClient(e){let t=e??this.defaultName;return await this.connection(t),this.connections.get(t).rawClient}async raw(e,t=[],r){let n=await this.connection(r),i=this.getConfig(r);switch(i.driver){case"sqlite":{let s=await this.rawClient(r),d=t.map(l=>typeof l=="boolean"?l?1:0:l instanceof Date?l.toISOString():l),o=s.prepare(e),c=e.trimStart().toUpperCase();return c.startsWith("SELECT")||c.startsWith("PRAGMA")||c.startsWith("WITH")?o.all(...d):o.run(...d)}case"postgres":return(await this.rawClient(r))(e,...t);case"mysql":{let s=await this.rawClient(r),[d]=await s.execute(e,t);return d}default:throw new Error(`Unsupported driver: ${i.driver}`)}}getDriver(e){return this.getConfig(e).driver}getConfig(e){let t=e??this.defaultName;if(!this.config)throw new Error("Database not configured.");let r=this.config.connections[t];if(!r)throw new Error(`Database connection "${t}" is not defined.`);return r}async disconnect(e){if(e){let t=this.connections.get(e);t&&(await this.closeConnection(t),this.connections.delete(e))}else{for(let[t,r]of this.connections)await this.closeConnection(r);this.connections.clear()}}isConnected(e){return this.connections.has(e??this.defaultName)}async transaction(e,t){let r=this.getConfig(t),n=await this.rawClient(t);switch(r.driver){case"sqlite":{n.exec("BEGIN");try{let i=await e();return n.exec("COMMIT"),i}catch(i){throw n.exec("ROLLBACK"),i}}case"postgres":{await n`BEGIN`;try{let i=await e();return await n`COMMIT`,i}catch(i){throw await n`ROLLBACK`,i}}case"mysql":{let i=await n.getConnection();await i.beginTransaction();try{let s=await e();return await i.commit(),i.release(),s}catch(s){throw await i.rollback(),i.release(),s}}default:throw new Error(`Unsupported driver: ${r.driver}`)}}async createConnection(e){switch(e.driver){case"sqlite":return this.createSQLiteConnection(e);case"postgres":return this.createPostgresConnection(e);case"mysql":return this.createMySQLConnection(e);default:throw new Error(`Unsupported database driver: ${e.driver}`)}}async createSQLiteConnection(e){let t=e.filename??e.database??":memory:";try{let r=(await import("better-sqlite3")).default,{drizzle:n}=await import("drizzle-orm/better-sqlite3"),i=new r(t);return i.pragma("journal_mode = WAL"),i.pragma("foreign_keys = ON"),{drizzle:n(i),config:e,rawClient:i}}catch(r){let n;try{n=(await new Function("mod","return import(mod)")("node:sqlite")).DatabaseSync}catch{throw new Error(`No SQLite driver available. Install better-sqlite3 (npm install better-sqlite3) or use Node.js v22+ which includes built-in SQLite support. Original error: ${r instanceof Error?r.message:String(r)}`)}let i=new n(t);i.exec("PRAGMA journal_mode = WAL"),i.exec("PRAGMA foreign_keys = ON");let s={prepare(o){let c=i.prepare(o);return{all(...l){return c.all(...l)},run(...l){return c.run(...l)},get(...l){return c.get(...l)}}},exec(o){i.exec(o)},pragma(o){return i.prepare(`PRAGMA ${o}`).all()},close(){i.close()}},d;try{let{drizzle:o}=await import("drizzle-orm/better-sqlite3");d=o(s)}catch{d=s}return{drizzle:d,config:e,rawClient:s}}}async createPostgresConnection(e){let t=(await import("postgres")).default,{drizzle:r}=await import("drizzle-orm/postgres-js"),n=e.url??`postgres://${e.user}:${e.password}@${e.host??"localhost"}:${e.port??5432}/${e.database}`,i=t(n);return{drizzle:r(i),config:e,rawClient:i}}async createMySQLConnection(e){let t=await import("mysql2/promise"),{drizzle:r}=await import("drizzle-orm/mysql2"),n=t.createPool({host:e.host??"localhost",port:e.port??3306,database:e.database,user:e.user,password:e.password,uri:e.url});return{drizzle:r(n),config:e,rawClient:n}}async closeConnection(e){try{switch(e.config.driver){case"sqlite":e.rawClient.close();break;case"postgres":await e.rawClient.end();break;case"mysql":await e.rawClient.end();break}}catch{}}},be=v("svelar.connection",()=>new Q)});var le={};S(le,{Job:()=>A,Queue:()=>we});var A,q,G,C,B,L,N,K,Y,we,de=y(()=>{"use strict";F();A=class{attempts=0;maxAttempts=3;retryDelay=60;queue="default";failed(e){console.error(`[Queue] Job ${this.constructor.name} permanently failed:`,e.message)}retrying(e){}serialize(){let e={};for(let[t,r]of Object.entries(this))typeof r!="function"&&(e[t]=r);return JSON.stringify(e)}restore(e){for(let[t,r]of Object.entries(e))t!=="attempts"&&t!=="maxAttempts"&&t!=="retryDelay"&&t!=="queue"&&(this[t]=r)}},q=class{async push(e){try{e.job.attempts=1,await e.job.handle()}catch(t){if(e.attempts+1<e.maxAttempts)return e.attempts++,e.job.attempts=e.attempts+1,e.job.retrying(e.job.attempts),this.push(e);e.job.failed(t)}}async pop(){return null}async size(){return 0}async clear(){}},G=class{queues=new Map;async push(e){let t=e.queue;this.queues.has(t)||this.queues.set(t,[]),this.queues.get(t).push(e)}async pop(e="default"){let t=this.queues.get(e)??[],r=Date.now(),n=t.findIndex(i=>i.availableAt<=r);return n===-1?null:t.splice(n,1)[0]}async size(e="default"){return this.queues.get(e)?.length??0}async clear(e){e?this.queues.delete(e):this.queues.clear()}},C=class{constructor(e,t){this.table=e;this.registry=t}async getConnection(){let{Connection:e}=await Promise.resolve().then(()=>(W(),U));return e}async push(e){await(await this.getConnection()).raw(`INSERT INTO ${this.table} (id, queue, payload, attempts, max_attempts, available_at, created_at)
|
|
21
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,[e.id,e.queue,JSON.stringify({jobClass:e.jobClass,payload:e.payload}),e.attempts,e.maxAttempts,Math.floor(e.availableAt/1e3),Math.floor(e.createdAt/1e3)])}async pop(e="default"){let t=await this.getConnection(),r=Math.floor(Date.now()/1e3),n=await t.raw(`SELECT * FROM ${this.table}
|
|
22
|
+
WHERE queue = ? AND available_at <= ? AND reserved_at IS NULL
|
|
23
|
+
ORDER BY created_at ASC LIMIT 1`,[e,r]);if(!n||n.length===0)return null;let i=n[0];await t.raw(`UPDATE ${this.table} SET reserved_at = ?, attempts = attempts + 1 WHERE id = ?`,[r,i.id]);let s=JSON.parse(i.payload),d=this.registry.resolve(s.jobClass,s.payload);return{id:i.id,jobClass:s.jobClass,payload:s.payload,queue:i.queue,attempts:i.attempts+1,maxAttempts:i.max_attempts,availableAt:i.available_at*1e3,createdAt:i.created_at*1e3,job:d}}async size(e="default"){return(await(await this.getConnection()).raw(`SELECT COUNT(*) as count FROM ${this.table} WHERE queue = ? AND reserved_at IS NULL`,[e]))?.[0]?.count??0}async clear(e){let t=await this.getConnection();e?await t.raw(`DELETE FROM ${this.table} WHERE queue = ?`,[e]):await t.raw(`DELETE FROM ${this.table}`,[])}async delete(e){await(await this.getConnection()).raw(`DELETE FROM ${this.table} WHERE id = ?`,[e])}async release(e,t=0){let r=await this.getConnection(),n=Math.floor(Date.now()/1e3)+t;await r.raw(`UPDATE ${this.table} SET reserved_at = NULL, available_at = ? WHERE id = ?`,[n,e])}},B=class{queues=new Map;config;registry;_bullmq=null;constructor(e,t){this.config=e,this.registry=t}async getBullMQ(){if(this._bullmq)return this._bullmq;try{return this._bullmq=await Function('return import("bullmq")')(),this._bullmq}catch{throw new Error("bullmq is required for the Redis queue driver. Install it with: npm install bullmq")}}getRedisConnection(){if(this.config.url){let e=new URL(this.config.url);return{host:e.hostname||"localhost",port:parseInt(e.port)||6379,password:e.password||this.config.password||void 0,db:parseInt(e.pathname?.slice(1)||"0")||this.config.db||0}}return{host:this.config.host??"localhost",port:this.config.port??6379,password:this.config.password,db:this.config.db??0}}async getQueue(e){if(this.queues.has(e))return this.queues.get(e);let t=await this.getBullMQ(),r=this.getRedisConnection(),n=this.config.prefix??"svelar",i=new t.Queue(e,{connection:r,prefix:n,defaultJobOptions:{removeOnComplete:this.config.defaultJobOptions?.removeOnComplete??100,removeOnFail:this.config.defaultJobOptions?.removeOnFail??500}});return this.queues.set(e,i),i}async push(e){let t=await this.getQueue(e.queue),r=Math.max(0,e.availableAt-Date.now());await t.add(e.jobClass,{jobClass:e.jobClass,payload:e.payload},{jobId:e.id,delay:r>0?r:void 0,attempts:e.maxAttempts,backoff:{type:"fixed",delay:(e.job.retryDelay??60)*1e3}})}async pop(e){return null}async size(e="default"){let r=await(await this.getQueue(e)).getJobCounts("waiting","delayed","active");return r.waiting+r.delayed+r.active}async clear(e){if(e)await(await this.getQueue(e)).obliterate({force:!0});else for(let t of this.queues.values())await t.obliterate({force:!0})}async createWorker(e,t,r,n){let i=await this.getBullMQ(),s=this.getRedisConnection(),d=this.config.prefix??"svelar",o=new i.Worker(e,async c=>{let l=c.data,u=t.resolve(l.jobClass,l.payload);u.attempts=c.attemptsMade+1,await u.handle()},{connection:s,prefix:d,concurrency:n?.concurrency??1});return o.on("failed",async(c,l)=>{let u=c?.data;if(u)try{let h=t.resolve(u.jobClass,u.payload);c.attemptsMade>=(c.opts?.attempts??3)&&(h.failed(l),await r.store({id:c.id,jobClass:u.jobClass,payload:u.payload,queue:e,attempts:c.attemptsMade,maxAttempts:c.opts?.attempts??3,availableAt:Date.now(),createdAt:c.timestamp??Date.now(),job:h},l))}catch{console.error("[Queue] Failed to resolve job for failure handler:",l.message)}}),o}},L=class{table="svelar_failed_jobs";async getConnection(){let{Connection:e}=await Promise.resolve().then(()=>(W(),U));return e}async store(e,t){try{await(await this.getConnection()).raw(`INSERT INTO ${this.table} (id, queue, job_class, payload, exception, failed_at)
|
|
24
|
+
VALUES (?, ?, ?, ?, ?, ?)`,[crypto.randomUUID(),e.queue,e.jobClass,e.payload,t.stack??t.message,Math.floor(Date.now()/1e3)])}catch{console.error("[Queue] Could not persist failed job (run migration to create svelar_failed_jobs table)")}}async all(){return(await(await this.getConnection()).raw(`SELECT * FROM ${this.table} ORDER BY failed_at DESC`,[])??[]).map(r=>({id:r.id,queue:r.queue,jobClass:r.job_class,payload:r.payload,exception:r.exception,failedAt:r.failed_at}))}async find(e){let r=await(await this.getConnection()).raw(`SELECT * FROM ${this.table} WHERE id = ? LIMIT 1`,[e]);if(!r||r.length===0)return null;let n=r[0];return{id:n.id,queue:n.queue,jobClass:n.job_class,payload:n.payload,exception:n.exception,failedAt:n.failed_at}}async forget(e){return await(await this.getConnection()).raw(`DELETE FROM ${this.table} WHERE id = ?`,[e]),!0}async flush(){let e=await this.getConnection(),r=(await e.raw(`SELECT COUNT(*) as count FROM ${this.table}`,[]))?.[0]?.count??0;return await e.raw(`DELETE FROM ${this.table}`,[]),r}},N=class{jobs=new Map;register(e){this.jobs.set(e.name,e)}registerAll(e){for(let t of e)this.register(t)}resolve(e,t){let r=this.jobs.get(e);if(!r)throw new Error(`Job class "${e}" is not registered. Call Queue.register(${e}) in your app bootstrap. Registered jobs: [${[...this.jobs.keys()].join(", ")}]`);let n=Object.create(r.prototype);n.attempts=0,n.maxAttempts=3,n.retryDelay=60,n.queue="default";try{let i=JSON.parse(t);n.restore(i)}catch{}return n}has(e){return this.jobs.has(e)}},K=class{config={default:"sync",connections:{sync:{driver:"sync"}}};drivers=new Map;processing=!1;jobRegistry=new N;failedStore=new L;_activeWorker=null;configure(e){this.config=e,this.drivers.clear()}register(e){this.jobRegistry.register(e)}registerAll(e){this.jobRegistry.registerAll(e)}async dispatch(e,t){let r=this.config.default,n=this.config.connections[r],i=this.resolveDriver(r);t?.queue&&(e.queue=t.queue),t?.maxAttempts!==void 0&&(e.maxAttempts=t.maxAttempts);let s={id:crypto.randomUUID(),jobClass:e.constructor.name,payload:e.serialize(),queue:e.queue??n?.queue??"default",attempts:0,maxAttempts:e.maxAttempts,availableAt:Date.now()+(t?.delay??0)*1e3,createdAt:Date.now(),job:e};await i.push(s)}async dispatchSync(e){let t=new q,r={id:crypto.randomUUID(),jobClass:e.constructor.name,payload:e.serialize(),queue:e.queue,attempts:0,maxAttempts:e.maxAttempts,availableAt:Date.now(),createdAt:Date.now(),job:e};await t.push(r)}async chain(e,t){if(e.length===0)return;let r=new Y(e);t?.queue&&(r.queue=t.queue),t?.maxAttempts!==void 0&&(r.maxAttempts=t.maxAttempts),await this.dispatch(r,t)}async work(e){let t=this.config.default,r=this.resolveDriver(t),n=e?.queue??"default";if(r instanceof B){let o=await r.createWorker(n,this.jobRegistry,this.failedStore,{concurrency:e?.concurrency??1});return this.processing=!0,this._activeWorker=o,await new Promise(c=>{let l=()=>{this.processing?setTimeout(l,500):o.close().then(c).catch(c)};l()}),0}let i=e?.maxJobs??1/0,s=(e?.sleep??1)*1e3,d=0;for(this.processing=!0;this.processing&&d<i;){let o=await r.pop(n);if(!o){if(i===1/0){await new Promise(c=>setTimeout(c,s));continue}break}o.attempts++,o.job.attempts=o.attempts;try{await o.job.handle(),d++,r instanceof C&&await r.delete(o.id)}catch(c){if(o.attempts<o.maxAttempts){o.job.retrying(o.attempts);let l=o.job.retryDelay??60;r instanceof C?await r.release(o.id,l):(o.availableAt=Date.now()+l*1e3,await r.push(o))}else o.job.failed(c),await this.failedStore.store(o,c),r instanceof C&&await r.delete(o.id)}}return d}async stop(){this.processing=!1,this._activeWorker&&(await this._activeWorker.close(),this._activeWorker=null)}async size(e){return this.resolveDriver(this.config.default).size(e)}async clear(e){return this.resolveDriver(this.config.default).clear(e)}async failed(){return this.failedStore.all()}async retry(e){let t=await this.failedStore.find(e);if(!t)return!1;let r=this.jobRegistry.resolve(t.jobClass,t.payload);return r.queue=t.queue,await this.dispatch(r,{queue:t.queue}),await this.failedStore.forget(e),!0}async retryAll(){let e=await this.failedStore.all(),t=0;for(let r of e)try{let n=this.jobRegistry.resolve(r.jobClass,r.payload);n.queue=r.queue,await this.dispatch(n,{queue:r.queue}),await this.failedStore.forget(r.id),t++}catch{}return t}async forgetFailed(e){return this.failedStore.forget(e)}async flushFailed(){return this.failedStore.flush()}resolveDriver(e){if(this.drivers.has(e))return this.drivers.get(e);let t=this.config.connections[e];if(!t)throw new Error(`Queue connection "${e}" is not defined.`);let r;switch(t.driver){case"sync":r=new q;break;case"memory":r=new G;break;case"database":r=new C(t.table??"svelar_jobs",this.jobRegistry);break;case"redis":r=new B(t,this.jobRegistry);break;default:throw new Error(`Unknown queue driver: ${t.driver}`)}return this.drivers.set(e,r),r}},Y=class extends A{remainingJobs;constructor(e){super(),this.remainingJobs=[...e],this.maxAttempts=1}async handle(){for(let e of this.remainingJobs){let t=null,r=!1;for(let n=1;n<=e.maxAttempts;n++){e.attempts=n;try{await e.handle(),r=!0;break}catch(i){t=i,n<e.maxAttempts&&(e.retrying(n),e.retryDelay>0&&await new Promise(s=>setTimeout(s,e.retryDelay*1e3)))}}if(!r&&t)throw e.failed(t),new Error(`Chain stopped: ${e.constructor.name} failed after ${e.maxAttempts} attempt(s). Remaining jobs: [${this.remainingJobs.slice(this.remainingJobs.indexOf(e)+1).map(n=>n.constructor.name).join(", ")}]`)}}serialize(){return JSON.stringify({jobs:this.remainingJobs.map(e=>({jobClass:e.constructor.name,payload:e.serialize()}))})}},we=v("svelar.queue",()=>new K)});var oe={};S(oe,{GeneratePdfJob:()=>_,PDF:()=>ve});import{readFileSync as ue}from"fs";import{basename as he}from"path";function g(){return D.driver||"pdfkit"}function x(){return D.gotenberg||{}}function H(){return D.pdfkit||{}}function P(a){if(!a)return;let e=a.match(/^([\d.]+)\s*(in|mm|cm|pt|px)?$/);if(!e)return;let t=parseFloat(e[1]);switch(e[2]||"pt"){case"in":return t*72;case"mm":return t*(72/25.4);case"cm":return t*(72/2.54);case"pt":return t;case"px":return t*.75;default:return t}}async function fe(a,e,t){let r=t.font||"Helvetica",n=t.fontSize||12;a.font(r).fontSize(n);let i=e,s=e.match(/<body[^>]*>([\s\S]*?)<\/body>/i);s&&(i=s[1]),i=i.replace(/<style[^>]*>[\s\S]*?<\/style>/gi,""),i=i.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,""),i=i.replace(/<head[^>]*>[\s\S]*?<\/head>/gi,"");let d=i.split(/\n/);for(let o of d){let c=o.trim();if(!c)continue;let l=c.match(/<h1[^>]*>(.*?)<\/h1>/i);if(l){a.fontSize(28).font(`${r}-Bold`).text(m(l[1]),{paragraphGap:8}),a.font(r).fontSize(n);continue}let u=c.match(/<h2[^>]*>(.*?)<\/h2>/i);if(u){a.fontSize(22).font(`${r}-Bold`).text(m(u[1]),{paragraphGap:6}),a.font(r).fontSize(n);continue}let h=c.match(/<h3[^>]*>(.*?)<\/h3>/i);if(h){a.fontSize(18).font(`${r}-Bold`).text(m(h[1]),{paragraphGap:4}),a.font(r).fontSize(n);continue}let k=c.match(/<h4[^>]*>(.*?)<\/h4>/i);if(k){a.fontSize(15).font(`${r}-Bold`).text(m(k[1]),{paragraphGap:3}),a.font(r).fontSize(n);continue}if(/<hr\s*\/?>/i.test(c)){a.moveDown(.5);let ie=a.y;a.moveTo(a.page.margins.left,ie).lineTo(a.page.width-a.page.margins.right,ie).stroke("#cccccc"),a.moveDown(.5);continue}if(/<br\s*\/?>/i.test(c)){a.moveDown(.5);continue}let w=c.match(/<li[^>]*>(.*?)<\/li>/i);if(w){a.text(` \u2022 ${m(w[1])}`,{paragraphGap:2});continue}let E=c.match(/<p[^>]*>(.*?)<\/p>/i);if(E){a.text(m(E[1]),{paragraphGap:4});continue}let re=m(c);re&&a.text(re,{paragraphGap:2})}}function m(a){return a.replace(/<[^>]+>/g,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").trim()}async function M(a,e={}){let t;try{t=(await import("pdfkit")).default}catch{throw new Error(`PDFKit is not installed. Install it with: npm install pdfkit
|
|
25
|
+
Or switch to the Gotenberg driver: PDF.configure({ driver: 'gotenberg' })`)}let r=H(),n={bufferPages:!0};e.landscape&&(n.layout="landscape"),e.pageSize?.width&&e.pageSize?.height?n.size=[P(e.pageSize.width)||595.28,P(e.pageSize.height)||841.89]:n.size=r.pageSize||"A4";let i=P(e.margins?.top)??r.margins?.top??72,s=P(e.margins?.bottom)??r.margins?.bottom??72,d=P(e.margins?.left)??r.margins?.left??72,o=P(e.margins?.right)??r.margins?.right??72;n.margins={top:i,bottom:s,left:d,right:o};let c=new t(n),l=[];if(c.on("data",u=>l.push(u)),await a(c),r.pageNumbers){let u=c.bufferedPageRange().count;for(let h=0;h<u;h++)c.switchToPage(h),c.fontSize(9).font("Helvetica").text(`Page ${h+1} of ${u}`,0,c.page.height-n.margins.bottom+20,{align:"center",width:c.page.width})}return new Promise((u,h)=>{c.on("end",()=>u(Buffer.concat(l))),c.on("error",h),c.end()})}function ge(){return x().url??process.env.GOTENBERG_URL??"http://localhost:3000"}async function p(a,e,t){let r=`${ge()}${a}`,n=e.build(),i=x(),s=i.timeout??6e4,d=t&&Object.keys(t).length>0,o=new AbortController,c=setTimeout(()=>o.abort(),s);try{let l=await fetch(r,{method:"POST",headers:{"Content-Type":e.contentType,...i.headers??{},...t??{}},body:new Uint8Array(n),signal:o.signal});if(d){if(l.status!==204&&!l.ok){let h=await l.text().catch(()=>"");throw new Error(`Gotenberg webhook error ${l.status}: ${h||l.statusText}`)}return Buffer.alloc(0)}if(!l.ok){let h=await l.text().catch(()=>"");throw new Error(`Gotenberg error ${l.status}: ${h||l.statusText}`)}let u=await l.arrayBuffer();return Buffer.from(u)}finally{clearTimeout(c)}}async function ye(){if(g()==="pdfkit")try{return await import("pdfkit"),{status:"up",driver:"pdfkit",details:{installed:!0}}}catch{return{status:"down",driver:"pdfkit",details:{installed:!1,fix:"npm install pdfkit"}}}let e=`${ge()}/health`;try{let t=await fetch(e),r=await t.json();return{status:t.ok?"up":"down",driver:"gotenberg",details:r}}catch(t){return{status:"unreachable",driver:"gotenberg",details:t.message}}}var D,f,b,R,V,X,Z,ee,T,te,ve,ce=y(()=>{I();D={driver:"pdfkit"};f=class{boundary=`----SvelarBoundary${Date.now()}${Math.random().toString(36).slice(2)}`;parts=[];get contentType(){return`multipart/form-data; boundary=${this.boundary}`}addField(e,t){let r=`--${this.boundary}\r
|
|
26
|
+
Content-Disposition: form-data; name="${e}"\r
|
|
27
|
+
\r
|
|
28
|
+
`;return this.parts.push(Buffer.from(r+t+`\r
|
|
29
|
+
`)),this}addFile(e,t,r,n="application/octet-stream"){let i=typeof r=="string"?Buffer.from(r):r,s=`--${this.boundary}\r
|
|
30
|
+
Content-Disposition: form-data; name="${e}"; filename="${t}"\r
|
|
31
|
+
Content-Type: ${n}\r
|
|
32
|
+
\r
|
|
33
|
+
`;return this.parts.push(Buffer.concat([Buffer.from(s),i,Buffer.from(`\r
|
|
34
|
+
`)])),this}build(){return this.parts.push(Buffer.from(`--${this.boundary}--\r
|
|
35
|
+
`)),Buffer.concat(this.parts)}};b=class{_margins={};_pageSize={};_landscape=!1;_scale;_headerHtml;_footerHtml;_printBackground=!0;_preferCssPageSize=!1;_waitDelay;_waitExpression;_extraHeaders={};_pdfFormat;_metadata={};_webhook;_downloadFrom=[];margins(e){return this._margins=e,this}pageSize(e){return this._pageSize=e,this}landscape(e=!0){return this._landscape=e,this}scale(e){return this._scale=e,this}header(e){return this._headerHtml=e,this}footer(e){return this._footerHtml=e,this}printBackground(e=!0){return this._printBackground=e,this}preferCssPageSize(e=!0){return this._preferCssPageSize=e,this}waitDelay(e){return this._waitDelay=e,this}waitForExpression(e){return this._waitExpression=e,this}pdfFormat(e){return this._pdfFormat=e,this}meta(e,t){return this._metadata[e]=t,this}webhook(e){return this._webhook=e,this}downloadFrom(e){return this._downloadFrom=e,this}async generateAsync(){if(g()!=="gotenberg")throw new Error("generateAsync() is only available with the Gotenberg driver.");let e=x();if(!this._webhook&&!e.webhookUrl)throw new Error("Webhook not configured. Call .webhook({ url, errorUrl }) or set webhookUrl in PDF.configure().");await this.generate()}applyChromiumFields(e){this._margins.top&&e.addField("marginTop",this._margins.top),this._margins.bottom&&e.addField("marginBottom",this._margins.bottom),this._margins.left&&e.addField("marginLeft",this._margins.left),this._margins.right&&e.addField("marginRight",this._margins.right),this._pageSize.width&&e.addField("paperWidth",this._pageSize.width),this._pageSize.height&&e.addField("paperHeight",this._pageSize.height),this._landscape&&e.addField("landscape","true"),this._scale!==void 0&&e.addField("scale",String(this._scale)),this._printBackground&&e.addField("printBackground","true"),this._preferCssPageSize&&e.addField("preferCssPageSize","true"),this._waitDelay&&e.addField("waitDelay",this._waitDelay),this._waitExpression&&e.addField("waitForExpression",this._waitExpression),this._pdfFormat&&e.addField("pdfa",this._pdfFormat);for(let[t,r]of Object.entries(this._metadata))e.addField(`metadata[${t}]`,r);this._downloadFrom.length>0&&e.addField("downloadFrom",JSON.stringify(this._downloadFrom))}getWebhookHeaders(){let e=x(),t=this._webhook??(e.webhookUrl?{url:e.webhookUrl,errorUrl:e.webhookErrorUrl??e.webhookUrl}:void 0);if(!t)return{};let r={"Gotenberg-Webhook-Url":t.url,"Gotenberg-Webhook-Error-Url":t.errorUrl};return t.method&&(r["Gotenberg-Webhook-Method"]=t.method),t.errorMethod&&(r["Gotenberg-Webhook-Error-Method"]=t.errorMethod),t.extraHeaders&&(r["Gotenberg-Webhook-Extra-Http-Headers"]=JSON.stringify(t.extraHeaders)),r}get isAsync(){let e=x();return!!(this._webhook||e.webhookUrl)}async store(e){let{writeFileSync:t,mkdirSync:r}=await import("fs"),{dirname:n}=await import("path"),i=await this.generate();return r(n(e),{recursive:!0}),t(e,i),i}},R=class extends b{constructor(t){super();this.htmlContent=t}async generate(){if(g()==="pdfkit")return M(async r=>{await fe(r,this.htmlContent,H())},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape,headerHtml:this._headerHtml,footerHtml:this._footerHtml});let t=new f;return t.addFile("files","index.html",this.htmlContent,"text/html"),this._headerHtml&&t.addFile("files","header.html",this._headerHtml,"text/html"),this._footerHtml&&t.addFile("files","footer.html",this._footerHtml,"text/html"),this.applyChromiumFields(t),p("/forms/chromium/convert/html",t,this.getWebhookHeaders())}},V=class extends b{constructor(t){super();this.targetUrl=t}async generate(){if(g()==="pdfkit"){let r=await fetch(this.targetUrl,{headers:this._extraHeaders});if(!r.ok)throw new Error(`Failed to fetch ${this.targetUrl}: ${r.status}`);let n=await r.text();return M(async i=>{await fe(i,n,H())},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape})}let t=new f;t.addField("url",this.targetUrl),this._headerHtml&&t.addFile("files","header.html",this._headerHtml,"text/html"),this._footerHtml&&t.addFile("files","footer.html",this._footerHtml,"text/html");for(let[r,n]of Object.entries(this._extraHeaders))t.addField(`extraHttpHeaders[${r}]`,n);return this.applyChromiumFields(t),p("/forms/chromium/convert/url",t,this.getWebhookHeaders())}httpHeaders(t){return this._extraHeaders={...this._extraHeaders,...t},this}},X=class extends b{constructor(t,r){super();this.markdownContent=t;this.wrapperHtml=r??`<!DOCTYPE html>
|
|
36
|
+
<html><head><meta charset="utf-8"></head>
|
|
37
|
+
<body>{{ toHTML "file.md" }}</body></html>`}wrapperHtml;async generate(){if(g()==="pdfkit")return M(async r=>{let n=H(),i=n.font||"Helvetica",s=n.fontSize||12;r.font(i).fontSize(s);let d=this.markdownContent.split(`
|
|
38
|
+
`);for(let o of d)if(o.startsWith("### "))r.fontSize(16).font(`${i}-Bold`).text(o.slice(4),{paragraphGap:3}),r.font(i).fontSize(s);else if(o.startsWith("## "))r.fontSize(20).font(`${i}-Bold`).text(o.slice(3),{paragraphGap:5}),r.font(i).fontSize(s);else if(o.startsWith("# "))r.fontSize(26).font(`${i}-Bold`).text(o.slice(2),{paragraphGap:7}),r.font(i).fontSize(s);else if(o.startsWith("- ")||o.startsWith("* "))r.text(` \u2022 ${o.slice(2)}`,{paragraphGap:2});else if(o.startsWith("---")||o.startsWith("***")){r.moveDown(.5);let c=r.y;r.moveTo(r.page.margins.left,c).lineTo(r.page.width-r.page.margins.right,c).stroke("#cccccc"),r.moveDown(.5)}else if(o.trim()==="")r.moveDown(.5);else{let c=o.replace(/\*\*(.+?)\*\*/g,"$1").replace(/\*(.+?)\*/g,"$1");r.text(c,{paragraphGap:2})}},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape});let t=new f;return t.addFile("files","index.html",this.wrapperHtml,"text/html"),t.addFile("files","file.md",this.markdownContent,"text/markdown"),this._headerHtml&&t.addFile("files","header.html",this._headerHtml,"text/html"),this._footerHtml&&t.addFile("files","footer.html",this._footerHtml,"text/html"),this.applyChromiumFields(t),p("/forms/chromium/convert/markdown",t,this.getWebhookHeaders())}},Z=class extends b{filePaths=[];fileBuffers=[];constructor(e,t){super(),typeof e=="string"?this.filePaths.push(e):Buffer.isBuffer(e)&&t&&this.fileBuffers.push({name:t,buffer:e})}addFile(e,t){return typeof e=="string"?this.filePaths.push(e):Buffer.isBuffer(e)&&t&&this.fileBuffers.push({name:t,buffer:e}),this}async generate(){if(g()==="pdfkit")throw new Error(`Office document conversion requires the Gotenberg driver.
|
|
39
|
+
Switch with: PDF.configure({ driver: 'gotenberg', gotenberg: { url: 'http://localhost:3000' } })`);let e=new f;for(let t of this.filePaths){let r=ue(t);e.addFile("files",he(t),r)}for(let{name:t,buffer:r}of this.fileBuffers)e.addFile("files",t,r);return this._landscape&&e.addField("landscape","true"),this._pdfFormat&&e.addField("pdfa",this._pdfFormat),this._downloadFrom.length>0&&e.addField("downloadFrom",JSON.stringify(this._downloadFrom)),p("/forms/libreoffice/convert",e,this.getWebhookHeaders())}},ee=class extends b{htmlFiles=[];pdfBuffers=[];addHtml(e,t=`page${this.htmlFiles.length+1}.html`){return this.htmlFiles.push({name:t,content:e}),this}addPdf(e,t=`doc${this.pdfBuffers.length+1}.pdf`){return this.pdfBuffers.push({name:t,buffer:e}),this}addPdfFile(e){let t=ue(e);return this.pdfBuffers.push({name:he(e),buffer:t}),this}async generate(){if(g()==="pdfkit")throw new Error(`PDF merging requires the Gotenberg driver.
|
|
40
|
+
Switch with: PDF.configure({ driver: 'gotenberg', gotenberg: { url: 'http://localhost:3000' } })`);if(this.htmlFiles.length===0&&this.pdfBuffers.length>0){let n=new f;for(let{name:i,buffer:s}of this.pdfBuffers)n.addFile("files",i,s,"application/pdf");return p("/forms/pdfengines/merge",n,this.getWebhookHeaders())}if(this.htmlFiles.length>0&&this.pdfBuffers.length===0){let n=new f;for(let{name:i,content:s}of this.htmlFiles)n.addFile("files",i,s,"text/html");return this.applyChromiumFields(n),p("/forms/chromium/convert/html",n,this.getWebhookHeaders())}let e=[];for(let{content:n}of this.htmlFiles){let i=await new R(n).generate();e.push(i)}let t=new f,r=0;for(let n of e)t.addFile("files",`converted_${r++}.pdf`,n,"application/pdf");for(let{name:n,buffer:i}of this.pdfBuffers)t.addFile("files",n,i,"application/pdf");return p("/forms/pdfengines/merge",t,this.getWebhookHeaders())}},T=class{constructor(e,t){this.mode=e;this.content=t}_format="png";_quality=100;_width=1920;_height=1080;_clipSelector;format(e){return this._format=e,this}quality(e){return this._quality=e,this}viewport(e,t){return this._width=e,this._height=t,this}clip(e){return this._clipSelector=e,this}async generate(){if(g()==="pdfkit")throw new Error(`Screenshots require the Gotenberg driver.
|
|
41
|
+
Switch with: PDF.configure({ driver: 'gotenberg', gotenberg: { url: 'http://localhost:3000' } })`);let e=new f;this.mode==="html"?e.addFile("files","index.html",this.content,"text/html"):e.addField("url",this.content),e.addField("format",this._format),e.addField("quality",String(this._quality)),e.addField("width",String(this._width)),e.addField("height",String(this._height)),this._clipSelector&&e.addField("clipSelector",this._clipSelector);let t=this.mode==="html"?"/forms/chromium/screenshot/html":"/forms/chromium/screenshot/url";return p(t,e)}},te=class{_margins={};_pageSize={};_landscape=!1;margins(e){return this._margins=e,this}pageSize(e){return this._pageSize=e,this}landscape(e=!0){return this._landscape=e,this}async build(e){return M(async t=>{await e(t)},{margins:this._margins,pageSize:this._pageSize,landscape:this._landscape})}async store(e,t){let{writeFileSync:r,mkdirSync:n}=await import("fs"),{dirname:i}=await import("path"),s=await this.build(t);return n(i(e),{recursive:!0}),r(e,s),s}};ve={configure(a){D={...D,...a}},get driver(){return g()},html(a){return new R(a)},url(a){return new V(a)},markdown(a,e){return new X(a,e)},office(a,e){return new Z(a,e)},merge(){return new ee},create(){return new te},screenshotHtml(a){return new T("html",a)},screenshotUrl(a){return new T("url",a)},health:ye,async dispatch(a){let{GeneratePdfJob:e}=await Promise.resolve().then(()=>(I(),ae)),{Queue:t}=await Promise.resolve().then(()=>(de(),le));await t.dispatch(new e(a))}}});ce();export{_ as GeneratePdfJob,ve as PDF};
|