@lateos/npm-scan 0.14.0 → 0.15.1
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/README.md +13 -4
- package/backend/detectors/atk-002-obfusc.js +53 -5
- package/backend/license.js +4 -0
- package/backend/lockfile.js +3 -3
- package/backend/policy.js +75 -10
- package/package.json +4 -4
- package/test/fixtures/lockfiles/npm-lock.json +69 -0
- package/test/fixtures/lockfiles/yarn.lock +8 -7
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@lateos/npm-scan)
|
|
4
4
|
[](LICENSING.md)
|
|
5
5
|
[](package.json)
|
|
6
|
-
[](https://github.com/lateos-ai/npm-scan)
|
|
7
|
+
[](https://github.com/lateos-ai/npm-scan)
|
|
8
8
|
[](https://hub.docker.com/r/lateos/npm-scan)
|
|
9
9
|
[](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
|
|
10
10
|
|
|
@@ -71,6 +71,7 @@ Attackers have moved past simple typosquatting. They now ship **obfuscated prein
|
|
|
71
71
|
| 🛡️ | **Zero telemetry** | No data leaves your machine. No cloud. No callbacks. |
|
|
72
72
|
| 💾 | **Local scan history** | SQLite-backed persistence, zero external dependencies |
|
|
73
73
|
| 🪝 | **Pre-commit hook** | Block threats before commit — one-liner install, scans `package-lock.json` changes |
|
|
74
|
+
| 📎 | **Yarn + pnpm support** | `scan-lockfile` parses `yarn.lock` and `pnpm-lock.yaml` alongside `package-lock.json` |
|
|
74
75
|
|
|
75
76
|
---
|
|
76
77
|
|
|
@@ -190,12 +191,16 @@ npm-scan scan --file path/to/malicious-package.tgz
|
|
|
190
191
|
### Scan a lockfile
|
|
191
192
|
|
|
192
193
|
```bash
|
|
193
|
-
# Scan the current project's dependencies
|
|
194
|
+
# Scan the current project's dependencies (auto-detects npm/yarn/pnpm)
|
|
194
195
|
npm-scan scan-lockfile
|
|
195
196
|
|
|
196
197
|
# Scan a specific lockfile
|
|
197
198
|
npm-scan scan-lockfile -f ./path/to/package-lock.json
|
|
198
199
|
|
|
200
|
+
# Scan yarn.lock or pnpm-lock.yaml
|
|
201
|
+
npm-scan scan-lockfile -f ./yarn.lock --yarn
|
|
202
|
+
npm-scan scan-lockfile -f ./pnpm-lock.yaml --pnpm
|
|
203
|
+
|
|
199
204
|
# Fail CI/CD on high or critical findings (exit code 1)
|
|
200
205
|
npm-scan scan-lockfile --fail-on high
|
|
201
206
|
|
|
@@ -211,7 +216,7 @@ npm-scan scan-lockfile --watch
|
|
|
211
216
|
# Watch with faster debounce (500ms) — great for dev workflows
|
|
212
217
|
npm-scan scan-lockfile --watch --debounce 500
|
|
213
218
|
|
|
214
|
-
# Watch monorepo (all
|
|
219
|
+
# Watch monorepo (all lockfiles — npm/yarn/pnpm — in workspace)
|
|
215
220
|
npm-scan scan-lockfile --watch --monorepo
|
|
216
221
|
|
|
217
222
|
# Output only risk score (0-10) for dashboards/thresholds
|
|
@@ -686,8 +691,12 @@ node --test test/detectors-corpus.test.js
|
|
|
686
691
|
- `test/detectors-corpus.test.js` — 33 malicious + 50 clean tarball integration (offline)
|
|
687
692
|
- `test/fetch.test.js` — tarball extraction, temp directory cleanup
|
|
688
693
|
- `test/policy-edge-cases.test.js` — edge cases in suppress, override, load validation
|
|
694
|
+
- `test/policy.test.js` — policy YAML/JSON load, apply, suppress, severity override tests
|
|
689
695
|
- `test/report-snapshots.test.js` — HTML/text/CRA/PDF format assertions
|
|
696
|
+
- `test/report.test.js` — SARIF, CSV, STIG, risk score format tests
|
|
697
|
+
- `test/lockfile.test.js` — npm/yarn/pnpm parser, auto-detect, ATK-007/011 lockfile tests
|
|
690
698
|
- `test/cli.test.js` — commander integration tests (help, version, scan, report, error handling)
|
|
699
|
+
- `test/cli-lockfile.test.js` — scan-lockfile CLI options, yarn/pnpm/monorepo/watch tests
|
|
691
700
|
|
|
692
701
|
### Need help?
|
|
693
702
|
|
|
@@ -1,3 +1,45 @@
|
|
|
1
|
+
const DIST_BUILD_PATTERNS = [/\/dist\//, /\/build\//, /\/bundle/, /\/min\//, /\.min\.js$/, /\.bundled?\.js$/];
|
|
2
|
+
const TEST_FIXTURE_PATTERNS = [/\/test\//, /\/tests\//, /\/__tests__\//, /\/spec\//, /\.test\.js$/, /\.spec\.js$/, /fixtures?/];
|
|
3
|
+
const LIFECYCLE_HOOK_PATTERNS = [/postinstall/, /preinstall/, /['"]install['"]/, /['"]prepare['"]/];
|
|
4
|
+
const KNOWN_SAFE_DOMAINS = [
|
|
5
|
+
'registry.npmjs.org', 'cdn.jsdelivr.net', 'unpkg.com', 'cdn.skypack.dev',
|
|
6
|
+
'esm.sh', 'deno.land', 'raw.githubusercontent.com', 'github.com',
|
|
7
|
+
'npmjs.com', 'nodejs.org', 'v8.dev', 'typescriptlang.org'
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
function extractUrlDomain(code) {
|
|
11
|
+
const urlMatch = code.match(/https?:\/\/([^/'"\s]+)/);
|
|
12
|
+
return urlMatch ? urlMatch[1] : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isDistOrBuild(filePath) {
|
|
16
|
+
return DIST_BUILD_PATTERNS.some(p => p.test(filePath));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isTestOrFixture(filePath) {
|
|
20
|
+
return TEST_FIXTURE_PATTERNS.some(p => p.test(filePath));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isLifecycleHook(code) {
|
|
24
|
+
return LIFECYCLE_HOOK_PATTERNS.some(p => p.test(code));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isKnownSafeDomain(domain) {
|
|
28
|
+
if (!domain) return false;
|
|
29
|
+
return KNOWN_SAFE_DOMAINS.some(safe => domain === safe || domain.endsWith('.' + safe));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createContext(filePath, code) {
|
|
33
|
+
return {
|
|
34
|
+
file_path: filePath,
|
|
35
|
+
is_dist_build: isDistOrBuild(filePath),
|
|
36
|
+
is_test_fixture: isTestOrFixture(filePath),
|
|
37
|
+
is_lifecycle_hook: isLifecycleHook(code),
|
|
38
|
+
url_domain: extractUrlDomain(code),
|
|
39
|
+
is_known_safe_domain: isKnownSafeDomain(extractUrlDomain(code)),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
1
43
|
export async function scan(pkgJson, files = []) {
|
|
2
44
|
const findings = [];
|
|
3
45
|
const pkgName = pkgJson?.name || '';
|
|
@@ -5,6 +47,7 @@ export async function scan(pkgJson, files = []) {
|
|
|
5
47
|
|
|
6
48
|
for (const f of files) {
|
|
7
49
|
const code = f.content;
|
|
50
|
+
const ctx = createContext(f.path, code);
|
|
8
51
|
|
|
9
52
|
const hasEval = /eval\(|new Function\(|\bFunction\('/.test(code);
|
|
10
53
|
|
|
@@ -19,7 +62,8 @@ export async function scan(pkgJson, files = []) {
|
|
|
19
62
|
severity: 'medium',
|
|
20
63
|
title: 'Obfuscated payload',
|
|
21
64
|
description: hexDecode ? 'Eval with hex-decoded payload' : 'Eval with base64-decoded payload',
|
|
22
|
-
evidence: 'eval + decode pattern detected'
|
|
65
|
+
evidence: 'eval + decode pattern detected',
|
|
66
|
+
context: ctx,
|
|
23
67
|
});
|
|
24
68
|
return findings;
|
|
25
69
|
}
|
|
@@ -32,7 +76,8 @@ export async function scan(pkgJson, files = []) {
|
|
|
32
76
|
severity: 'high',
|
|
33
77
|
title: 'Obfuscated payload',
|
|
34
78
|
description: 'Double-encoded nested payload',
|
|
35
|
-
evidence: 'nested encode/decode detected'
|
|
79
|
+
evidence: 'nested encode/decode detected',
|
|
80
|
+
context: { ...ctx, is_multi_layer: true },
|
|
36
81
|
});
|
|
37
82
|
return findings;
|
|
38
83
|
}
|
|
@@ -48,7 +93,8 @@ export async function scan(pkgJson, files = []) {
|
|
|
48
93
|
severity: 'medium',
|
|
49
94
|
title: 'Obfuscated payload',
|
|
50
95
|
description: 'Decoded string containing URL/fetch call',
|
|
51
|
-
evidence: 'obfuscation with network call'
|
|
96
|
+
evidence: 'obfuscation with network call',
|
|
97
|
+
context: ctx,
|
|
52
98
|
});
|
|
53
99
|
return findings;
|
|
54
100
|
}
|
|
@@ -60,7 +106,8 @@ export async function scan(pkgJson, files = []) {
|
|
|
60
106
|
severity: 'medium',
|
|
61
107
|
title: 'Obfuscated payload',
|
|
62
108
|
description: 'Eval with String.fromCharCode obfuscation',
|
|
63
|
-
evidence: 'charcode obfuscation detected'
|
|
109
|
+
evidence: 'charcode obfuscation detected',
|
|
110
|
+
context: ctx,
|
|
64
111
|
});
|
|
65
112
|
return findings;
|
|
66
113
|
}
|
|
@@ -79,7 +126,8 @@ export async function scan(pkgJson, files = []) {
|
|
|
79
126
|
severity: 'high',
|
|
80
127
|
title: 'Obfuscated payload',
|
|
81
128
|
description: 'Shell-code obfuscation pattern',
|
|
82
|
-
evidence: p.source.substring(0, 60)
|
|
129
|
+
evidence: p.source.substring(0, 60),
|
|
130
|
+
context: ctx,
|
|
83
131
|
});
|
|
84
132
|
return findings;
|
|
85
133
|
}
|
package/backend/license.js
CHANGED
|
@@ -78,6 +78,10 @@ export function validateLicense(key, feature = '*') {
|
|
|
78
78
|
|
|
79
79
|
export function isFeatureEnabled(feature, licenseKey = process.env.NPM_SCAN_LICENSE_KEY) {
|
|
80
80
|
try {
|
|
81
|
+
if (!licenseKey) {
|
|
82
|
+
const unlocked = feature === 'scan' || ALLOWED_UNLOCKED.includes(feature);
|
|
83
|
+
if (unlocked) return true;
|
|
84
|
+
}
|
|
81
85
|
validateLicense(licenseKey, feature);
|
|
82
86
|
return true;
|
|
83
87
|
} catch {
|
package/backend/lockfile.js
CHANGED
|
@@ -126,10 +126,10 @@ function parseYarnLockfile(content, filePath) {
|
|
|
126
126
|
if (bodyTrim.startsWith('version ')) {
|
|
127
127
|
const vMatch = bodyTrim.match(/^version ['"]([^'"]+)['"]/);
|
|
128
128
|
if (vMatch) version = vMatch[1];
|
|
129
|
-
} else if (bodyTrim.
|
|
130
|
-
const rMatch = bodyTrim.match(
|
|
129
|
+
} else if (bodyTrim.match(/^\s*resolved\s+(.+)/)) {
|
|
130
|
+
const rMatch = bodyTrim.match(/^\s*resolved\s+(.+)/);
|
|
131
131
|
if (rMatch) {
|
|
132
|
-
resolved = rMatch[1];
|
|
132
|
+
resolved = rMatch[1].trim().replace(/^['"]|['"]$/g, '');
|
|
133
133
|
if (resolved.startsWith('https://registry.yarnpkg.com/')) {
|
|
134
134
|
resolved = resolved.replace('https://registry.yarnpkg.com/', 'https://registry.npmjs.org/');
|
|
135
135
|
}
|
package/backend/policy.js
CHANGED
|
@@ -4,10 +4,77 @@ import { load as yamlLoad } from 'js-yaml';
|
|
|
4
4
|
const SEVERITY_ORDER = ['none', 'low', 'medium', 'high', 'critical'];
|
|
5
5
|
const VALID_SEVERITIES = new Set(SEVERITY_ORDER);
|
|
6
6
|
|
|
7
|
+
const KNOWN_REPUTABLE_PACKAGES = new Set([
|
|
8
|
+
'react', 'react-dom', 'vue', 'angular', 'next', 'nuxt',
|
|
9
|
+
'express', 'fastify', 'hono', 'koa', 'connect',
|
|
10
|
+
'webpack', 'vite', 'rollup', 'esbuild', 'typescript', 'babel-core',
|
|
11
|
+
'lodash', 'ramda', 'underscore',
|
|
12
|
+
'axios', 'node-fetch', 'got', 'superagent',
|
|
13
|
+
'sequelize', 'prisma', 'typeorm', 'mongoose',
|
|
14
|
+
'jest', 'mocha', 'vitest', 'ava',
|
|
15
|
+
'prettier', 'eslint', 'stylelint',
|
|
16
|
+
'socket.io', 'ws',
|
|
17
|
+
'rimraf', 'glob', 'minimatch', 'fs-extra',
|
|
18
|
+
]);
|
|
19
|
+
|
|
7
20
|
function severityIndex(s) {
|
|
8
21
|
return SEVERITY_ORDER.indexOf(s);
|
|
9
22
|
}
|
|
10
23
|
|
|
24
|
+
function matchesFilePath(filePath, pattern) {
|
|
25
|
+
if (!pattern) return false;
|
|
26
|
+
if (pattern === '*') return true;
|
|
27
|
+
const regexPattern = pattern
|
|
28
|
+
.replace(/\./g, '\\.')
|
|
29
|
+
.replace(/\*\*/g, '___DOUBLE_STAR___')
|
|
30
|
+
.replace(/\*/g, '[^/]*')
|
|
31
|
+
.replace(/___DOUBLE_STAR___/g, '.*');
|
|
32
|
+
return new RegExp(`^${regexPattern}$`).test(filePath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function matchesContext(finding, rule) {
|
|
36
|
+
const ctx = finding.context;
|
|
37
|
+
if (!ctx) return false;
|
|
38
|
+
|
|
39
|
+
if (rule.context?.is_dist_build === true && !ctx.is_dist_build) return false;
|
|
40
|
+
if (rule.context?.is_dist_build === false && ctx.is_dist_build) return false;
|
|
41
|
+
if (rule.context?.is_test_fixture === true && !ctx.is_test_fixture) return false;
|
|
42
|
+
if (rule.context?.is_test_fixture === false && ctx.is_test_fixture) return false;
|
|
43
|
+
if (rule.context?.is_lifecycle_hook === true && !ctx.is_lifecycle_hook) return false;
|
|
44
|
+
if (rule.context?.is_lifecycle_hook === false && ctx.is_lifecycle_hook) return false;
|
|
45
|
+
if (rule.context?.is_known_safe_domain === true && !ctx.is_known_safe_domain) return false;
|
|
46
|
+
if (rule.context?.is_known_safe_domain === false && ctx.is_known_safe_domain) return false;
|
|
47
|
+
|
|
48
|
+
if (rule.context?.file_path && !matchesFilePath(ctx.file_path, rule.context.file_path)) return false;
|
|
49
|
+
if (rule.context?.url_domain) {
|
|
50
|
+
if (!ctx.url_domain) return false;
|
|
51
|
+
const domainPattern = rule.context.url_domain.replace(/\*/g, '.*');
|
|
52
|
+
if (!new RegExp(`^${domainPattern}$`).test(ctx.url_domain)) return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getPackageReputationTier(pkgName) {
|
|
59
|
+
const name = pkgName?.replace(/^@/, '').replace(/\/.*/, '') || '';
|
|
60
|
+
if (KNOWN_REPUTABLE_PACKAGES.has(name)) return 'trusted';
|
|
61
|
+
return 'unknown';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function matchesSuppressRule(finding, pkgName, rule) {
|
|
65
|
+
if (rule.atk_id !== (finding.atk_id || finding.id)) return false;
|
|
66
|
+
if (rule.package && rule.package !== '*' && rule.package !== pkgName) return false;
|
|
67
|
+
|
|
68
|
+
if (rule.context && !matchesContext(finding, rule)) return false;
|
|
69
|
+
|
|
70
|
+
if (rule.reputation_tier) {
|
|
71
|
+
const tier = getPackageReputationTier(pkgName);
|
|
72
|
+
if (rule.reputation_tier !== tier && !(rule.reputation_tier === '*' || rule.reputation_tier === 'any')) return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
11
78
|
function loadPolicy(path) {
|
|
12
79
|
const raw = readFileSync(path, 'utf8').trim();
|
|
13
80
|
let policy;
|
|
@@ -63,6 +130,8 @@ function sanitizePolicy(policy) {
|
|
|
63
130
|
atk_id: r.atk_id,
|
|
64
131
|
package: r.package || '*',
|
|
65
132
|
reason: r.reason || '',
|
|
133
|
+
context: r.context || null,
|
|
134
|
+
reputation_tier: r.reputation_tier || null,
|
|
66
135
|
})),
|
|
67
136
|
};
|
|
68
137
|
}
|
|
@@ -73,19 +142,15 @@ function isAllowed(packageName, policy) {
|
|
|
73
142
|
return policy.allow.packages.some(p => p === packageName || p === nameOnly);
|
|
74
143
|
}
|
|
75
144
|
|
|
76
|
-
function matchesSuppressRule(finding, pkgName, rule) {
|
|
77
|
-
if (rule.atk_id !== (finding.atk_id || finding.id)) return false;
|
|
78
|
-
if (rule.package === '*') return true;
|
|
79
|
-
return rule.package === pkgName;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
145
|
function applyPolicy(findings, packageName, policy) {
|
|
83
146
|
let filtered = [...findings];
|
|
84
147
|
|
|
85
148
|
if (policy.suppress.length) {
|
|
86
|
-
filtered = filtered.filter(f =>
|
|
87
|
-
|
|
88
|
-
|
|
149
|
+
filtered = filtered.filter(f => {
|
|
150
|
+
if (f.context?.is_lifecycle_hook) return true;
|
|
151
|
+
if (f.context?.is_multi_layer) return true;
|
|
152
|
+
return !policy.suppress.some(r => matchesSuppressRule(f, packageName, r));
|
|
153
|
+
});
|
|
89
154
|
}
|
|
90
155
|
|
|
91
156
|
filtered = filtered.map(f => {
|
|
@@ -108,4 +173,4 @@ function checkFailOn(findings, policy) {
|
|
|
108
173
|
return findings.some(f => severityIndex(f.severity) >= threshold);
|
|
109
174
|
}
|
|
110
175
|
|
|
111
|
-
export { loadPolicy, applyPolicy, isAllowed };
|
|
176
|
+
export { loadPolicy, applyPolicy, isAllowed, getPackageReputationTier, matchesContext };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lateos/npm-scan",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "Modern npm supply chain security scanner — detects obfuscated payloads, credential stealers, conditional triggers, sandbox evasion, and worm-like propagation. 11 attack types, SBOM, NIST/EU CRA compliance reporting.",
|
|
5
5
|
"main": "backend/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"corpus": "node tests/corpus/run.js"
|
|
35
35
|
},
|
|
36
36
|
"lint-staged": {
|
|
37
|
-
"**/package{,-lock}.json": "node cli/cli.js scan-lockfile --fail-on high",
|
|
38
|
-
"**/yarn.lock": "node cli/cli.js scan-lockfile --fail-on high --yarn",
|
|
39
|
-
"**/pnpm-lock.yaml": "node cli/cli.js scan-lockfile --fail-on high --pnpm"
|
|
37
|
+
"**/package{,-lock}.json": "sh -c 'node cli/cli.js scan-lockfile --fail-on high'",
|
|
38
|
+
"**/yarn.lock": "sh -c 'node cli/cli.js scan-lockfile --fail-on high --yarn'",
|
|
39
|
+
"**/pnpm-lock.yaml": "sh -c 'node cli/cli.js scan-lockfile --fail-on high --pnpm'"
|
|
40
40
|
},
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "test-project",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"packages": {
|
|
6
|
+
"": {
|
|
7
|
+
"name": "test-project",
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"lodash": "^4.17.21",
|
|
11
|
+
"axios": "^1.6.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@babel/core": "^7.23.0"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"node_modules/lodash": {
|
|
18
|
+
"name": "lodash",
|
|
19
|
+
"version": "4.17.21",
|
|
20
|
+
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
|
21
|
+
"integrity": "sha512-v2kDEeDAnj4p1hhL6Ogrgu4BSWwg8cD2fRIouDAiqwu+iNl1IvyMex9jG9j8OpNp1zntnv/headququbit",
|
|
22
|
+
"dependencies": {}
|
|
23
|
+
},
|
|
24
|
+
"node_modules/axios": {
|
|
25
|
+
"name": "axios",
|
|
26
|
+
"version": "1.6.8",
|
|
27
|
+
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
|
|
28
|
+
"integrity": "sha512-j2xvyqwsdd456789abcdef",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"form-data": "4.0.0",
|
|
31
|
+
"proxy-from-env": "1.1.0"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"node_modules/axios/node_modules/form-data": {
|
|
35
|
+
"version": "4.0.0",
|
|
36
|
+
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
|
37
|
+
"integrity": "sha512-444567890123456"
|
|
38
|
+
},
|
|
39
|
+
"node_modules/@babel/core": {
|
|
40
|
+
"name": "@babel/core",
|
|
41
|
+
"version": "7.23.9",
|
|
42
|
+
"resolved": "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz",
|
|
43
|
+
"integrity": "sha512-5q+M1iEJCOrGJs9NxzG3p3z7w2cJK/QuoRoI2pOJhtcNQjl9y7w6w4At5ZQHZdwqd+5N5G1lULu7I6pXVBw==",
|
|
44
|
+
"dev": true,
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@babel/generator": "^7.23.6",
|
|
47
|
+
"@babel/parser": "^7.23.9"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"node_modules/reakt": {
|
|
51
|
+
"name": "reakt",
|
|
52
|
+
"version": "18.2.0",
|
|
53
|
+
"resolved": "https://registry.yarnpkg.com/reakt/-/reakt-18.2.0.tgz",
|
|
54
|
+
"integrity": "sha-abcdabcd1234defghi",
|
|
55
|
+
"optional": true,
|
|
56
|
+
"dependencies": {}
|
|
57
|
+
},
|
|
58
|
+
"node_modules/express": {
|
|
59
|
+
"name": "express",
|
|
60
|
+
"version": "4.18.2",
|
|
61
|
+
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
|
62
|
+
"integrity": "sha512-abcdabcd1234abcdefghi",
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"accepts": "~1.3.8",
|
|
65
|
+
"body-parser": "1.20.2"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
lodash@^4.17.21:
|
|
2
2
|
version "4.17.21"
|
|
3
|
-
resolved "https://registry.
|
|
3
|
+
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz"
|
|
4
4
|
integrity sha512-Vythumb
|
|
5
5
|
dependencies: {}
|
|
6
6
|
dev false
|
|
7
|
-
optional
|
|
7
|
+
optional true
|
|
8
8
|
|
|
9
9
|
axios@^1.6.0:
|
|
10
10
|
version "1.6.8"
|
|
11
|
-
resolved "https://registry.
|
|
12
|
-
integrity
|
|
11
|
+
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz"
|
|
12
|
+
integrity sha-j2xvyqwsdd456789abcdef
|
|
13
13
|
dependencies:
|
|
14
14
|
form-data "4.0.0"
|
|
15
15
|
proxy-from-env "1.1.0"
|
|
@@ -30,6 +30,7 @@ axios@^1.6.0:
|
|
|
30
30
|
gensync "^1.0.0-beta.2"
|
|
31
31
|
json5 "^2.2.3"
|
|
32
32
|
semver "^6.3.1"
|
|
33
|
+
rimraf "^3.0.2"
|
|
33
34
|
dev true
|
|
34
35
|
optional false
|
|
35
36
|
|
|
@@ -45,7 +46,7 @@ axios@^1.6.0:
|
|
|
45
46
|
dev false
|
|
46
47
|
optional false
|
|
47
48
|
|
|
48
|
-
reakt@^18.2.0
|
|
49
|
+
reakt@^18.2.0:
|
|
49
50
|
version "18.2.0"
|
|
50
51
|
resolved "https://registry.yarnpkg.com/reakt/-/reakt-18.2.0.tgz"
|
|
51
52
|
integrity sha512-abcdabcd1234defghi
|
|
@@ -53,7 +54,7 @@ reakt@^18.2.0, reakt@^18.2.0::version=18.2.0:
|
|
|
53
54
|
dev false
|
|
54
55
|
optional true
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
express@npm:expres@^4.18.2:
|
|
57
58
|
version "4.18.2"
|
|
58
59
|
resolved "https://registry.npmjs.org/expres-4.18.2.tgz"
|
|
59
60
|
integrity sha512-abcdabcd1234abcdefghi
|
|
@@ -92,7 +93,7 @@ reakt@^18.2.0, reakt@^18.2.0::version=18.2.0:
|
|
|
92
93
|
dev false
|
|
93
94
|
optional false
|
|
94
95
|
|
|
95
|
-
"my-scope-plugin@npm:my-scope-plugin@^1.0.0"
|
|
96
|
+
"my-scope-plugin@npm:my-scope-plugin@^1.0.0":
|
|
96
97
|
version "1.0.0"
|
|
97
98
|
resolved "https://registry.npmjs.org/my-scope-plugin-1.0.0.tgz"
|
|
98
99
|
integrity sha512-abcdefghijk123456789abcdef
|