Skip to content

Commit c00b95d

Browse files
committed
feat(ghoulscript): add option to disable cdn
1 parent fa92053 commit c00b95d

File tree

19 files changed

+1259
-403
lines changed

19 files changed

+1259
-403
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"packageManager": "yarn@4.2.2",
44
"private": true,
55
"workspaces": [
6-
"packages/*"
6+
"packages/*",
7+
"playground/*"
78
],
89
"scripts": {
910
"lint": "eslint . --ext .js,.vue,.ts --format pretty",
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import { defineBuildConfig } from 'unbuild'
22

33
export default defineBuildConfig({
4-
entries : ['src/index', 'src/rpc.worker'],
4+
entries: [
5+
{
6+
input : 'src/',
7+
outDir: 'dist/',
8+
format: 'esm',
9+
},
10+
{
11+
input : 'src/',
12+
outDir : 'dist/',
13+
format : 'cjs',
14+
ext : 'cjs',
15+
declaration: false,
16+
},
17+
],
518
declaration: true,
619
rollup : { emitCJS: true },
720
})

packages/ghoulscript/package.json

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
{
22
"name": "@privyid/ghoulscript",
33
"packageManager": "yarn@4.2.2",
4+
"version": "0.1.0-alpha.1",
45
"type": "module",
56
"main": "./dist/index.cjs",
7+
"module": "./dist/index.mjs",
68
"types": "./dist/index.d.ts",
79
"exports": {
810
".": {
911
"import": "./dist/index.mjs",
1012
"require": "./dist/index.cjs",
1113
"types": "./dist/index.d.ts"
12-
},
13-
"./rpc.worker": {
14-
"import": "./dist/rpc.worker.mjs",
15-
"require": "./dist/rpc.worker.cjs",
16-
"types": "./dist/rpc.worker.d.ts"
1714
}
1815
},
1916
"files": [
@@ -25,14 +22,14 @@
2522
"test": "jiti ./tests/sample.ts"
2623
},
2724
"devDependencies": {
28-
"@tsconfig/node20": "^20.1.4",
2925
"jiti": "^1.21.0",
3026
"typescript": "^5.4.5",
31-
"unbuild": "^2.0.0"
27+
"unbuild": "3.0.0-rc.6"
3228
},
3329
"dependencies": {
3430
"@privyid/ghostscript": "workspace:^",
35-
"defu": "^6.1.4"
31+
"defu": "^6.1.4",
32+
"ufo": "^1.5.3"
3633
},
3734
"license": "AGPL-3.0-only"
3835
}

packages/ghoulscript/src/config.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { defu } from 'defu'
2+
import { withBase } from 'ufo'
3+
import meta from '@privyid/ghostscript/meta'
4+
import { name, version } from '../package.json'
5+
6+
export interface Config {
7+
/**
8+
* Enable worker
9+
* @default true
10+
*/
11+
useWorker: boolean,
12+
/**
13+
* Enable CDN
14+
* @default true
15+
*/
16+
useCDN: boolean,
17+
/**
18+
* CDN BaseURL
19+
* @default 'https://unpkg.com/'
20+
*/
21+
cdnURL: string,
22+
}
23+
24+
let config: Config = {
25+
useWorker: typeof window !== 'undefined',
26+
useCDN : true,
27+
cdnURL : 'https://unpkg.com/',
28+
}
29+
30+
export function useConfig () {
31+
return config
32+
}
33+
34+
export function configureGS (config_: Partial<Config>) {
35+
config = defu(config_, config)
36+
}
37+
38+
export function getWorkerURL () {
39+
return withBase(`${name as string}@${version as string}/dist/rpc.worker.mjs`, config.cdnURL)
40+
}
41+
42+
export function getFileURL (url: string) {
43+
return withBase(`${meta.name}@${meta.version}/dist/${url}`, config.cdnURL)
44+
}

packages/ghoulscript/src/core.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import useGS from '@privyid/ghostscript'
1+
import type { GSModule } from '@privyid/ghostscript'
2+
import initGS from '@privyid/ghostscript'
23
import { defu } from 'defu'
4+
import { getFileURL, useConfig } from './config'
5+
import { joinRelativeURL } from 'ufo'
36

47
interface PageRange {
58
start: number,
@@ -63,6 +66,17 @@ export interface CompressOptions {
6366
pageList?: PageList,
6467
}
6568

69+
async function useGS (moduleOverrides?: Partial<GSModule>) {
70+
return await initGS(defu<Partial<GSModule>, [Partial<GSModule>]>(moduleOverrides, {
71+
locateFile (url: string, dir: string) {
72+
if ((typeof window !== 'undefined' || typeof importScripts === 'function') && useConfig().useCDN)
73+
return getFileURL(url)
74+
75+
return joinRelativeURL(dir, url)
76+
},
77+
}))
78+
}
79+
6680
async function createPDF (inputs: ArrayBufferView[], options: Partial<CompressOptions> = {}): Promise<Uint8Array> {
6781
const gs = await useGS()
6882
const opts = defu<CompressOptions, [CompressOptions]>(options, {
@@ -138,14 +152,33 @@ async function createPDF (inputs: ArrayBufferView[], options: Partial<CompressOp
138152
return gs.FS.readFile('./output', { encoding: 'binary' })
139153
}
140154

155+
/**
156+
* Optimize PDF and redure file size
157+
* @param input
158+
* @param option
159+
* @returns
160+
*/
141161
export async function optimizePDF (input: ArrayBufferView, option: Partial<CompressOptions> = {}) {
142162
return await createPDF([input], option)
143163
}
144164

165+
/**
166+
* Merge multiple files into single file
167+
* @param inputs
168+
* @param option
169+
* @returns
170+
*/
145171
export async function combinePDF (inputs: ArrayBufferView[], option: Partial<CompressOptions> = {}) {
146172
return await createPDF(inputs, option)
147173
}
148174

175+
/**
176+
* Split PDF into multiple files
177+
* @param input
178+
* @param pageLists
179+
* @param option
180+
* @returns
181+
*/
149182
export async function splitPdf (input: ArrayBufferView, pageLists: PageList[], option: Partial<CompressOptions> = {}) {
150183
return await Promise.all(
151184
pageLists.map(async (pageList) => {
@@ -154,6 +187,13 @@ export async function splitPdf (input: ArrayBufferView, pageLists: PageList[], o
154187
)
155188
}
156189

190+
/**
191+
* Add encryption password
192+
* @param input
193+
* @param userPassword
194+
* @param ownerPassword
195+
* @returns
196+
*/
157197
export async function addPassword (input: ArrayBufferView, userPassword: string, ownerPassword: string = userPassword) {
158198
return await createPDF([input], {
159199
ownerPassword,
@@ -194,6 +234,13 @@ export interface RenderOptions {
194234
format: 'jpg' | 'png',
195235
}
196236

237+
/**
238+
* Convert PDF to image
239+
* @param input Input buffer
240+
* @param pageNumber
241+
* @param options
242+
* @returns
243+
*/
197244
export async function renderPageAsImage (input: ArrayBufferView, pageNumber: number = 1, options: Partial<RenderOptions> = {}) {
198245
const gs = await useGS()
199246
const opts = defu<RenderOptions, [RenderOptions]>(options, {

packages/ghoulscript/src/index.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,53 @@
1+
import { useConfig } from './config'
12
import type {
23
CommandArgs,
34
CommandResult,
45
Commands,
5-
} from './rpc.js'
6+
} from './rpc'
67
import {
78
callRPC,
89
callWorkerRPC,
9-
} from './rpc.js'
10+
} from './rpc'
11+
import type * as core from './core'
1012

11-
interface GSConfig {
12-
useWebWorker: boolean,
13-
}
14-
15-
const config: GSConfig = { useWebWorker: typeof window !== 'undefined' }
13+
export {
14+
configureGS,
15+
} from './config'
1616

17-
export function configureGS (config_: Partial<GSConfig>) {
18-
Object.assign(config, config_)
19-
}
17+
export {
18+
setWorkerRPC,
19+
} from './rpc'
2020

2121
async function call <C extends Commands> (name: C, args: CommandArgs<C>): Promise<CommandResult<C>> {
22-
return config.useWebWorker
23-
? await callWorkerRPC(name, args)
24-
: await callRPC(name, args)
22+
return useConfig().useWorker
23+
? callWorkerRPC(name, args)
24+
: callRPC(name, args)
2525
}
2626

27-
export async function optimizePDF (...args: CommandArgs<'optimizePDF'>): CommandResult<'optimizePDF'> {
27+
export const optimizePDF: typeof core.optimizePDF = async (...args: CommandArgs<'optimizePDF'>): CommandResult<'optimizePDF'> => {
2828
return await call('optimizePDF', args)
2929
}
3030

31-
export async function combinePDF (...args: CommandArgs<'combinePDF'>): CommandResult<'combinePDF'> {
31+
export const combinePDF: typeof core.combinePDF = async (...args: CommandArgs<'combinePDF'>): CommandResult<'combinePDF'> => {
3232
return await call('combinePDF', args)
3333
}
3434

35-
export async function splitPdf (...args: CommandArgs<'splitPdf'>): CommandResult<'splitPdf'> {
35+
export const splitPdf: typeof core.splitPdf = async (...args: CommandArgs<'splitPdf'>): CommandResult<'splitPdf'> => {
3636
return await call('splitPdf', args)
3737
}
3838

39-
export async function addPassword (...args: CommandArgs<'addPassword'>): CommandResult<'addPassword'> {
39+
export const addPassword: typeof core.addPassword = async (...args: CommandArgs<'addPassword'>): CommandResult<'addPassword'> => {
4040
return await call('addPassword', args)
4141
}
4242

43-
export async function removePassword (...args: CommandArgs<'removePassword'>): CommandResult<'removePassword'> {
43+
export const removePassword: typeof core.removePassword = async (...args: CommandArgs<'removePassword'>): CommandResult<'removePassword'> => {
4444
return await call('removePassword', args)
4545
}
4646

47-
export async function renderPageAsImage (...args: CommandArgs<'renderPageAsImage'>): CommandResult<'renderPageAsImage'> {
47+
export const renderPageAsImage: typeof core.renderPageAsImage = async (...args: CommandArgs<'renderPageAsImage'>): CommandResult<'renderPageAsImage'> => {
4848
return await call('renderPageAsImage', args)
4949
}
5050

51-
export async function getInfo (...args: CommandArgs<'getInfo'>): CommandResult<'getInfo'> {
51+
export const getInfo: typeof core.getInfo = async (...args: CommandArgs<'getInfo'>): CommandResult<'getInfo'> => {
5252
return await call('getInfo', args)
5353
}

packages/ghoulscript/src/rpc.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import * as core from './core.js'
2-
3-
let worker: Worker
1+
import type { Config } from './config'
2+
import { getWorkerURL, useConfig } from './config'
3+
import * as core from './core'
44

55
export type Core = typeof core
66

@@ -16,20 +16,33 @@ export interface RPC <C extends Commands = any> {
1616
id: number,
1717
name: C,
1818
args: CommandArgs<C>,
19+
config: Config,
1920
}
2021

2122
export interface RPCResult<C extends Commands = any> {
2223
id: number,
2324
result: CommandResult<C>,
25+
error?: undefined,
2426
}
2527

28+
let worker: Worker
29+
2630
export function useWorkerRPC () {
27-
if (!worker)
28-
worker = new Worker(new URL('rpc.worker', import.meta.url))
31+
if (!worker) {
32+
const url = useConfig().useCDN
33+
? getWorkerURL()
34+
: new URL('rpc.worker.mjs', import.meta.url)
35+
36+
worker = new Worker(url, { type: 'module' })
37+
}
2938

3039
return worker
3140
}
3241

42+
export function setWorkerRPC (worker_: Worker) {
43+
worker = worker_
44+
}
45+
3346
export async function callWorkerRPC<C extends Commands, A extends CommandArgs<C>> (name: C, args: A) {
3447
return await new Promise<CommandResult<C>>((resolve, reject) => {
3548
const id = Date.now()
@@ -38,7 +51,11 @@ export async function callWorkerRPC<C extends Commands, A extends CommandArgs<C>
3851
const onMessage = (event: MessageEvent<RPCResult<C>>) => {
3952
if (event.data.id === id) {
4053
cleanUp()
41-
resolve(event.data.result)
54+
55+
if (event.data.error)
56+
reject(event.data.error)
57+
else
58+
resolve(event.data.result)
4259
}
4360
}
4461

@@ -56,9 +73,10 @@ export async function callWorkerRPC<C extends Commands, A extends CommandArgs<C>
5673
worker.addEventListener('error', onError)
5774

5875
worker.postMessage({
59-
id : id,
60-
name: name,
61-
args: args,
76+
id : id,
77+
name : name,
78+
args : args,
79+
config: useConfig(),
6280
})
6381
})
6482
}
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
/* eslint-disable @typescript-eslint/triple-slash-reference */
22
/* eslint-env serviceworker */
33

4-
import type { RPC } from './rpc.js'
5-
import { callRPC } from './rpc.js'
4+
import type { RPC } from './rpc'
5+
import { callRPC } from './rpc'
6+
import { configureGS } from './config'
67

78
self.addEventListener('message', (event: MessageEvent<RPC>) => {
8-
const rpc = event.data
9-
const id = rpc.id
9+
const rpc = event.data
10+
const id = rpc.id
11+
const config = rpc.config
12+
13+
configureGS(config)
1014

1115
callRPC(rpc.name, rpc.args)
1216
.then((result) => {
@@ -16,6 +20,9 @@ self.addEventListener('message', (event: MessageEvent<RPC>) => {
1620
})
1721
})
1822
.catch((error) => {
19-
throw error
23+
self.postMessage({
24+
id,
25+
error,
26+
})
2027
})
2128
})

packages/ghoulscript/tests/sample.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
removePassword,
1010
renderPageAsImage,
1111
splitPdf,
12-
} from '../src/index.js'
12+
} from '../dist'
1313

1414
const _filename = fileURLToPath(import.meta.url)
1515
const _dirname = dirname(_filename)

0 commit comments

Comments
 (0)