@dintero/sri-to-dist 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright 2025 Dintero
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # sri-to-dist
2
+
3
+ [![Actions Status](https://github.com/Dintero/sri-to-dist/workflows/CI/badge.svg?branch=master)](https://github.com/Dintero/sri-to-dist/actions?query=branch%3Amaster+workflow%3ACI+) [![npm latest version](https://img.shields.io/npm/v/@dintero/sri-to-dist/latest.svg)](https://www.npmjs.com/package/@dintero/sri-to-dist)
4
+
5
+ A tool to add subresource integrity (SRI) hashes to HTML files.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g @dintero/sri-to-dist
11
+ # or
12
+ npx @dintero/sri-to-dist
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```bash
18
+ sri-to-dist -i input.html -o output.html
19
+ sri-to-dist --input input.html --output output.html --base-url https://example.com
20
+ ```
21
+
22
+ ### Options
23
+
24
+ - `-i, --input <file>`: Input HTML file (required)
25
+ - `-o, --output <file>`: Output HTML file (optional, defaults to stdout)
26
+ - `-b, --base-url <url>`: Base URL for resolving relative paths (optional)
27
+ - `-n, --no-remote <url>`: Optional flag, no remote sri files allowed
28
+ - `-v, --verify <url>`: Optional flag, verify that all sri resources from input have correct sha384 hashes
29
+
30
+ ## License
31
+
32
+ MIT
33
+
34
+ ## Security
35
+
36
+ Contact us at [security@dintero.com](mailto:security@dintero.com)
37
+
38
+
39
+ ## Step 8: Build and test locally
40
+
41
+ ```bash
42
+ npm install
43
+ npm run build
44
+ npm run test
45
+ npm link # This makes your package available globally for testing
46
+ ```
47
+
48
+ Now you can run:
49
+
50
+ ```bash
51
+ sri-to-dist -i test.html
52
+ ```
53
+
54
+ ## Step 9: Publish to npm
55
+
56
+ ```bash
57
+ npm login
58
+ npm publish
59
+ ```
60
+
61
+ ## Creating a new release
62
+
63
+ 1. Enforce all commits to the master branch to be formatted according to the [Angular Commit Message Format](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format)
64
+ 2. When merged to master, it will automatically be released with [semantic-release](https://github.com/semantic-release/semantic-release)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ // This shim loads the compiled JavaScript
4
+ require("../dist/index.js");
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@dintero/sri-to-dist",
3
+ "version": "1.0.3",
4
+ "description": "HTML tool for adding subresource integrity hashes",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "sri-to-dist": "bin/sri-to-dist.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "bin"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "prepare": "npm run build",
17
+ "start": "node bin/sri-to-dist.js",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "lint": "biome lint .",
21
+ "format": "biome format . --write",
22
+ "prepublishOnly": "yarn run build"
23
+ },
24
+ "keywords": [
25
+ "subresource",
26
+ "integrity",
27
+ "sri",
28
+ "html",
29
+ "security"
30
+ ],
31
+ "homepage": "https://github.com/Dintero/sri-to-dist?tab=readme-ov-file#sri-to-dist",
32
+ "author": "Sven Nicolai Viig <sven@dintero.com> (http://dintero.com)",
33
+ "license": "MIT",
34
+ "devDependencies": {
35
+ "@biomejs/biome": "1.9.4",
36
+ "@types/node": "22.14.0",
37
+ "@types/temp": "0.9.4",
38
+ "semantic-release": "24.2.3",
39
+ "temp": "0.9.4",
40
+ "typescript": "5.8.2",
41
+ "vitest": "3.1.1"
42
+ },
43
+ "dependencies": {
44
+ "commander": "13.1.0"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/Dintero/sri-to-dist/issues"
48
+ },
49
+ "private": false,
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/Dintero/sri-to-dist.git"
56
+ }
57
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const fs = __importStar(require("node:fs"));
37
+ const path = __importStar(require("node:path"));
38
+ const commander_1 = require("commander");
39
+ const lib_1 = require("./lib");
40
+ const package_json_1 = require("../package.json");
41
+ const main = async () => {
42
+ try {
43
+ // Set up command-line parser
44
+ const program = new commander_1.Command();
45
+ program
46
+ .version(package_json_1.version)
47
+ .description("HTML processing tool to add subresource integrity hashes")
48
+ .requiredOption("-i, --input <file>", "Input HTML file")
49
+ .option("-o, --output <file>", "Optional output HTML file")
50
+ .option("-b, --base-url <url>", "Optional base URL")
51
+ .option("-n, --no-remote", "Optional flag, no remote sri files allowed")
52
+ .option("-v, --verify", "Optional flag, verify hashes in input");
53
+ program.parse(process.argv);
54
+ const options = program.opts();
55
+ // Extract values
56
+ const inputPath = options.input;
57
+ const outputPath = options.output;
58
+ const baseUrl = options.baseUrl;
59
+ const noRemote = options.noRemote || false;
60
+ const verify = options.verify || false;
61
+ // Read HTML file
62
+ const htmlContent = fs.readFileSync(inputPath, "utf-8");
63
+ const updatedHtml = await (0, lib_1.toHtmlWithSri)(htmlContent, path.dirname(inputPath), baseUrl, noRemote, verify);
64
+ (0, lib_1.handleUpdatedHtml)(process.stdout, outputPath, updatedHtml);
65
+ }
66
+ catch (error) {
67
+ console.error(`Error: ${error}`);
68
+ process.exit(1);
69
+ }
70
+ };
71
+ main().catch((error) => {
72
+ console.error(`Error: ${error}`);
73
+ process.exit(1);
74
+ });
@@ -0,0 +1,11 @@
1
+ declare const extractLinkRel: (scriptOrLinkTag: string) => string | undefined;
2
+ declare const isSriTag: (scriptOrLinkTag: string) => boolean;
3
+ declare const toHtmlWithSri: (htmlContent: string, baseDir: string, baseUrl?: string, noRemote?: boolean, verify?: boolean) => Promise<string>;
4
+ declare const getContent: (src: string, baseDir: string, baseUrl?: string, noRemote?: boolean) => Promise<Buffer>;
5
+ declare const fetchRemoteContent: (src: string) => Promise<Buffer>;
6
+ declare const readLocalContent: (src: string, baseDir: string, baseUrl: string) => Buffer;
7
+ declare const calculateSha384: (content: Buffer) => string;
8
+ declare const handleUpdatedHtml: (stdout: NodeJS.WriteStream, outputPath?: string, updatedHtml?: string) => void;
9
+ declare const toSriScriptTag: (tag: string, integrity: string) => string;
10
+ declare const ensureCrossoriginAnonymous: (tag: string) => string;
11
+ export { extractLinkRel, isSriTag, toHtmlWithSri, getContent, readLocalContent, fetchRemoteContent, calculateSha384, ensureCrossoriginAnonymous, toSriScriptTag, handleUpdatedHtml, };
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.handleUpdatedHtml = exports.toSriScriptTag = exports.ensureCrossoriginAnonymous = exports.calculateSha384 = exports.fetchRemoteContent = exports.readLocalContent = exports.getContent = exports.toHtmlWithSri = exports.isSriTag = exports.extractLinkRel = void 0;
37
+ const fs = __importStar(require("node:fs"));
38
+ const path = __importStar(require("node:path"));
39
+ const node_crypto_1 = require("node:crypto");
40
+ const extractLinkRel = (scriptOrLinkTag) => {
41
+ const re = /<link\s+[^>]*rel="([^"]*)"/;
42
+ const match = scriptOrLinkTag.match(re);
43
+ return match ? match[1] : undefined;
44
+ };
45
+ exports.extractLinkRel = extractLinkRel;
46
+ const isSriTag = (scriptOrLinkTag) => {
47
+ const rel = extractLinkRel(scriptOrLinkTag);
48
+ if (rel) {
49
+ // Check link tags
50
+ // Split by whitespace to handle multiple rel values
51
+ const relValues = rel.split(/\s+/);
52
+ // Check for critical resource types
53
+ const criticalTypes = [
54
+ "style",
55
+ "stylesheet",
56
+ "preload",
57
+ "modulepreload",
58
+ ];
59
+ // If preload, check if it's preloading a style or script
60
+ if (relValues.includes("preload")) {
61
+ // Extract as attribute
62
+ const asPattern = /as="([^"]*)"/;
63
+ const asMatch = scriptOrLinkTag.match(asPattern);
64
+ if (asMatch) {
65
+ const asValue = asMatch[1];
66
+ return asValue === "style" || asValue === "script";
67
+ }
68
+ if (relValues.includes("stylesheet")) {
69
+ // handle case where rel contains both preload and stylesheet
70
+ return true;
71
+ }
72
+ if (relValues.includes("style")) {
73
+ // handle case where rel contains both preload and style
74
+ return true;
75
+ }
76
+ // Do not calculate sri for other preload link tags
77
+ return false;
78
+ }
79
+ // Check if link tag has sri rel
80
+ for (const relValue of relValues) {
81
+ if (criticalTypes.includes(relValue)) {
82
+ return true;
83
+ }
84
+ }
85
+ // Ignore other types of link tags
86
+ return false;
87
+ }
88
+ // Check if it's a script tag
89
+ if (scriptOrLinkTag.startsWith("<script")) {
90
+ return true;
91
+ }
92
+ // Not a script tag
93
+ return false;
94
+ };
95
+ exports.isSriTag = isSriTag;
96
+ const toHtmlWithSri = async (htmlContent, baseDir, baseUrl, noRemote, verify) => {
97
+ // Find all script and link tags that should have integrity hashes
98
+ const re = /<(script|link)\s+[^>]*(?:src|href)="([^"]+)"[^>]*>/g;
99
+ let updatedHtml = htmlContent;
100
+ const matches = htmlContent.matchAll(re);
101
+ for (const [scriptOrLinkTag, _, src] of matches) {
102
+ // Skip non supported resources
103
+ if (!isSriTag(scriptOrLinkTag)) {
104
+ continue;
105
+ }
106
+ // Get content of script or link
107
+ try {
108
+ const content = await getContent(src, baseDir, baseUrl, noRemote);
109
+ // Calculate SHA-384 hash and create integrity attribute value
110
+ const hashHex = calculateSha384(content);
111
+ const integrity = `sha384-${hashHex}`;
112
+ if (verify) {
113
+ const oldHash = getIntegrityFromTag(scriptOrLinkTag);
114
+ if (!oldHash) {
115
+ throw new Error(`Missing hash for ${src}, expected ${integrity}`);
116
+ }
117
+ if (oldHash !== integrity) {
118
+ throw new Error(`Invalid hash ${oldHash} for ${src}, expected ${integrity}`);
119
+ }
120
+ }
121
+ // Create new script tag with integrity
122
+ const sriScriptTag = toSriScriptTag(scriptOrLinkTag, integrity);
123
+ // Replace in HTML
124
+ updatedHtml = updatedHtml.replace(scriptOrLinkTag, sriScriptTag);
125
+ }
126
+ catch (error) {
127
+ console.error(`Warning: Failed to process ${src}: ${error}`);
128
+ throw error;
129
+ }
130
+ }
131
+ return updatedHtml;
132
+ };
133
+ exports.toHtmlWithSri = toHtmlWithSri;
134
+ const getIntegrityFromTag = (tag) => {
135
+ const integrityPattern = /integrity="([^"]*)"/;
136
+ const match = tag.match(integrityPattern);
137
+ return match ? match[1] : undefined;
138
+ };
139
+ const getContent = async (src, baseDir, baseUrl, noRemote) => {
140
+ // Handle remote vs local content
141
+ if (src.startsWith("http://") || src.startsWith("https://")) {
142
+ // If remote_base_url is provided and src starts with it, treat it as local content
143
+ if (baseUrl && src.startsWith(baseUrl)) {
144
+ return readLocalContent(src, baseDir, baseUrl);
145
+ }
146
+ if (noRemote) {
147
+ throw new Error("Remote sri resources not allowed");
148
+ }
149
+ return fetchRemoteContent(src);
150
+ }
151
+ // For relative src, read from file
152
+ return readLocalContent(src, baseDir, baseUrl || "");
153
+ };
154
+ exports.getContent = getContent;
155
+ const fetchRemoteContent = async (src) => {
156
+ try {
157
+ // Using native fetch available in Node.js 18+
158
+ const response = await fetch(src);
159
+ if (!response.ok) {
160
+ throw new Error(`Failed to fetch: ${response.statusText}`);
161
+ }
162
+ // Check content type
163
+ const contentType = response.headers.get("content-type") || "";
164
+ // Verify content type is appropriate for scripts or stylesheets
165
+ const validTypes = [
166
+ "text/javascript",
167
+ "application/javascript",
168
+ "application/x-javascript",
169
+ "text/css",
170
+ "text/plain",
171
+ ];
172
+ if (!validTypes.some((type) => contentType.includes(type))) {
173
+ throw new Error(`Unexpected content type '${contentType}' for resource '${src}'`);
174
+ }
175
+ const arrayBuffer = await response.arrayBuffer();
176
+ return Buffer.from(arrayBuffer);
177
+ }
178
+ catch (error) {
179
+ throw new Error(`Failed to fetch remote content from '${src}': ${error}`);
180
+ }
181
+ };
182
+ exports.fetchRemoteContent = fetchRemoteContent;
183
+ const addTrailingSlashIfNotEmpty = (baseUrl) => {
184
+ if (baseUrl === "")
185
+ return baseUrl;
186
+ return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
187
+ };
188
+ const toLocalPath = (src, baseDir, baseUrl) => {
189
+ const baseWithTrailingSlash = addTrailingSlashIfNotEmpty(baseUrl);
190
+ let localPath = src;
191
+ if (src.startsWith(baseWithTrailingSlash)) {
192
+ localPath = src.substring(baseWithTrailingSlash.length);
193
+ }
194
+ else if (src.startsWith(baseUrl)) {
195
+ localPath = src.substring(baseUrl.length);
196
+ }
197
+ // Remove any slash from start at file path before reading local file
198
+ const localPathWithoutStartingSlash = localPath.startsWith("/")
199
+ ? localPath.substring(1)
200
+ : localPath;
201
+ return path.join(baseDir, localPathWithoutStartingSlash);
202
+ };
203
+ const readLocalContent = (src, baseDir, baseUrl) => {
204
+ const filePath = toLocalPath(src, baseDir, baseUrl);
205
+ try {
206
+ return fs.readFileSync(filePath);
207
+ }
208
+ catch (error) {
209
+ throw new Error(`Failed to read file at path '${filePath}': ${error}`);
210
+ }
211
+ };
212
+ exports.readLocalContent = readLocalContent;
213
+ const calculateSha384 = (content) => {
214
+ const hash = (0, node_crypto_1.createHash)("sha384").update(content).digest();
215
+ return hash.toString("base64");
216
+ };
217
+ exports.calculateSha384 = calculateSha384;
218
+ const handleUpdatedHtml = (stdout, outputPath, updatedHtml) => {
219
+ if (!updatedHtml)
220
+ return;
221
+ if (outputPath) {
222
+ fs.writeFileSync(outputPath, updatedHtml);
223
+ }
224
+ else {
225
+ stdout.write(`${updatedHtml}\n`);
226
+ }
227
+ };
228
+ exports.handleUpdatedHtml = handleUpdatedHtml;
229
+ const toSriScriptTag = (tag, integrity) => {
230
+ // First handle the integrity attribute
231
+ let newTag = tag;
232
+ if (tag.includes("integrity=")) {
233
+ // Replace existing integrity attribute
234
+ const reIntegrity = /integrity="[^"]*"/g;
235
+ newTag = newTag.replace(reIntegrity, `integrity="${integrity}"`);
236
+ }
237
+ else {
238
+ // Add integrity attribute
239
+ if (tag.endsWith("/>")) {
240
+ newTag = newTag.replace(/\/>$/, ` integrity="${integrity}"/>`);
241
+ }
242
+ else {
243
+ newTag = newTag.replace(/>$/, ` integrity="${integrity}">`);
244
+ }
245
+ }
246
+ // Ensure crossorigin attribute is set
247
+ return ensureCrossoriginAnonymous(newTag);
248
+ };
249
+ exports.toSriScriptTag = toSriScriptTag;
250
+ const ensureCrossoriginAnonymous = (tag) => {
251
+ // Replace if exists
252
+ if (tag.includes("crossorigin=")) {
253
+ const reCrossorigin = /crossorigin="[^"]*"/g;
254
+ return tag.replace(reCrossorigin, 'crossorigin="anonymous"');
255
+ }
256
+ // Add crossorigin="anonymous" attribute if missing from tag
257
+ if (tag.endsWith("/>")) {
258
+ return tag.replace(/\/>$/, ' crossorigin="anonymous"/>');
259
+ }
260
+ return tag.replace(/>$/, ' crossorigin="anonymous">');
261
+ };
262
+ exports.ensureCrossoriginAnonymous = ensureCrossoriginAnonymous;
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@dintero/sri-to-dist",
3
+ "version": "1.0.3",
4
+ "description": "HTML tool for adding subresource integrity hashes",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "sri-to-dist": "bin/sri-to-dist.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "bin"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "prepare": "npm run build",
17
+ "start": "node bin/sri-to-dist.js",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "lint": "biome lint .",
21
+ "format": "biome format . --write",
22
+ "prepublishOnly": "yarn run build"
23
+ },
24
+ "keywords": [
25
+ "subresource",
26
+ "integrity",
27
+ "sri",
28
+ "html",
29
+ "security"
30
+ ],
31
+ "homepage": "https://github.com/Dintero/sri-to-dist?tab=readme-ov-file#sri-to-dist",
32
+ "author": "Sven Nicolai Viig <sven@dintero.com> (http://dintero.com)",
33
+ "license": "MIT",
34
+ "devDependencies": {
35
+ "@biomejs/biome": "1.9.4",
36
+ "@types/node": "22.14.0",
37
+ "@types/temp": "0.9.4",
38
+ "semantic-release": "24.2.3",
39
+ "temp": "0.9.4",
40
+ "typescript": "5.8.2",
41
+ "vitest": "3.1.1"
42
+ },
43
+ "dependencies": {
44
+ "commander": "13.1.0"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/Dintero/sri-to-dist/issues"
48
+ },
49
+ "private": false,
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/Dintero/sri-to-dist.git"
56
+ }
57
+ }