template-replacement 3.3.2 → 3.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.
Files changed (56) hide show
  1. package/.editorconfig +8 -0
  2. package/.oxfmtrc.jsonc +7 -0
  3. package/.oxlintrc.json +3 -0
  4. package/README.md +39 -9
  5. package/core/base.ts +54 -55
  6. package/core/general.ts +37 -9
  7. package/core/sign.ts +43 -8
  8. package/dispatcher/general.ts +2 -1
  9. package/dispatcher/sign.ts +2 -1
  10. package/dispatcher/workerGeneral.ts +1 -1
  11. package/dispatcher/workerSign.ts +1 -1
  12. package/dist/base-DQz39fXI.js +249 -0
  13. package/dist/index-oILo_kXG.js +46 -0
  14. package/dist/main/general.js +1373 -1401
  15. package/dist/main/sign.js +1559 -1573
  16. package/dist/replace/general.js +281 -306
  17. package/dist/replace/sign.js +304 -315
  18. package/download/index.ts +13 -13
  19. package/download/stream.ts +29 -28
  20. package/eslint.config.ts +28 -0
  21. package/fileSystem/db/index.ts +25 -25
  22. package/fileSystem/db/indexedDBCache.ts +142 -124
  23. package/fileSystem/index.ts +5 -8
  24. package/fileSystem/interface.ts +4 -5
  25. package/fileSystem/opfs/index.ts +40 -36
  26. package/helper/index.ts +144 -116
  27. package/index.ts +9 -17
  28. package/office/zip.ts +106 -97
  29. package/package.json +17 -11
  30. package/replace/base.ts +203 -214
  31. package/replace/general.ts +44 -19
  32. package/replace/image.ts +88 -86
  33. package/replace/interface.ts +29 -24
  34. package/replace/paramsData.ts +108 -96
  35. package/replace/sign.ts +79 -43
  36. package/task/urlDownloadTask.ts +54 -63
  37. package/temp/index.ts +139 -131
  38. package/temp/interface.ts +8 -8
  39. package/tsconfig.json +1 -1
  40. package/vite.config.ts +11 -14
  41. package/worker/child/agency.ts +49 -41
  42. package/worker/child/base.ts +125 -89
  43. package/worker/child/general.ts +2 -3
  44. package/worker/child/sign.ts +4 -4
  45. package/worker/index.ts +52 -51
  46. package/worker/interface.ts +9 -6
  47. package/worker/main/general.ts +5 -5
  48. package/worker/main/index.ts +191 -66
  49. package/worker/main/sign.ts +5 -5
  50. package/worker/type.ts +16 -15
  51. package/dist/assets/template_replacement_core_wasm_bg.wasm +0 -0
  52. package/dist/assets/template_replacement_sign_core_wasm_bg.wasm +0 -0
  53. package/dist/base-BuKBOMgk.js +0 -269
  54. package/dist/general.d.ts +0 -1
  55. package/dist/index-tFDVIkZX.js +0 -46
  56. package/dist/sign.d.ts +0 -1
package/helper/index.ts CHANGED
@@ -2,159 +2,187 @@ import urlDownloadTask from '../task/urlDownloadTask'
2
2
  import { fileTypeFromBuffer } from 'file-type'
3
3
 
4
4
  export function urlSuffix(url: string): string {
5
- url = url.split('?')[0]
6
- if (url.lastIndexOf('.') === -1) {
7
- return ''
8
- }
9
- return url.substring(url.lastIndexOf('.') + 1)
5
+ url = url.split('?')[0]
6
+ if (url.lastIndexOf('.') === -1) {
7
+ return ''
8
+ }
9
+ return url.substring(url.lastIndexOf('.') + 1)
10
10
  }
11
11
 
12
- export function getFileNameFromUrl(url: string): string {
13
- url = url.split('?')[0]
14
- const pathParts = url.split('/')
15
- return pathParts[pathParts.length - 1]
12
+ export function getFileNameFromUrl(url: string): string {
13
+ url = url.split('?')[0]
14
+ const pathParts = url.split('/')
15
+ return pathParts[pathParts.length - 1]
16
16
  }
17
17
 
18
- export const enum fileTypes {
19
- word = 'word',
20
- excel = 'excel',
21
- unknown = 'unknown',
18
+ export const enum fileTypes {
19
+ word = 'word',
20
+ excel = 'excel',
21
+ unknown = 'unknown',
22
22
  }
23
23
 
24
24
  export const officeMIMETypes: Record<string, fileTypes> = {
25
- //docx
26
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': fileTypes.word,
27
- //dotx
28
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.template': fileTypes.word,
29
- //xlsx
30
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': fileTypes.excel,
25
+ //docx
26
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': fileTypes.word,
27
+ //dotx
28
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.template': fileTypes.word,
29
+ //xlsx
30
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': fileTypes.excel,
31
31
  }
32
32
 
33
33
  export const officeSuffixTypes: Record<string, fileTypes> = {
34
- 'docx': fileTypes.word,
35
- 'dotx': fileTypes.word,
36
- 'xlsx': fileTypes.excel,
34
+ docx: fileTypes.word,
35
+ dotx: fileTypes.word,
36
+ xlsx: fileTypes.excel,
37
37
  }
38
38
 
39
39
  export function fileType(file: File): fileTypes {
40
- return officeMIMETypes[file.type] ?? fileTypes.unknown
40
+ return officeMIMETypes[file.type] ?? fileTypes.unknown
41
41
  }
42
42
 
43
43
  export function fileTypeByName(name: string): fileTypes {
44
- return officeSuffixTypes[urlSuffix(name)] ?? fileTypes.unknown
44
+ return officeSuffixTypes[urlSuffix(name)] ?? fileTypes.unknown
45
45
  }
46
46
 
47
- export async function fileTypeByBuffer(buffer: Uint8Array|ArrayBuffer|Blob): Promise<fileTypes> {
48
- if (buffer instanceof Blob) {
49
- buffer = await buffer.arrayBuffer()
50
- }
51
- const type = await fileTypeFromBuffer(buffer)
52
- if (type && officeMIMETypes[type.mime]) {
53
- return officeMIMETypes[type.mime]
47
+ export async function fileTypeByBuffer(
48
+ buffer: Uint8Array | ArrayBuffer | Blob,
49
+ ): Promise<fileTypes> {
50
+ if (buffer instanceof Blob) {
51
+ if (buffer.type && officeMIMETypes[buffer.type]) {
52
+ return officeMIMETypes[buffer.type]
54
53
  }
55
- return fileTypes.unknown
54
+ buffer = await buffer.arrayBuffer()
55
+ }
56
+ const type = await fileTypeFromBuffer(buffer)
57
+
58
+ if (type && officeMIMETypes[type.mime]) {
59
+ return officeMIMETypes[type.mime]
60
+ }
61
+ return fileTypes.unknown
56
62
  }
57
63
 
58
64
  export function generateId(): string {
59
- return crypto.randomUUID()
65
+ return crypto.randomUUID()
60
66
  }
61
67
 
62
68
  export type fileArrayBufferData = {
63
- name: string
64
- buffer: ArrayBuffer
65
- }
66
-
67
- export async function filesReaderArrayBuffer(files: File[]): Promise<fileArrayBufferData[]> {
68
- const awaits = []
69
- for (const file of files) {
70
- awaits.push(new Promise(async (resolve, reject) => {
71
- try {
72
- resolve({
73
- name: file.name,
74
- buffer: await file.arrayBuffer()
75
- } as fileArrayBufferData)
76
- } catch (error) {
77
- reject(error)
78
- }
79
- }))
80
- }
81
- return (await Promise.all(awaits)) as fileArrayBufferData[]
69
+ name: string
70
+ buffer: ArrayBuffer
82
71
  }
83
72
 
73
+ export function filesReaderArrayBuffer(
74
+ files: File[],
75
+ ): Promise<fileArrayBufferData[]> {
76
+ const awaits: Promise<fileArrayBufferData>[] = []
77
+ for (const file of files) {
78
+ awaits.push(
79
+ new Promise((resolve, reject) => {
80
+ try {
81
+ file
82
+ .arrayBuffer()
83
+ .then((buffer) => {
84
+ resolve({
85
+ name: file.name,
86
+ buffer,
87
+ })
88
+ })
89
+ .catch(reject)
90
+ } catch (error) {
91
+ reject(error)
92
+ }
93
+ }),
94
+ )
95
+ }
96
+ return Promise.all(awaits)
97
+ }
84
98
 
85
99
  export type fileBase64Data = {
86
- name: string
87
- base64: string
88
- }
89
-
90
- export async function filesReaderBase64(files: File[]): Promise<fileBase64Data[]> {
91
- const awaits = []
92
- for (const file of files) {
93
- awaits.push(new Promise((resolve, reject) => {
94
- const fileReader = new FileReader()
95
- fileReader.onload = function(e) {
96
- let base64 = e.target?.result as string
97
- if (!base64) {
98
- resolve({
99
- name: file.name,
100
- base64: ''
101
- })
102
- return
103
- }
104
- const index = base64.indexOf(",")
105
- if (index != -1) {
106
- base64 = base64.slice(index + 1)
107
- }
108
- resolve({
109
- name: file.name,
110
- base64: base64
111
- })
112
- }
113
- fileReader.onerror = function (e) {
114
- reject(e)
115
- }
116
- fileReader.readAsDataURL(file)
117
- }))
118
- }
119
- return await Promise.all(awaits) as fileBase64Data[]
100
+ name: string
101
+ base64: string
120
102
  }
121
103
 
122
- export function base64ToBlob(base64: string): Blob {
123
- const arr = base64.split(',')
124
- let mime
125
- if (arr.length > 1) {
126
- const m: RegExpMatchArray | null = arr[0].match(/:(.*?);/)
127
- if (m?.length) {
128
- mime = m[1]
129
- base64 = arr[1]
104
+ export function filesReaderBase64(files: File[]): Promise<fileBase64Data[]> {
105
+ const awaits: Promise<fileBase64Data>[] = []
106
+ for (const file of files) {
107
+ awaits.push(
108
+ new Promise((resolve, reject) => {
109
+ const fileReader = new FileReader()
110
+ fileReader.onload = function (e) {
111
+ let base64 = e.target?.result as string
112
+ if (!base64) {
113
+ resolve({
114
+ name: file.name,
115
+ base64: '',
116
+ })
117
+ return
118
+ }
119
+ const index = base64.indexOf(',')
120
+ if (index != -1) {
121
+ base64 = base64.slice(index + 1)
122
+ }
123
+ resolve({
124
+ name: file.name,
125
+ base64: base64,
126
+ })
130
127
  }
131
- }
132
- if (!mime) {
133
- mime = 'application/octet-stream'
134
- }
128
+ fileReader.onerror = function (e) {
129
+ reject(e)
130
+ }
131
+ fileReader.readAsDataURL(file)
132
+ }),
133
+ )
134
+ }
135
+ return Promise.all(awaits)
136
+ }
135
137
 
136
- const byteCharacters = atob(base64)
137
- const byteArray = new Uint8Array(byteCharacters.length)
138
- for (let i = 0; i < byteCharacters.length; i++) {
139
- byteArray[i] = byteCharacters.charCodeAt(i)
138
+ export function base64ToBlob(base64: string): Blob {
139
+ const arr = base64.split(',')
140
+ let mime
141
+ if (arr.length > 1) {
142
+ const m: RegExpMatchArray | null = arr[0].match(/:(.*?);/)
143
+ if (m?.length) {
144
+ mime = m[1]
145
+ base64 = arr[1]
140
146
  }
141
- return new Blob([byteArray], { type: mime })
147
+ }
148
+ if (!mime) {
149
+ mime = 'application/octet-stream'
150
+ }
151
+
152
+ const byteCharacters = atob(base64)
153
+ const byteArray = new Uint8Array(byteCharacters.length)
154
+ for (let i = 0; i < byteCharacters.length; i++) {
155
+ byteArray[i] = byteCharacters.charCodeAt(i)
156
+ }
157
+ return new Blob([byteArray], { type: mime })
142
158
  }
143
159
 
144
160
  //urls提取为文件二进制数据
145
- export async function urlsToFileBlobs(urls: string[], onDownloadProgress?: (progressEvent: any) => void): Promise<(Blob|undefined)[]> {
146
- const task = new urlDownloadTask(urls)
147
- if(onDownloadProgress) {
148
- task.onDownloadProgress(onDownloadProgress)
149
- }
150
- return await task.start()
161
+ export function urlsToFileBlobs(
162
+ urls: string[],
163
+ onDownloadProgress?: (progressEvent: unknown) => void,
164
+ ): Promise<(Blob | undefined)[]> {
165
+ const task = new urlDownloadTask(urls)
166
+ if (onDownloadProgress) {
167
+ task.onDownloadProgress(onDownloadProgress)
168
+ }
169
+ return task.start()
151
170
  }
152
171
 
153
172
  export function splitArrayIntoChunks<T>(array: T[], chunkSize: number): T[][] {
154
- const result: T[][] = []
155
- for (let i = 0; i < array.length; i += chunkSize) {
156
- const chunk = array.slice(i, i + chunkSize)
157
- result.push(chunk)
158
- }
159
- return result
160
- }
173
+ const result: T[][] = []
174
+ for (let i = 0; i < array.length; i += chunkSize) {
175
+ const chunk = array.slice(i, i + chunkSize)
176
+ result.push(chunk)
177
+ }
178
+ return result
179
+ }
180
+
181
+ // 字符串SHA-1哈希值
182
+ export async function hashString(str: string): Promise<string> {
183
+ const encoder = new TextEncoder()
184
+ const data = encoder.encode(str)
185
+ const hashBuffer = await window.crypto.subtle.digest('SHA-1', data)
186
+ const hashArray = Array.from(new Uint8Array(hashBuffer))
187
+ return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
188
+ }
package/index.ts CHANGED
@@ -4,23 +4,15 @@ import workerGeneral from './dispatcher/workerGeneral'
4
4
  import workerSign from './dispatcher/workerSign'
5
5
  import ReplaceInterface from './replace/interface'
6
6
 
7
- export function General(): ReplaceInterface {
8
- return general()
9
- }
7
+ export const General = general
10
8
 
11
- export function Sign(): ReplaceInterface {
12
- return sign()
13
- }
9
+ export const Sign = sign
14
10
 
15
- export function WorkerGeneral(concurrency?: number): ReplaceInterface {
16
- return workerGeneral(concurrency)
17
- }
11
+ export const WorkerGeneral = workerGeneral
18
12
 
19
- export function WorkerSign(concurrency?: number): ReplaceInterface {
20
- return workerSign(concurrency)
21
- }
13
+ export const WorkerSign = workerSign
22
14
 
23
- type signFun = (data: any) => Promise<string>;
15
+ type signFun = (data: unknown) => Promise<string>
24
16
 
25
17
  export default (concurrency?: number, signFn?: signFun): ReplaceInterface => {
26
18
  let res = undefined
@@ -28,16 +20,16 @@ export default (concurrency?: number, signFn?: signFun): ReplaceInterface => {
28
20
  if (signFn) {
29
21
  res = workerSign(concurrency)
30
22
  res.sign = signFn
31
- }else{
23
+ } else {
32
24
  res = workerGeneral(concurrency)
33
25
  }
34
- }else {
26
+ } else {
35
27
  if (signFn) {
36
28
  res = sign()
37
29
  res.sign = signFn
38
- }else{
30
+ } else {
39
31
  res = general()
40
32
  }
41
33
  }
42
34
  return res
43
- }
35
+ }
package/office/zip.ts CHANGED
@@ -1,116 +1,125 @@
1
1
  import { stream } from '../download'
2
- import { FlateError, unzip, Unzipped, zip, strToU8, AsyncZipOptions, Zip as fflateZip, ZipDeflate } from 'fflate'
2
+ import {
3
+ FlateError,
4
+ unzip,
5
+ Unzipped,
6
+ zip,
7
+ strToU8,
8
+ AsyncZipOptions,
9
+ Zip as fflateZip,
10
+ ZipDeflate,
11
+ } from 'fflate'
3
12
 
4
- type InputType = string|Uint8Array|ArrayBuffer|Blob
13
+ type InputType = string | Uint8Array | ArrayBuffer | Blob
5
14
 
6
15
  export default class Zip {
7
- name: string = ''
8
- fileBlob?: Blob
9
- _unzipData?: Unzipped
10
- _lastUpdateTime: number = 0;
16
+ name: string = ''
17
+ fileBlob?: Blob
18
+ private _unzipData?: Unzipped
19
+ private _lastUpdateTime: number = 0
11
20
 
12
- constructor(file?: Blob) {
13
- if (!file) {
14
- return
15
- }
16
- this.name = (file as File)?.name ?? ''
17
- this.fileBlob = file
21
+ constructor(file?: Blob) {
22
+ if (!file) {
23
+ return
18
24
  }
25
+ this.name = (file as File)?.name ?? ''
26
+ this.fileBlob = file
27
+ }
19
28
 
20
- getFileBlob(): Blob|undefined {
21
- return this.fileBlob
22
- }
29
+ getFileBlob(): Blob | undefined {
30
+ return this.fileBlob
31
+ }
23
32
 
24
- async fileZip(): Promise<Unzipped> {
25
- if (!this._unzipData) {
26
- try {
27
- const blob = this.getFileBlob()
28
- if (blob) {
29
- const arrayBuffer = await blob.arrayBuffer()
30
- this._unzipData = await new Promise(async (resolve, reject) => {
31
- unzip(new Uint8Array(arrayBuffer), (err: FlateError | null, data: Unzipped) => {
32
- if (err) {
33
- return reject(err)
34
- }
35
- resolve(data)
36
- })
37
- })
38
- }
39
- } catch (e) {
40
- console.warn(e)
41
- }
42
- }
43
- if (!this._unzipData) {
44
- this._unzipData = {}
33
+ async fileZip(): Promise<Unzipped> {
34
+ if (!this._unzipData) {
35
+ try {
36
+ const blob = this.getFileBlob()
37
+ if (blob) {
38
+ const arrayBuffer = await blob.arrayBuffer()
39
+ this._unzipData = await new Promise((resolve, reject) => {
40
+ unzip(
41
+ new Uint8Array(arrayBuffer),
42
+ (err: FlateError | null, data: Unzipped) => {
43
+ resolve(data)
44
+ },
45
+ )
46
+ })
45
47
  }
46
- return this._unzipData
48
+ } catch (e) {
49
+ console.warn(e)
50
+ }
47
51
  }
48
-
49
- async setZipData(path: string, data: InputType): Promise<void> {
50
- const fileZip = await this.fileZip()
51
- switch (true) {
52
- case data instanceof Blob:
53
- data = new Uint8Array(await data.arrayBuffer())
54
- break
55
- case data instanceof Uint8Array:
56
- break
57
- case data instanceof ArrayBuffer:
58
- data = new Uint8Array(data)
59
- break
60
- case data instanceof String:
61
- data = strToU8(data as string)
62
- break
63
- default:
64
- throw new Error('Invalid data type')
65
- }
66
- fileZip[path] = data as Uint8Array
67
- this._lastUpdateTime = (new Date()).getTime()
52
+ if (!this._unzipData) {
53
+ this._unzipData = {}
68
54
  }
55
+ return this._unzipData
56
+ }
69
57
 
70
- async generate(options: AsyncZipOptions): Promise<Blob|undefined> {
71
- const data = await this.fileZip()
72
- if (!Object.keys(data).length) {
73
- return undefined
74
- }
75
- return await new Promise(async (resolve, reject) => {
76
- zip(data, options, (err: FlateError | null, data: Uint8Array) => {
77
- if (err) {
78
- return reject(err)
79
- }
80
- resolve(new Blob([data]))
81
- })
82
- })
58
+ async setZipData(path: string, data: InputType): Promise<void> {
59
+ const fileZip = await this.fileZip()
60
+ switch (true) {
61
+ case data instanceof Blob:
62
+ data = new Uint8Array(await data.arrayBuffer())
63
+ break
64
+ case data instanceof Uint8Array:
65
+ break
66
+ case data instanceof ArrayBuffer:
67
+ data = new Uint8Array(data)
68
+ break
69
+ case data instanceof String:
70
+ data = strToU8(data as string)
71
+ break
72
+ default:
73
+ throw new Error('Invalid data type')
83
74
  }
75
+ fileZip[path] = data as Uint8Array
76
+ this._lastUpdateTime = new Date().getTime()
77
+ }
84
78
 
85
- async download(fileName: string): Promise<void> {
86
- const data = await this.fileZip()
87
- if (!Object.keys(data).length) {
88
- return
79
+ async generate(options: AsyncZipOptions): Promise<Blob | undefined> {
80
+ const data = await this.fileZip()
81
+ if (!Object.keys(data).length) {
82
+ return undefined
83
+ }
84
+ return await new Promise((resolve, reject) => {
85
+ zip(data, options, (err: FlateError | null, data: Uint8Array) => {
86
+ if (err) {
87
+ return reject(err)
89
88
  }
89
+ resolve(new Blob([data as BlobPart]))
90
+ })
91
+ })
92
+ }
90
93
 
91
- if (fileName == undefined) {
92
- fileName = this.name
93
- }
94
+ async download(fileName: string): Promise<void> {
95
+ const data = await this.fileZip()
96
+ if (!Object.keys(data).length) {
97
+ return
98
+ }
94
99
 
95
- const downloadStream = stream(fileName)
96
- const zip = new fflateZip((err, dat, final) => {
97
- if (err) {
98
- downloadStream.abort(err)
99
- return
100
- }
101
- downloadStream.write(dat)
102
- if (final) {
103
- downloadStream.close()
104
- }
105
- })
100
+ if (fileName == undefined) {
101
+ fileName = this.name
102
+ }
106
103
 
107
- for (const key in data) {
108
- const deflate = new ZipDeflate(key, {
109
- level: 9
110
- });
111
- zip.add(deflate)
112
- deflate.push(data[key], true);
113
- }
114
- zip.end()
104
+ const downloadStream = stream(fileName)
105
+ const zip = new fflateZip((err, dat, final) => {
106
+ if (err) {
107
+ downloadStream.abort(err)
108
+ return
109
+ }
110
+ downloadStream.write(dat)
111
+ if (final) {
112
+ downloadStream.close()
113
+ }
114
+ })
115
+
116
+ for (const key in data) {
117
+ const deflate = new ZipDeflate(key, {
118
+ level: 9,
119
+ })
120
+ zip.add(deflate)
121
+ deflate.push(data[key], true)
115
122
  }
116
- }
123
+ zip.end()
124
+ }
125
+ }
package/package.json CHANGED
@@ -1,31 +1,37 @@
1
1
  {
2
2
  "name": "template-replacement",
3
3
  "description": "模板文件替换",
4
- "version": "3.3.2",
4
+ "version": "3.4.0",
5
5
  "author": "fushiliang <994301536@qq.com>",
6
6
  "type": "module",
7
7
  "main": "index.ts",
8
8
  "license": "Apache 2.0",
9
9
  "scripts": {
10
- "build": "npx vite build --config vite.config.ts"
10
+ "build": "vite build --config vite.config.ts",
11
+ "lint": "npx oxlint && npx eslint"
11
12
  },
12
13
  "dependencies": {
13
- "@types/streamsaver": "^2.0.5",
14
- "axios": "^1.13.1",
14
+ "axios": "^1.13.2",
15
15
  "fflate": "^0.8.2",
16
16
  "file-type": "^19.6.0",
17
17
  "streamsaver": "^2.0.6",
18
- "template-replacement-core-wasm": "^1.4.0",
19
- "template-replacement-sign-core-wasm": "^1.4.0",
20
- "vite-plugin-wasm-pack": "^0.1.12"
18
+ "template-replacement-core-wasm": "^1.7.2",
19
+ "template-replacement-sign-core-wasm": "^1.7.2"
21
20
  },
22
21
  "devDependencies": {
23
- "terser": "^5.44.0",
22
+ "@rollup/pluginutils": "^5.3.0",
23
+ "@types/streamsaver": "^2.0.5",
24
+ "@typescript-eslint/eslint-plugin": "^8.50.0",
25
+ "@typescript-eslint/parser": "^8.50.0",
26
+ "eslint": "^9.39.2",
27
+ "eslint-plugin-oxlint": "^1.33.0",
28
+ "oxfmt": "^0.16.0",
29
+ "oxlint": "^1.33.0",
30
+ "terser": "^5.44.1",
24
31
  "typescript": "^5.9.3",
25
- "vite": "^7.1.12",
26
- "vite-plugin-dts": "^4.5.4"
32
+ "vite": "^7.3.0"
27
33
  },
28
34
  "keywords": [
29
35
  "template-replacement"
30
36
  ]
31
- }
37
+ }