vite-plugin-sri4 1.5.0 → 1.7.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 (3) hide show
  1. package/dist/index.cjs +140 -91
  2. package/dist/index.js +140 -91
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -3,6 +3,8 @@
3
3
  var node_crypto = require('node:crypto');
4
4
  var fetch = require('cross-fetch');
5
5
 
6
+ const LOG_PREFIX = '[vite-plugin-sri4]';
7
+
6
8
  const DEFAULT_OPTIONS = {
7
9
  algorithm: 'sha384',
8
10
  bypassDomains: [],
@@ -10,12 +12,23 @@ const DEFAULT_OPTIONS = {
10
12
  debug: false
11
13
  };
12
14
 
15
+ /**
16
+ * Log debug messages if debug mode is enabled
17
+ * @param {string} message - Message to log
18
+ * @param {Object} options - Plugin options
19
+ */
13
20
  function log(message, options) {
14
21
  if (options.debug) {
15
- console.log(`[vite-plugin-sri4] ${message}`);
22
+ console.log(`${LOG_PREFIX} ${message}`);
16
23
  }
17
24
  }
18
25
 
26
+ /**
27
+ * Compute SRI hash for given content
28
+ * @param {string|Buffer} content - Content to hash
29
+ * @param {string} algorithm - Hash algorithm to use
30
+ * @returns {string|null} SRI hash string or null if failed
31
+ */
19
32
  function computeSri(content, algorithm = 'sha384') {
20
33
  try {
21
34
  const hash = node_crypto.createHash(algorithm)
@@ -23,11 +36,17 @@ function computeSri(content, algorithm = 'sha384') {
23
36
  .digest('base64');
24
37
  return `${algorithm}-${hash}`;
25
38
  } catch (error) {
26
- console.error(`[vite-plugin-sri4] Failed to compute SRI hash: ${error}`);
39
+ console.error(`${LOG_PREFIX} Failed to compute SRI hash: ${error}`);
27
40
  return null;
28
41
  }
29
42
  }
30
43
 
44
+ /**
45
+ * Check if external resource has CORS enabled
46
+ * @param {string} url - URL to check
47
+ * @param {Object} options - Plugin options
48
+ * @returns {Promise<boolean>} Whether CORS is enabled
49
+ */
31
50
  async function externalResourceIsCorsEnabled(url, options) {
32
51
  try {
33
52
  const response = await fetch(url, {
@@ -45,38 +64,18 @@ async function externalResourceIsCorsEnabled(url, options) {
45
64
  }
46
65
  }
47
66
 
48
- async function replaceAsync(str, regex, asyncFn) {
49
- const promises = [];
50
- const matches = [];
51
-
52
- str.replace(regex, (...args) => {
53
- matches.push(args);
54
- promises.push(asyncFn(...args));
55
- return '';
56
- });
57
-
58
- const results = await Promise.all(promises);
59
-
60
- let lastIndex = 0;
61
- let result = '';
62
-
63
- for (let i = 0; i < matches.length; i++) {
64
- const match = matches[i][0];
65
- const index = str.indexOf(match, lastIndex);
66
- result += str.slice(lastIndex, index) + results[i];
67
- lastIndex = index + match.length;
68
- }
69
-
70
- result += str.slice(lastIndex);
71
- return result;
72
- }
73
-
67
+ /**
68
+ * Check if URL belongs to bypass domains
69
+ * @param {string} url - URL to check
70
+ * @param {string[]} bypassDomains - List of domains to bypass
71
+ * @returns {boolean} Whether URL belongs to bypass domains
72
+ */
74
73
  function isBypassDomain(url, bypassDomains = []) {
75
74
  if (!bypassDomains.length) return false;
76
75
  try {
77
76
  const parsedUrl = url.startsWith('//')
78
- ? new URL(url, 'http://dummy')
79
- : new URL(url);
77
+ ? new URL(`http:${url}`)
78
+ : new URL(url, 'http://dummy');
80
79
  return bypassDomains.some(
81
80
  (domain) => parsedUrl.hostname === domain ||
82
81
  parsedUrl.hostname.endsWith(`.${domain}`)
@@ -86,97 +85,147 @@ function isBypassDomain(url, bypassDomains = []) {
86
85
  }
87
86
  }
88
87
 
88
+ /**
89
+ * Check if tag already has crossorigin attribute
90
+ * @param {string} tag - HTML tag to check
91
+ * @returns {boolean} Whether tag has crossorigin attribute
92
+ */
89
93
  function hasCrossOriginAttr(tag) {
90
94
  return /(?:^|\s)crossorigin(?:=["']?[^"'\s>]*["']?)?(?:\s|>|$)/i.test(tag);
91
95
  }
92
96
 
97
+ /**
98
+ * Process individual HTML tags and add SRI attributes
99
+ * @param {string} tag - HTML tag to process
100
+ * @param {string} url - Resource URL
101
+ * @param {Object} options - Plugin options
102
+ * @param {Map} sriMap - Map of file names to SRI hashes
103
+ * @returns {Promise<string>} Processed HTML tag
104
+ */
105
+ async function processTag(tag, url, options, sriMap) {
106
+ if (tag.includes('integrity=')) {
107
+ log(`Skip tag with existing integrity attribute: ${tag}`, options);
108
+ return tag;
109
+ }
110
+
111
+ // Handle external resources
112
+ if (/^(https?:)?\/\//i.test(url)) {
113
+ if (isBypassDomain(url, options.bypassDomains)) {
114
+ log(`Skip SRI for bypass domain: ${url}`, options);
115
+ return tag;
116
+ }
117
+
118
+ const corsOk = await externalResourceIsCorsEnabled(url, options);
119
+ if (!corsOk) {
120
+ log(`External resource ${url} does not support CORS`, options);
121
+ return tag;
122
+ }
123
+
124
+ try {
125
+ const response = await fetch(url);
126
+ const content = await response.arrayBuffer();
127
+ const hash = computeSri(Buffer.from(content), options.algorithm);
128
+ if (hash) {
129
+ log(`Computing SRI for external resource ${url}: ${hash}`, options);
130
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
131
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
132
+ return tag.replace(/>$/, ` integrity="${hash}"${crossOriginAttr}>`);
133
+ }
134
+ } catch (error) {
135
+ log(`Failed to process external resource ${url}: ${error}`, options);
136
+ }
137
+ return tag;
138
+ }
139
+
140
+ // Handle local resources
141
+ const fileName = url.startsWith('/') ? url.slice(1) : url;
142
+ const integrity = sriMap.get(fileName);
143
+ if (integrity) {
144
+ log(`Using precomputed SRI for ${fileName}: ${integrity}`, options);
145
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
146
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
147
+ return tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
148
+ }
149
+
150
+ log(`No SRI hash found for ${fileName}`, options);
151
+ return tag;
152
+ }
153
+
154
+ /**
155
+ * Vite plugin for adding Subresource Integrity (SRI) hashes to assets
156
+ * @param {Object} userOptions - Plugin options
157
+ * @returns {import('vite').Plugin} Vite plugin object
158
+ */
93
159
  function sri(userOptions = {}) {
94
160
  const options = { ...DEFAULT_OPTIONS, ...userOptions };
95
161
  const sriMap = new Map();
162
+ let isBuild = false;
96
163
 
97
164
  return {
98
165
  name: 'vite-plugin-sri4',
99
- enforce: 'post',
100
166
  apply: 'build',
167
+ enforce: 'post',
101
168
 
102
169
  configResolved(config) {
103
170
  options.domain = config.server?.host || '';
171
+ isBuild = config.command === 'build';
172
+ log('Plugin configured in ' + (isBuild ? 'build' : 'dev') + ' mode', options);
173
+ },
174
+
175
+ async renderChunk(code, chunk) {
176
+ if (!isBuild) return null;
177
+
178
+ const hash = computeSri(code, options.algorithm);
179
+ if (hash) {
180
+ sriMap.set(chunk.fileName, hash);
181
+ log(`Computing SRI for chunk ${chunk.fileName}: ${hash}`, options);
182
+ }
183
+ return null;
104
184
  },
105
185
 
106
186
  async generateBundle(_, bundle) {
187
+ if (!isBuild) return;
188
+
107
189
  for (const fileName in bundle) {
108
190
  const chunk = bundle[fileName];
109
- if (chunk.type === 'chunk' || chunk.type === 'asset') {
110
- const content = chunk.code || chunk.source;
111
- if (content) {
112
- const hash = computeSri(content, options.algorithm);
113
- if (hash) {
114
- sriMap.set(fileName, hash);
115
- log(`Computed SRI for ${fileName}: ${hash}`, options);
116
- }
191
+ if (chunk.type === 'asset' && !sriMap.has(fileName)) {
192
+ const hash = computeSri(chunk.source, options.algorithm);
193
+ if (hash) {
194
+ sriMap.set(fileName, hash);
195
+ log(`Computing SRI for asset ${fileName}: ${hash}`, options);
117
196
  }
118
197
  }
119
198
  }
120
199
  },
121
200
 
122
201
  async transformIndexHtml(html) {
123
- const hasIntegrity = (tag) => /integrity=/i.test(tag);
124
- const isExternalUrl = (url) => /^(https?:)?\/\//i.test(url);
125
-
126
- const processTag = async (match, tag, src, moduleSrc) => {
127
- const actualSrc = src || moduleSrc;
128
-
129
- if (hasIntegrity(tag)) {
130
- return tag;
131
- }
202
+ if (!isBuild || !html) {
203
+ log('Skipping HTML transform in dev mode or empty HTML', options);
204
+ return html;
205
+ }
132
206
 
133
- if (isExternalUrl(actualSrc) &&
134
- isBypassDomain(actualSrc, options.bypassDomains)) {
135
- log(`Skipping SRI injection for bypass domain: ${actualSrc}`, options);
136
- return tag;
207
+ try {
208
+ // Process script tags
209
+ const scriptTags = html.match(/<script[^>]+src=["']([^"']+)["'][^>]*>/g) || [];
210
+ for (const tag of scriptTags) {
211
+ const url = tag.match(/src=["']([^"']+)["']/)[1];
212
+ const newTag = await processTag(tag, url, options, sriMap);
213
+ html = html.replace(tag, newTag);
137
214
  }
138
215
 
139
- if (isExternalUrl(actualSrc)) {
140
- const corsOk = await externalResourceIsCorsEnabled(actualSrc, options);
141
- if (!corsOk) {
142
- log(`External resource ${actualSrc} does not support CORS`, options);
143
- return tag;
144
- }
145
- }
146
-
147
- const fileName = actualSrc.startsWith('/') ? actualSrc.slice(1) : actualSrc;
148
- const integrity = sriMap.get(fileName);
149
-
150
- if (integrity) {
151
- const hasCrossOrigin = hasCrossOriginAttr(tag);
152
- if (!hasCrossOrigin) {
153
- return tag.replace(
154
- />$/,
155
- ` integrity="${integrity}" crossorigin="${options.crossorigin}">`
156
- );
157
- }
158
- return tag.replace(
159
- />$/,
160
- ` integrity="${integrity}">`
161
- );
216
+ // Process link tags
217
+ const linkTags = html.match(/<link[^>]+href=["']([^"']+)["'][^>]*>/g) || [];
218
+ for (const tag of linkTags) {
219
+ const url = tag.match(/href=["']([^"']+)["']/)[1];
220
+ const newTag = await processTag(tag, url, options, sriMap);
221
+ html = html.replace(tag, newTag);
162
222
  }
163
223
 
164
- return tag;
165
- };
166
-
167
- html = await replaceAsync(
168
- html,
169
- /(<script[^>]+(?:src="([^"]+)"[^>]*|type="module"[^>]*src="([^"]+)"[^>]*)>)/g,
170
- processTag
171
- );
172
-
173
- html = await replaceAsync(
174
- html,
175
- /(<link[^>]+href="([^"]+)"[^>]*>)/g,
176
- processTag
177
- );
178
-
179
- return html;
224
+ return html;
225
+ } catch (error) {
226
+ console.error(`${LOG_PREFIX} Failed to transform HTML: ${error}`);
227
+ return html;
228
+ }
180
229
  }
181
230
  };
182
231
  }
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import fetch from 'cross-fetch';
3
3
 
4
+ const LOG_PREFIX = '[vite-plugin-sri4]';
5
+
4
6
  const DEFAULT_OPTIONS = {
5
7
  algorithm: 'sha384',
6
8
  bypassDomains: [],
@@ -8,12 +10,23 @@ const DEFAULT_OPTIONS = {
8
10
  debug: false
9
11
  };
10
12
 
13
+ /**
14
+ * Log debug messages if debug mode is enabled
15
+ * @param {string} message - Message to log
16
+ * @param {Object} options - Plugin options
17
+ */
11
18
  function log(message, options) {
12
19
  if (options.debug) {
13
- console.log(`[vite-plugin-sri4] ${message}`);
20
+ console.log(`${LOG_PREFIX} ${message}`);
14
21
  }
15
22
  }
16
23
 
24
+ /**
25
+ * Compute SRI hash for given content
26
+ * @param {string|Buffer} content - Content to hash
27
+ * @param {string} algorithm - Hash algorithm to use
28
+ * @returns {string|null} SRI hash string or null if failed
29
+ */
17
30
  function computeSri(content, algorithm = 'sha384') {
18
31
  try {
19
32
  const hash = createHash(algorithm)
@@ -21,11 +34,17 @@ function computeSri(content, algorithm = 'sha384') {
21
34
  .digest('base64');
22
35
  return `${algorithm}-${hash}`;
23
36
  } catch (error) {
24
- console.error(`[vite-plugin-sri4] Failed to compute SRI hash: ${error}`);
37
+ console.error(`${LOG_PREFIX} Failed to compute SRI hash: ${error}`);
25
38
  return null;
26
39
  }
27
40
  }
28
41
 
42
+ /**
43
+ * Check if external resource has CORS enabled
44
+ * @param {string} url - URL to check
45
+ * @param {Object} options - Plugin options
46
+ * @returns {Promise<boolean>} Whether CORS is enabled
47
+ */
29
48
  async function externalResourceIsCorsEnabled(url, options) {
30
49
  try {
31
50
  const response = await fetch(url, {
@@ -43,38 +62,18 @@ async function externalResourceIsCorsEnabled(url, options) {
43
62
  }
44
63
  }
45
64
 
46
- async function replaceAsync(str, regex, asyncFn) {
47
- const promises = [];
48
- const matches = [];
49
-
50
- str.replace(regex, (...args) => {
51
- matches.push(args);
52
- promises.push(asyncFn(...args));
53
- return '';
54
- });
55
-
56
- const results = await Promise.all(promises);
57
-
58
- let lastIndex = 0;
59
- let result = '';
60
-
61
- for (let i = 0; i < matches.length; i++) {
62
- const match = matches[i][0];
63
- const index = str.indexOf(match, lastIndex);
64
- result += str.slice(lastIndex, index) + results[i];
65
- lastIndex = index + match.length;
66
- }
67
-
68
- result += str.slice(lastIndex);
69
- return result;
70
- }
71
-
65
+ /**
66
+ * Check if URL belongs to bypass domains
67
+ * @param {string} url - URL to check
68
+ * @param {string[]} bypassDomains - List of domains to bypass
69
+ * @returns {boolean} Whether URL belongs to bypass domains
70
+ */
72
71
  function isBypassDomain(url, bypassDomains = []) {
73
72
  if (!bypassDomains.length) return false;
74
73
  try {
75
74
  const parsedUrl = url.startsWith('//')
76
- ? new URL(url, 'http://dummy')
77
- : new URL(url);
75
+ ? new URL(`http:${url}`)
76
+ : new URL(url, 'http://dummy');
78
77
  return bypassDomains.some(
79
78
  (domain) => parsedUrl.hostname === domain ||
80
79
  parsedUrl.hostname.endsWith(`.${domain}`)
@@ -84,97 +83,147 @@ function isBypassDomain(url, bypassDomains = []) {
84
83
  }
85
84
  }
86
85
 
86
+ /**
87
+ * Check if tag already has crossorigin attribute
88
+ * @param {string} tag - HTML tag to check
89
+ * @returns {boolean} Whether tag has crossorigin attribute
90
+ */
87
91
  function hasCrossOriginAttr(tag) {
88
92
  return /(?:^|\s)crossorigin(?:=["']?[^"'\s>]*["']?)?(?:\s|>|$)/i.test(tag);
89
93
  }
90
94
 
95
+ /**
96
+ * Process individual HTML tags and add SRI attributes
97
+ * @param {string} tag - HTML tag to process
98
+ * @param {string} url - Resource URL
99
+ * @param {Object} options - Plugin options
100
+ * @param {Map} sriMap - Map of file names to SRI hashes
101
+ * @returns {Promise<string>} Processed HTML tag
102
+ */
103
+ async function processTag(tag, url, options, sriMap) {
104
+ if (tag.includes('integrity=')) {
105
+ log(`Skip tag with existing integrity attribute: ${tag}`, options);
106
+ return tag;
107
+ }
108
+
109
+ // Handle external resources
110
+ if (/^(https?:)?\/\//i.test(url)) {
111
+ if (isBypassDomain(url, options.bypassDomains)) {
112
+ log(`Skip SRI for bypass domain: ${url}`, options);
113
+ return tag;
114
+ }
115
+
116
+ const corsOk = await externalResourceIsCorsEnabled(url, options);
117
+ if (!corsOk) {
118
+ log(`External resource ${url} does not support CORS`, options);
119
+ return tag;
120
+ }
121
+
122
+ try {
123
+ const response = await fetch(url);
124
+ const content = await response.arrayBuffer();
125
+ const hash = computeSri(Buffer.from(content), options.algorithm);
126
+ if (hash) {
127
+ log(`Computing SRI for external resource ${url}: ${hash}`, options);
128
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
129
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
130
+ return tag.replace(/>$/, ` integrity="${hash}"${crossOriginAttr}>`);
131
+ }
132
+ } catch (error) {
133
+ log(`Failed to process external resource ${url}: ${error}`, options);
134
+ }
135
+ return tag;
136
+ }
137
+
138
+ // Handle local resources
139
+ const fileName = url.startsWith('/') ? url.slice(1) : url;
140
+ const integrity = sriMap.get(fileName);
141
+ if (integrity) {
142
+ log(`Using precomputed SRI for ${fileName}: ${integrity}`, options);
143
+ const hasCrossOrigin = hasCrossOriginAttr(tag);
144
+ const crossOriginAttr = hasCrossOrigin ? '' : ` crossorigin="${options.crossorigin}"`;
145
+ return tag.replace(/>$/, ` integrity="${integrity}"${crossOriginAttr}>`);
146
+ }
147
+
148
+ log(`No SRI hash found for ${fileName}`, options);
149
+ return tag;
150
+ }
151
+
152
+ /**
153
+ * Vite plugin for adding Subresource Integrity (SRI) hashes to assets
154
+ * @param {Object} userOptions - Plugin options
155
+ * @returns {import('vite').Plugin} Vite plugin object
156
+ */
91
157
  function sri(userOptions = {}) {
92
158
  const options = { ...DEFAULT_OPTIONS, ...userOptions };
93
159
  const sriMap = new Map();
160
+ let isBuild = false;
94
161
 
95
162
  return {
96
163
  name: 'vite-plugin-sri4',
97
- enforce: 'post',
98
164
  apply: 'build',
165
+ enforce: 'post',
99
166
 
100
167
  configResolved(config) {
101
168
  options.domain = config.server?.host || '';
169
+ isBuild = config.command === 'build';
170
+ log('Plugin configured in ' + (isBuild ? 'build' : 'dev') + ' mode', options);
171
+ },
172
+
173
+ async renderChunk(code, chunk) {
174
+ if (!isBuild) return null;
175
+
176
+ const hash = computeSri(code, options.algorithm);
177
+ if (hash) {
178
+ sriMap.set(chunk.fileName, hash);
179
+ log(`Computing SRI for chunk ${chunk.fileName}: ${hash}`, options);
180
+ }
181
+ return null;
102
182
  },
103
183
 
104
184
  async generateBundle(_, bundle) {
185
+ if (!isBuild) return;
186
+
105
187
  for (const fileName in bundle) {
106
188
  const chunk = bundle[fileName];
107
- if (chunk.type === 'chunk' || chunk.type === 'asset') {
108
- const content = chunk.code || chunk.source;
109
- if (content) {
110
- const hash = computeSri(content, options.algorithm);
111
- if (hash) {
112
- sriMap.set(fileName, hash);
113
- log(`Computed SRI for ${fileName}: ${hash}`, options);
114
- }
189
+ if (chunk.type === 'asset' && !sriMap.has(fileName)) {
190
+ const hash = computeSri(chunk.source, options.algorithm);
191
+ if (hash) {
192
+ sriMap.set(fileName, hash);
193
+ log(`Computing SRI for asset ${fileName}: ${hash}`, options);
115
194
  }
116
195
  }
117
196
  }
118
197
  },
119
198
 
120
199
  async transformIndexHtml(html) {
121
- const hasIntegrity = (tag) => /integrity=/i.test(tag);
122
- const isExternalUrl = (url) => /^(https?:)?\/\//i.test(url);
123
-
124
- const processTag = async (match, tag, src, moduleSrc) => {
125
- const actualSrc = src || moduleSrc;
126
-
127
- if (hasIntegrity(tag)) {
128
- return tag;
129
- }
200
+ if (!isBuild || !html) {
201
+ log('Skipping HTML transform in dev mode or empty HTML', options);
202
+ return html;
203
+ }
130
204
 
131
- if (isExternalUrl(actualSrc) &&
132
- isBypassDomain(actualSrc, options.bypassDomains)) {
133
- log(`Skipping SRI injection for bypass domain: ${actualSrc}`, options);
134
- return tag;
205
+ try {
206
+ // Process script tags
207
+ const scriptTags = html.match(/<script[^>]+src=["']([^"']+)["'][^>]*>/g) || [];
208
+ for (const tag of scriptTags) {
209
+ const url = tag.match(/src=["']([^"']+)["']/)[1];
210
+ const newTag = await processTag(tag, url, options, sriMap);
211
+ html = html.replace(tag, newTag);
135
212
  }
136
213
 
137
- if (isExternalUrl(actualSrc)) {
138
- const corsOk = await externalResourceIsCorsEnabled(actualSrc, options);
139
- if (!corsOk) {
140
- log(`External resource ${actualSrc} does not support CORS`, options);
141
- return tag;
142
- }
143
- }
144
-
145
- const fileName = actualSrc.startsWith('/') ? actualSrc.slice(1) : actualSrc;
146
- const integrity = sriMap.get(fileName);
147
-
148
- if (integrity) {
149
- const hasCrossOrigin = hasCrossOriginAttr(tag);
150
- if (!hasCrossOrigin) {
151
- return tag.replace(
152
- />$/,
153
- ` integrity="${integrity}" crossorigin="${options.crossorigin}">`
154
- );
155
- }
156
- return tag.replace(
157
- />$/,
158
- ` integrity="${integrity}">`
159
- );
214
+ // Process link tags
215
+ const linkTags = html.match(/<link[^>]+href=["']([^"']+)["'][^>]*>/g) || [];
216
+ for (const tag of linkTags) {
217
+ const url = tag.match(/href=["']([^"']+)["']/)[1];
218
+ const newTag = await processTag(tag, url, options, sriMap);
219
+ html = html.replace(tag, newTag);
160
220
  }
161
221
 
162
- return tag;
163
- };
164
-
165
- html = await replaceAsync(
166
- html,
167
- /(<script[^>]+(?:src="([^"]+)"[^>]*|type="module"[^>]*src="([^"]+)"[^>]*)>)/g,
168
- processTag
169
- );
170
-
171
- html = await replaceAsync(
172
- html,
173
- /(<link[^>]+href="([^"]+)"[^>]*>)/g,
174
- processTag
175
- );
176
-
177
- return html;
222
+ return html;
223
+ } catch (error) {
224
+ console.error(`${LOG_PREFIX} Failed to transform HTML: ${error}`);
225
+ return html;
226
+ }
178
227
  }
179
228
  };
180
229
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-sri4",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
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",