vite-plugin-sri4 1.8.1 → 1.8.3

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 (3) hide show
  1. package/dist/index.cjs +58 -127
  2. package/dist/index.js +58 -127
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -9,8 +9,7 @@ const DEFAULT_OPTIONS = {
9
9
  algorithm: 'sha384',
10
10
  bypassDomains: [],
11
11
  crossorigin: 'anonymous',
12
- debug: false,
13
- inlineScripts: false
12
+ debug: false
14
13
  };
15
14
 
16
15
  function log(message, options) {
@@ -21,9 +20,6 @@ function log(message, options) {
21
20
 
22
21
  function computeSri(content, algorithm = 'sha384') {
23
22
  try {
24
- if (typeof content === 'string') {
25
- content = Buffer.from(content, 'utf-8');
26
- }
27
23
  const hash = node_crypto.createHash(algorithm)
28
24
  .update(content)
29
25
  .digest('base64');
@@ -53,21 +49,14 @@ async function externalResourceIsCorsEnabled(url, options) {
53
49
  function isBypassDomain(url, bypassDomains = []) {
54
50
  if (!bypassDomains.length) return false;
55
51
  try {
56
- let parsedUrl;
57
- if (url.startsWith('//')) {
58
- parsedUrl = new URL(`http:${url}`);
59
- } else if (url.startsWith('http://') || url.startsWith('https://')) {
60
- parsedUrl = new URL(url);
61
- } else {
62
- parsedUrl = new URL(url, 'http://dummy');
63
- }
64
-
52
+ const parsedUrl = url.startsWith('//')
53
+ ? new URL(`http:${url}`)
54
+ : new URL(url, 'http://dummy');
65
55
  return bypassDomains.some(
66
56
  (domain) => parsedUrl.hostname === domain ||
67
57
  parsedUrl.hostname.endsWith(`.${domain}`)
68
58
  );
69
59
  } catch (e) {
70
- console.error(`${LOG_PREFIX} Failed to parse URL: ${url}`, e);
71
60
  return false;
72
61
  }
73
62
  }
@@ -76,26 +65,27 @@ function hasCrossOriginAttr(tag) {
76
65
  return /(?:^|\s)crossorigin(?:=["']?[^"'\s>]*["']?)?(?:\s|>|$)/i.test(tag);
77
66
  }
78
67
 
79
- function getAllPossiblePaths(url) {
80
- const paths = [
68
+ function getBundleKey(url, base = '') {
69
+ // 嘗試各種可能的路徑格式
70
+ const possiblePaths = [
81
71
  url,
82
- url.startsWith('/') ? url.slice(1) : url,
83
- url.startsWith('/static/') ? url.slice(8) : url,
84
- !url.startsWith('/static/') ? `static/${url}` : url,
85
- !url.startsWith('/static/') ? `/static/${url}` : url,
72
+ url.replace(/^\//, ''),
86
73
  url.replace(/^\/static\//, ''),
87
- url.replace(/^static\//, '')
74
+ url.replace(/^static\//, ''),
75
+ url.replace(base, ''),
76
+ url.replace(base, '').replace(/^\//, '')
88
77
  ];
89
78
 
90
- const withoutHash = url.replace(/-[a-zA-Z0-9]+\./, '.');
79
+ // 移除 hash 後的版本
80
+ const withoutHash = url.replace(/-[a-zA-Z0-9]+\.([^.]+)$/, '.$1');
91
81
  if (withoutHash !== url) {
92
- paths.push(...getAllPossiblePaths(withoutHash));
82
+ possiblePaths.push(...getBundleKey(withoutHash, base));
93
83
  }
94
84
 
95
- return [...new Set(paths)];
85
+ return [...new Set(possiblePaths)];
96
86
  }
97
87
 
98
- async function processTag(tag, url, options, sriMap) {
88
+ async function processTag(tag, url, options, bundle, base = '') {
99
89
  if (tag.includes('integrity=')) {
100
90
  log(`Skip tag with existing integrity attribute: ${tag}`, options);
101
91
  return tag;
@@ -136,51 +126,31 @@ async function processTag(tag, url, options, sriMap) {
136
126
  }
137
127
 
138
128
  // Handle local resources
139
- const possiblePaths = getAllPossiblePaths(url);
140
- let integrity = null;
129
+ const possibleKeys = getBundleKey(url, base);
130
+ let bundleItem = null;
141
131
 
142
- log(`Checking possible paths for ${url}:`, options);
143
- for (const path of possiblePaths) {
144
- log(`- Checking path: ${path}`, options);
145
- if (sriMap.has(path)) {
146
- integrity = sriMap.get(path);
147
- log(`Found integrity for path ${path}: ${integrity}`, options);
132
+ for (const key of possibleKeys) {
133
+ if (bundle[key]) {
134
+ bundleItem = bundle[key];
135
+ log(`Found bundle item for key: ${key}`, options);
148
136
  break;
149
137
  }
150
138
  }
151
139
 
152
- if (integrity) {
153
- log(`Using precomputed SRI for ${url}: ${integrity}`, options);
154
- const hasCrossOrigin = hasCrossOriginAttr(tag);
155
- const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
156
- const newTag = tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
157
- log(`New tag: ${newTag}`, options);
158
- return newTag;
159
- }
160
-
161
- log(`No SRI hash found for ${url}`, options);
162
- log(`Available paths in sriMap: ${Array.from(sriMap.keys()).join(', ')}`, options);
163
- return tag;
164
- }
165
-
166
- async function processInlineScript(tag, options) {
167
- if (tag.includes('integrity=')) {
168
- log(`Skip inline script with existing integrity attribute: ${tag}`, options);
169
- return tag;
170
- }
171
-
172
- const content = tag.match(/<script[^>]*>([\s\S]*?)<\/script>/)?.[1]?.trim();
173
- if (!content) {
174
- log(`Skip empty inline script: ${tag}`, options);
175
- return tag;
176
- }
177
-
178
- const hash = computeSri(content, options.algorithm);
179
- if (hash) {
180
- log(`Computing SRI for inline script: ${hash}`, options);
181
- const newTag = tag.replace('>', ` integrity="${hash}">`);
182
- log(`New inline script tag: ${newTag}`, options);
183
- return newTag;
140
+ if (bundleItem) {
141
+ const source = bundleItem.type === 'chunk' ? bundleItem.code : bundleItem.source;
142
+ const integrity = computeSri(source, options.algorithm);
143
+ if (integrity) {
144
+ log(`Computing SRI for local resource ${url}: ${integrity}`, options);
145
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
146
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
147
+ const newTag = tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
148
+ log(`New tag: ${newTag}`, options);
149
+ return newTag;
150
+ }
151
+ } else {
152
+ log(`No bundle item found for ${url}`, options);
153
+ log(`Available bundle keys: ${Object.keys(bundle).join(', ')}`, options);
184
154
  }
185
155
 
186
156
  return tag;
@@ -188,8 +158,8 @@ async function processInlineScript(tag, options) {
188
158
 
189
159
  function sri(userOptions = {}) {
190
160
  const options = { ...DEFAULT_OPTIONS, ...userOptions };
191
- const sriMap = new Map();
192
161
  let isBuild = false;
162
+ let base = '';
193
163
 
194
164
  return {
195
165
  name: 'vite-plugin-sri4',
@@ -199,45 +169,12 @@ function sri(userOptions = {}) {
199
169
  configResolved(config) {
200
170
  options.domain = config.server?.host || '';
201
171
  isBuild = config.command === 'build';
172
+ base = config.base || '';
202
173
  log('Plugin configured in ' + (isBuild ? 'build' : 'dev') + ' mode', options);
174
+ log(`Base URL: ${base}`, options);
203
175
  },
204
176
 
205
- async renderChunk(code, chunk) {
206
- if (!isBuild) return null;
207
-
208
- const hash = computeSri(code, options.algorithm);
209
- if (hash) {
210
- for (const path of getAllPossiblePaths(chunk.fileName)) {
211
- sriMap.set(path, hash);
212
- log(`Stored SRI for path ${path}: ${hash}`, options);
213
- }
214
- }
215
- return null;
216
- },
217
-
218
- async generateBundle(_, bundle) {
219
- if (!isBuild) return;
220
-
221
- for (const fileName in bundle) {
222
- const chunk = bundle[fileName];
223
- if (chunk.type === 'asset' && !sriMap.has(fileName)) {
224
- const hash = computeSri(chunk.source, options.algorithm);
225
- if (hash) {
226
- for (const path of getAllPossiblePaths(fileName)) {
227
- sriMap.set(path, hash);
228
- log(`Computing SRI for asset ${path}: ${hash}`, options);
229
- }
230
- }
231
- }
232
- }
233
-
234
- log('Final sriMap contents:', options);
235
- for (const [key, value] of sriMap.entries()) {
236
- log(`${key} => ${value}`, options);
237
- }
238
- },
239
-
240
- async transformIndexHtml(html) {
177
+ async transformIndexHtml(html, ctx) {
241
178
  if (!isBuild || !html) {
242
179
  log('Skipping HTML transform in dev mode or empty HTML', options);
243
180
  return html;
@@ -245,38 +182,32 @@ function sri(userOptions = {}) {
245
182
 
246
183
  try {
247
184
  log('Starting HTML transformation', options);
248
- log(`SRI Map size: ${sriMap.size}`, options);
249
-
250
- // Process script tags
251
- const scriptTags = html.match(/<script[^>]+src=["']([^"']+)["'][^>]*>/g) || [];
252
- log(`Found ${scriptTags.length} script tags`, options);
253
- for (const tag of scriptTags) {
254
- const url = tag.match(/src=["']([^"']+)["']/)[1];
185
+ const bundle = ctx.bundle || {};
186
+ log(`Bundle size: ${Object.keys(bundle).length}`, options);
187
+
188
+ // Process script tags with and without quotes
189
+ const scriptTagRegex = /<script[^>]+src=(?:["']([^"']+)["']|([^ >]+))[^>]*>/g;
190
+ let match;
191
+ while ((match = scriptTagRegex.exec(html)) !== null) {
192
+ const [tag, quotedUrl, unquotedUrl] = match;
193
+ const url = quotedUrl || unquotedUrl;
255
194
  log(`Processing script: ${url}`, options);
256
- const newTag = await processTag(tag, url, options, sriMap);
195
+ const newTag = await processTag(tag, url, options, bundle, base);
257
196
  html = html.replace(tag, newTag);
258
197
  }
259
198
 
260
- // Process inline scripts if enabled
261
- if (options.inlineScripts) {
262
- const inlineScripts = html.match(/<script[^>]*>([^<]+)<\/script>/g) || [];
263
- log(`Found ${inlineScripts.length} inline script tags`, options);
264
- for (const tag of inlineScripts) {
265
- const newTag = await processInlineScript(tag, options);
199
+ // Process link tags with and without quotes
200
+ const linkTagRegex = /<link[^>]+href=(?:["']([^"']+)["']|([^ >]+))[^>]*>/g;
201
+ while ((match = linkTagRegex.exec(html)) !== null) {
202
+ const [tag, quotedUrl, unquotedUrl] = match;
203
+ const url = quotedUrl || unquotedUrl;
204
+ if (tag.includes('stylesheet') || tag.includes('modulepreload')) {
205
+ log(`Processing link: ${url}`, options);
206
+ const newTag = await processTag(tag, url, options, bundle, base);
266
207
  html = html.replace(tag, newTag);
267
208
  }
268
209
  }
269
210
 
270
- // Process link tags
271
- const linkTags = html.match(/<link[^>]+href=["']([^"']+)["'][^>]*>/g) || [];
272
- log(`Found ${linkTags.length} link tags`, options);
273
- for (const tag of linkTags) {
274
- const url = tag.match(/href=["']([^"']+)["']/)[1];
275
- log(`Processing link: ${url}`, options);
276
- const newTag = await processTag(tag, url, options, sriMap);
277
- html = html.replace(tag, newTag);
278
- }
279
-
280
211
  return html;
281
212
  } catch (error) {
282
213
  console.error(`${LOG_PREFIX} Failed to transform HTML: ${error}`);
package/dist/index.js CHANGED
@@ -7,8 +7,7 @@ const DEFAULT_OPTIONS = {
7
7
  algorithm: 'sha384',
8
8
  bypassDomains: [],
9
9
  crossorigin: 'anonymous',
10
- debug: false,
11
- inlineScripts: false
10
+ debug: false
12
11
  };
13
12
 
14
13
  function log(message, options) {
@@ -19,9 +18,6 @@ function log(message, options) {
19
18
 
20
19
  function computeSri(content, algorithm = 'sha384') {
21
20
  try {
22
- if (typeof content === 'string') {
23
- content = Buffer.from(content, 'utf-8');
24
- }
25
21
  const hash = createHash(algorithm)
26
22
  .update(content)
27
23
  .digest('base64');
@@ -51,21 +47,14 @@ async function externalResourceIsCorsEnabled(url, options) {
51
47
  function isBypassDomain(url, bypassDomains = []) {
52
48
  if (!bypassDomains.length) return false;
53
49
  try {
54
- let parsedUrl;
55
- if (url.startsWith('//')) {
56
- parsedUrl = new URL(`http:${url}`);
57
- } else if (url.startsWith('http://') || url.startsWith('https://')) {
58
- parsedUrl = new URL(url);
59
- } else {
60
- parsedUrl = new URL(url, 'http://dummy');
61
- }
62
-
50
+ const parsedUrl = url.startsWith('//')
51
+ ? new URL(`http:${url}`)
52
+ : new URL(url, 'http://dummy');
63
53
  return bypassDomains.some(
64
54
  (domain) => parsedUrl.hostname === domain ||
65
55
  parsedUrl.hostname.endsWith(`.${domain}`)
66
56
  );
67
57
  } catch (e) {
68
- console.error(`${LOG_PREFIX} Failed to parse URL: ${url}`, e);
69
58
  return false;
70
59
  }
71
60
  }
@@ -74,26 +63,27 @@ function hasCrossOriginAttr(tag) {
74
63
  return /(?:^|\s)crossorigin(?:=["']?[^"'\s>]*["']?)?(?:\s|>|$)/i.test(tag);
75
64
  }
76
65
 
77
- function getAllPossiblePaths(url) {
78
- const paths = [
66
+ function getBundleKey(url, base = '') {
67
+ // 嘗試各種可能的路徑格式
68
+ const possiblePaths = [
79
69
  url,
80
- url.startsWith('/') ? url.slice(1) : url,
81
- url.startsWith('/static/') ? url.slice(8) : url,
82
- !url.startsWith('/static/') ? `static/${url}` : url,
83
- !url.startsWith('/static/') ? `/static/${url}` : url,
70
+ url.replace(/^\//, ''),
84
71
  url.replace(/^\/static\//, ''),
85
- url.replace(/^static\//, '')
72
+ url.replace(/^static\//, ''),
73
+ url.replace(base, ''),
74
+ url.replace(base, '').replace(/^\//, '')
86
75
  ];
87
76
 
88
- const withoutHash = url.replace(/-[a-zA-Z0-9]+\./, '.');
77
+ // 移除 hash 後的版本
78
+ const withoutHash = url.replace(/-[a-zA-Z0-9]+\.([^.]+)$/, '.$1');
89
79
  if (withoutHash !== url) {
90
- paths.push(...getAllPossiblePaths(withoutHash));
80
+ possiblePaths.push(...getBundleKey(withoutHash, base));
91
81
  }
92
82
 
93
- return [...new Set(paths)];
83
+ return [...new Set(possiblePaths)];
94
84
  }
95
85
 
96
- async function processTag(tag, url, options, sriMap) {
86
+ async function processTag(tag, url, options, bundle, base = '') {
97
87
  if (tag.includes('integrity=')) {
98
88
  log(`Skip tag with existing integrity attribute: ${tag}`, options);
99
89
  return tag;
@@ -134,51 +124,31 @@ async function processTag(tag, url, options, sriMap) {
134
124
  }
135
125
 
136
126
  // Handle local resources
137
- const possiblePaths = getAllPossiblePaths(url);
138
- let integrity = null;
127
+ const possibleKeys = getBundleKey(url, base);
128
+ let bundleItem = null;
139
129
 
140
- log(`Checking possible paths for ${url}:`, options);
141
- for (const path of possiblePaths) {
142
- log(`- Checking path: ${path}`, options);
143
- if (sriMap.has(path)) {
144
- integrity = sriMap.get(path);
145
- log(`Found integrity for path ${path}: ${integrity}`, options);
130
+ for (const key of possibleKeys) {
131
+ if (bundle[key]) {
132
+ bundleItem = bundle[key];
133
+ log(`Found bundle item for key: ${key}`, options);
146
134
  break;
147
135
  }
148
136
  }
149
137
 
150
- if (integrity) {
151
- log(`Using precomputed SRI for ${url}: ${integrity}`, options);
152
- const hasCrossOrigin = hasCrossOriginAttr(tag);
153
- const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
154
- const newTag = tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
155
- log(`New tag: ${newTag}`, options);
156
- return newTag;
157
- }
158
-
159
- log(`No SRI hash found for ${url}`, options);
160
- log(`Available paths in sriMap: ${Array.from(sriMap.keys()).join(', ')}`, options);
161
- return tag;
162
- }
163
-
164
- async function processInlineScript(tag, options) {
165
- if (tag.includes('integrity=')) {
166
- log(`Skip inline script with existing integrity attribute: ${tag}`, options);
167
- return tag;
168
- }
169
-
170
- const content = tag.match(/<script[^>]*>([\s\S]*?)<\/script>/)?.[1]?.trim();
171
- if (!content) {
172
- log(`Skip empty inline script: ${tag}`, options);
173
- return tag;
174
- }
175
-
176
- const hash = computeSri(content, options.algorithm);
177
- if (hash) {
178
- log(`Computing SRI for inline script: ${hash}`, options);
179
- const newTag = tag.replace('>', ` integrity="${hash}">`);
180
- log(`New inline script tag: ${newTag}`, options);
181
- return newTag;
138
+ if (bundleItem) {
139
+ const source = bundleItem.type === 'chunk' ? bundleItem.code : bundleItem.source;
140
+ const integrity = computeSri(source, options.algorithm);
141
+ if (integrity) {
142
+ log(`Computing SRI for local resource ${url}: ${integrity}`, options);
143
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
144
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
145
+ const newTag = tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
146
+ log(`New tag: ${newTag}`, options);
147
+ return newTag;
148
+ }
149
+ } else {
150
+ log(`No bundle item found for ${url}`, options);
151
+ log(`Available bundle keys: ${Object.keys(bundle).join(', ')}`, options);
182
152
  }
183
153
 
184
154
  return tag;
@@ -186,8 +156,8 @@ async function processInlineScript(tag, options) {
186
156
 
187
157
  function sri(userOptions = {}) {
188
158
  const options = { ...DEFAULT_OPTIONS, ...userOptions };
189
- const sriMap = new Map();
190
159
  let isBuild = false;
160
+ let base = '';
191
161
 
192
162
  return {
193
163
  name: 'vite-plugin-sri4',
@@ -197,45 +167,12 @@ function sri(userOptions = {}) {
197
167
  configResolved(config) {
198
168
  options.domain = config.server?.host || '';
199
169
  isBuild = config.command === 'build';
170
+ base = config.base || '';
200
171
  log('Plugin configured in ' + (isBuild ? 'build' : 'dev') + ' mode', options);
172
+ log(`Base URL: ${base}`, options);
201
173
  },
202
174
 
203
- async renderChunk(code, chunk) {
204
- if (!isBuild) return null;
205
-
206
- const hash = computeSri(code, options.algorithm);
207
- if (hash) {
208
- for (const path of getAllPossiblePaths(chunk.fileName)) {
209
- sriMap.set(path, hash);
210
- log(`Stored SRI for path ${path}: ${hash}`, options);
211
- }
212
- }
213
- return null;
214
- },
215
-
216
- async generateBundle(_, bundle) {
217
- if (!isBuild) return;
218
-
219
- for (const fileName in bundle) {
220
- const chunk = bundle[fileName];
221
- if (chunk.type === 'asset' && !sriMap.has(fileName)) {
222
- const hash = computeSri(chunk.source, options.algorithm);
223
- if (hash) {
224
- for (const path of getAllPossiblePaths(fileName)) {
225
- sriMap.set(path, hash);
226
- log(`Computing SRI for asset ${path}: ${hash}`, options);
227
- }
228
- }
229
- }
230
- }
231
-
232
- log('Final sriMap contents:', options);
233
- for (const [key, value] of sriMap.entries()) {
234
- log(`${key} => ${value}`, options);
235
- }
236
- },
237
-
238
- async transformIndexHtml(html) {
175
+ async transformIndexHtml(html, ctx) {
239
176
  if (!isBuild || !html) {
240
177
  log('Skipping HTML transform in dev mode or empty HTML', options);
241
178
  return html;
@@ -243,38 +180,32 @@ function sri(userOptions = {}) {
243
180
 
244
181
  try {
245
182
  log('Starting HTML transformation', options);
246
- log(`SRI Map size: ${sriMap.size}`, options);
247
-
248
- // Process script tags
249
- const scriptTags = html.match(/<script[^>]+src=["']([^"']+)["'][^>]*>/g) || [];
250
- log(`Found ${scriptTags.length} script tags`, options);
251
- for (const tag of scriptTags) {
252
- const url = tag.match(/src=["']([^"']+)["']/)[1];
183
+ const bundle = ctx.bundle || {};
184
+ log(`Bundle size: ${Object.keys(bundle).length}`, options);
185
+
186
+ // Process script tags with and without quotes
187
+ const scriptTagRegex = /<script[^>]+src=(?:["']([^"']+)["']|([^ >]+))[^>]*>/g;
188
+ let match;
189
+ while ((match = scriptTagRegex.exec(html)) !== null) {
190
+ const [tag, quotedUrl, unquotedUrl] = match;
191
+ const url = quotedUrl || unquotedUrl;
253
192
  log(`Processing script: ${url}`, options);
254
- const newTag = await processTag(tag, url, options, sriMap);
193
+ const newTag = await processTag(tag, url, options, bundle, base);
255
194
  html = html.replace(tag, newTag);
256
195
  }
257
196
 
258
- // Process inline scripts if enabled
259
- if (options.inlineScripts) {
260
- const inlineScripts = html.match(/<script[^>]*>([^<]+)<\/script>/g) || [];
261
- log(`Found ${inlineScripts.length} inline script tags`, options);
262
- for (const tag of inlineScripts) {
263
- const newTag = await processInlineScript(tag, options);
197
+ // Process link tags with and without quotes
198
+ const linkTagRegex = /<link[^>]+href=(?:["']([^"']+)["']|([^ >]+))[^>]*>/g;
199
+ while ((match = linkTagRegex.exec(html)) !== null) {
200
+ const [tag, quotedUrl, unquotedUrl] = match;
201
+ const url = quotedUrl || unquotedUrl;
202
+ if (tag.includes('stylesheet') || tag.includes('modulepreload')) {
203
+ log(`Processing link: ${url}`, options);
204
+ const newTag = await processTag(tag, url, options, bundle, base);
264
205
  html = html.replace(tag, newTag);
265
206
  }
266
207
  }
267
208
 
268
- // Process link tags
269
- const linkTags = html.match(/<link[^>]+href=["']([^"']+)["'][^>]*>/g) || [];
270
- log(`Found ${linkTags.length} link tags`, options);
271
- for (const tag of linkTags) {
272
- const url = tag.match(/href=["']([^"']+)["']/)[1];
273
- log(`Processing link: ${url}`, options);
274
- const newTag = await processTag(tag, url, options, sriMap);
275
- html = html.replace(tag, newTag);
276
- }
277
-
278
209
  return html;
279
210
  } catch (error) {
280
211
  console.error(`${LOG_PREFIX} Failed to transform HTML: ${error}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-sri4",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "A Vite plugin to generate Subresource Integrity (SRI) hashes for output files.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",