@socketsecurity/sdk 3.0.27 → 3.0.29

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/dist/index.mjs CHANGED
@@ -1,63 +1,3535 @@
1
1
  /* Socket SDK ESM - Built with esbuild */
2
- var X={name:"@socketsecurity/sdk",version:"3.0.27",license:"MIT",description:"SDK for the Socket API client",author:{name:"Socket Inc",email:"eng@socket.dev",url:"https://socket.dev"},homepage:"https://github.com/SocketDev/socket-sdk-js",repository:{type:"git",url:"git://github.com/SocketDev/socket-sdk-js.git"},type:"module",main:"./dist/index.mjs",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",default:"./dist/index.mjs"},"./package.json":"./package.json","./testing":{types:"./dist/testing.d.ts",default:"./dist/testing.mjs"},"./types/api":{types:"./types/api.d.ts",default:"./types/api.d.ts"},"./types/api-helpers":{types:"./types/api-helpers.d.ts",default:"./types/api-helpers.d.ts"}},scripts:{build:"node scripts/build.mjs",bump:"node scripts/bump.mjs",check:"node scripts/check.mjs",clean:"node scripts/clean.mjs",cover:"node scripts/cover.mjs",fix:"node scripts/lint.mjs --fix","generate-sdk":"node scripts/generate-sdk.mjs",lint:"node scripts/lint.mjs",precommit:"pnpm run check --lint --staged",prepare:"husky",prepublishOnly:"echo 'ERROR: Use GitHub Actions workflow for publishing' && exit 1",publish:"node scripts/publish.mjs",claude:"node scripts/claude.mjs",test:"node scripts/test.mjs",type:"tsgo --noEmit -p .config/tsconfig.check.json",update:"node scripts/update.mjs"},dependencies:{"@socketsecurity/lib":"2.10.4"},devDependencies:{"@babel/parser":"7.26.3","@babel/traverse":"7.26.4","@babel/types":"7.26.3","@biomejs/biome":"2.2.4","@dotenvx/dotenvx":"1.49.0","@eslint/compat":"1.3.2","@eslint/js":"9.35.0","@types/node":"24.9.2","@typescript/native-preview":"7.0.0-dev.20250926.1","@vitest/coverage-v8":"4.0.3",del:"8.0.1","dev-null-cli":"2.0.0",esbuild:"0.25.11",eslint:"9.35.0","eslint-import-resolver-typescript":"4.4.4","eslint-plugin-import-x":"4.16.1","eslint-plugin-jsdoc":"57.0.8","eslint-plugin-n":"17.23.1","eslint-plugin-sort-destructure-keys":"2.0.0","eslint-plugin-unicorn":"56.0.1","fast-glob":"3.3.3",globals:"16.4.0","http2-wrapper":"2.2.1",husky:"9.1.7","magic-string":"0.30.14",nock:"14.0.10","npm-run-all2":"8.0.4","openapi-typescript":"6.7.6",semver:"7.7.2",taze:"19.6.0","type-coverage":"2.29.7","typescript-eslint":"8.44.1",vitest:"4.0.3","yoctocolors-cjs":"2.1.3"},pnpm:{ignoredBuiltDependencies:["esbuild","unrs-resolver"],overrides:{vite:"7.1.12"}},engines:{node:">=18",pnpm:">=10.16.0"},files:["CHANGELOG.md","data/*.json","dist/*.d.ts","dist/*.js","dist/*.mjs","types/*.d.ts"],typeCoverage:{cache:!0,atLeast:99,ignoreAsAssertion:!0,ignoreCatch:!0,ignoreEmptyType:!0,"ignore-non-null-assertion":!0,"ignore-type-assertion":!0,"ignore-files":"test/*",strict:!0}};function x(o){let{homepage:t}=o;return`${o.name.replace("@","").replace("/","-")}/${o.version}${t?` (${t})`:""}`}import{SOCKET_API_TOKENS_URL as re,SOCKET_CONTACT_URL as ne,SOCKET_DASHBOARD_URL as oe}from"@socketsecurity/lib/constants/socket";var q=x(X),Z=3e4,ee=3,te=1e3,B=300*1e3,N=5e3,j=10*1024*1024,$=100*1024*1024,se="https://socketusercontent.com",G=new Set(["http","https","http2"]),fe=new Map([["malware","error"],["criticalCVE","warn"],["didYouMean","warn"],["gitDependency","warn"],["httpDependency","warn"],["licenseSpdxDisj","warn"],["obfuscatedFile","warn"],["troll","warn"],["deprecated","monitor"],["mediumCVE","monitor"],["mildCVE","monitor"],["shrinkwrap","monitor"],["telemetry","monitor"],["unpopularPackage","monitor"],["unstableOwnership","monitor"],["ambiguousClassifier","ignore"],["badEncoding","ignore"],["badSemver","ignore"],["badSemverDependency","ignore"],["bidi","ignore"],["binScriptConfusion","ignore"],["chromeContentScript","ignore"],["chromeHostPermission","ignore"],["chromePermission","ignore"],["chromeWildcardHostPermission","ignore"],["chronoAnomaly","ignore"],["compromisedSSHKey","ignore"],["copyleftLicense","ignore"],["cve","ignore"],["debugAccess","ignore"],["deprecatedLicense","ignore"],["deprecatedException","ignore"],["dynamicRequire","ignore"],["emptyPackage","ignore"],["envVars","ignore"],["explicitlyUnlicensedItem","ignore"],["extraneousDependency","ignore"],["fileDependency","ignore"],["filesystemAccess","ignore"],["floatingDependency","ignore"],["gitHubDependency","ignore"],["gptAnomaly","ignore"],["gptDidYouMean","ignore"],["gptMalware","ignore"],["gptSecurity","ignore"],["hasNativeCode","ignore"],["highEntropyStrings","ignore"],["homoglyphs","ignore"],["installScripts","ignore"],["invalidPackageJSON","ignore"],["invisibleChars","ignore"],["licenseChange","ignore"],["licenseException","ignore"],["longStrings","ignore"],["majorRefactor","ignore"],["manifestConfusion","ignore"],["minifiedFile","ignore"],["miscLicenseIssues","ignore"],["missingAuthor","ignore"],["missingDependency","ignore"],["missingLicense","ignore"],["missingTarball","ignore"],["mixedLicense","ignore"],["modifiedException","ignore"],["modifiedLicense","ignore"],["networkAccess","ignore"],["newAuthor","ignore"],["noAuthorData","ignore"],["noBugTracker","ignore"],["noLicenseFound","ignore"],["noREADME","ignore"],["noRepository","ignore"],["noTests","ignore"],["noV1","ignore"],["noWebsite","ignore"],["nonOSILicense","ignore"],["nonSPDXLicense","ignore"],["nonpermissiveLicense","ignore"],["notice","ignore"],["obfuscatedRequire","ignore"],["peerDependency","ignore"],["potentialVulnerability","ignore"],["semverAnomaly","ignore"],["shellAccess","ignore"],["shellScriptOverride","ignore"],["socketUpgradeAvailable","ignore"],["suspiciousStarActivity","ignore"],["suspiciousString","ignore"],["trivialPackage","ignore"],["typeModuleCompatibility","ignore"],["uncaughtOptionalDependency","ignore"],["unclearLicense","ignore"],["unidentifiedLicense","ignore"],["unmaintained","ignore"],["unpublished","ignore"],["unresolvedRequire","ignore"],["unsafeCopyright","ignore"],["unusedDependency","ignore"],["urlStrings","ignore"],["usesEval","ignore"],["zeroWidth","ignore"]]);import ae from"node:path";import{memoize as ye}from"@socketsecurity/lib/memoization";import{normalizePath as ie}from"@socketsecurity/lib/path";var Q=ye(o=>o.endsWith("/")?o:`${o}/`,{name:"normalizeBaseUrl"});function z(){if(Promise.withResolvers)return Promise.withResolvers();let o={};return o.promise=new Promise((t,e)=>{o.resolve=t,o.reject=e}),o}function k(o){let t=new URLSearchParams(o),e={__proto__:null},s=t.entries();for(let r of s){let n=r[0],a=r[1];n==="defaultBranch"?n="default_branch":n==="perPage"&&(n="per_page"),a&&(e[n]=a)}return new URLSearchParams(e)}function U(o,t){let e=I(t);return o.map(s=>ie(ae.resolve(e,s)))}function I(o="."){return ie(ae.resolve(process.cwd(),o))}import W from"node:events";import{createReadStream as ke}from"node:fs";import _ from"node:path";import{Readable as Pe}from"node:stream";import{normalizePath as Te}from"@socketsecurity/lib/path";import Re from"node:http";import Se from"node:https";import{debugLog as ce}from"@socketsecurity/lib/debug";import{jsonParse as we}from"@socketsecurity/lib/json";import{perfTimer as J}from"@socketsecurity/lib/performance";var R=class o extends Error{response;constructor(t,e=""){let s=t.statusCode??"unknown",r=t.statusMessage??"No status message";super(`Socket API ${e||"Request failed"} (${s}): ${r}`),this.name="ResponseError",this.response=t,Error.captureStackTrace(this,o)}};async function A(o,t,e){let s=P(o).request(`${o}${t}`,{method:"DELETE",...e}).end();return await T(s)}async function m(o,t,e){let s=J("http:get",{urlPath:t});try{let r=P(o).request(`${o}${t}`,{method:"GET",...e}).end(),n=await T(r);return s({statusCode:n.statusCode}),n}catch(r){throw s({error:!0}),r}}async function y(o,t,e,s,r){let n=J(`http:${o.toLowerCase()}`,{urlPath:e});try{let a=JSON.stringify(s),i=P(t).request(`${t}${e}`,{method:o,...r,headers:{...r.headers,"Content-Length":Buffer.byteLength(a,"utf8"),"Content-Type":"application/json"}});i.write(a),i.end();let c=await T(i);return n({statusCode:c.statusCode}),c}catch(a){throw n({error:!0}),a}}async function L(o){return await new Promise((t,e)=>{let s="",r=0;o.setEncoding("utf8"),o.on("data",n=>{let a=Buffer.byteLength(n,"utf8");if(r+=a,r>j){o.destroy();let i=(r/(1024*1024)).toFixed(2),c=(j/(1024*1024)).toFixed(2),u=[`Response exceeds maximum size limit (${i}MB > ${c}MB)`,"\u2192 The API response is too large to process safely.","\u2192 Try: Use pagination parameters (limit, offset) to reduce response size.","\u2192 Try: Request specific fields instead of full objects.","\u2192 Contact support if you need to process larger responses."].join(`
3
- `);e(new Error(u));return}s+=n}),o.on("end",()=>t(s)),o.on("error",n=>e(n))})}function P(o){return o.startsWith("https:")?Se:Re}async function T(o){return await new Promise((t,e)=>{let s=!1;o.on("response",r=>{s||t(r)}),o.on("timeout",()=>{s=!0,o.destroy();let r=o.method||"REQUEST",n=o.path||"unknown",a=o.timeout||"configured timeout",i=[`${r} request timed out after ${a}ms: ${n}`,"\u2192 The Socket API did not respond in time.","\u2192 Try: Increase timeout option or check network connectivity.","\u2192 If problem persists, Socket API may be experiencing issues."].join(`
4
- `);e(new Error(i))}),o.on("error",r=>{if(!s){let n=r,a=o.method||"REQUEST",i=o.path||"unknown",c=`${a} request failed: ${i}`;n.code==="ECONNREFUSED"?c+=["","\u2192 Connection refused. Socket API server is unreachable.","\u2192 Check: Network connectivity and firewall settings.","\u2192 Verify: Base URL is correct (default: https://api.socket.dev)"].join(`
5
- `):n.code==="ENOTFOUND"?c+=["","\u2192 DNS lookup failed. Cannot resolve hostname.","\u2192 Check: Internet connection and DNS settings.","\u2192 Verify: Base URL hostname is correct."].join(`
6
- `):n.code==="ETIMEDOUT"?c+=["","\u2192 Connection timed out. Network or server issue.","\u2192 Try: Check network connectivity and retry.","\u2192 If using proxy, verify proxy configuration."].join(`
7
- `):n.code==="ECONNRESET"?c+=["","\u2192 Connection reset by server. Possible network interruption.","\u2192 Try: Retry the request. Enable retries option if not set."].join(`
8
- `):n.code==="EPIPE"?c+=["","\u2192 Broken pipe. Server closed connection unexpectedly.","\u2192 Possible: Authentication issue or server error.","\u2192 Check: API token is valid and has required permissions."].join(`
9
- `):n.code==="CERT_HAS_EXPIRED"||n.code==="UNABLE_TO_VERIFY_LEAF_SIGNATURE"?c+=["","\u2192 SSL/TLS certificate error.","\u2192 Check: System time and date are correct.","\u2192 Try: Update CA certificates on your system."].join(`
10
- `):n.code&&(c+=`
11
- \u2192 Error code: ${n.code}`);let u=new Error(c,{cause:r});e(u)}})})}async function d(o,t){let e=J("http:parse-json");try{if(!O(o))throw new R(o,t?`${t} Request failed`:void 0);let s=await L(o);if(s==="")return ce("API response: empty response treated as {}"),e({success:!0}),{};try{let r=we(s);return ce("API response:",r),e({success:!0}),r}catch(r){if(e({error:!0}),r instanceof SyntaxError){let a=o.headers["content-type"],c=["Socket API returned invalid JSON response",`\u2192 Response preview: ${s.length>200?`${s.slice(0,200)}...`:s}`,`\u2192 Parse error: ${r.message}`];a&&!a.includes("application/json")?c.push(`\u2192 Unexpected Content-Type: ${a} (expected application/json)`,"\u2192 The API may have returned an error page instead of JSON."):s.startsWith("<")?c.push("\u2192 Response appears to be HTML, not JSON.","\u2192 This may indicate an API endpoint error or network interception."):s.length===0?c.push("\u2192 Response body is empty when JSON was expected."):(s.includes("502 Bad Gateway")||s.includes("503 Service"))&&c.push("\u2192 Response indicates a server error.","\u2192 The Socket API may be temporarily unavailable.");let u=new Error(c.join(`
12
- `),{cause:r});throw u.name="SyntaxError",u.originalResponse=s,Object.setPrototypeOf(u,SyntaxError.prototype),u}if(r instanceof Error)throw r;let n=new Error("Unknown JSON parsing error",{cause:r});throw n.name="SyntaxError",n.originalResponse=s,Object.setPrototypeOf(n,SyntaxError.prototype),n}}catch(s){throw e({error:!0}),s}}function O(o){let{statusCode:t}=o;return t?t>=200&&t<300:!1}function M(o,t,e){if(!t){let s=e?e.split(","):void 0,r=n=>({name:n.name,version:n.version,size:n.size,author:n.author,type:n.type,supplyChainRisk:n.supplyChainRisk,scorecards:n.scorecards,topLevelAncestors:n.topLevelAncestors,alerts:n.alerts?.filter(a=>!(a.severity==="low"||s&&a.action&&!s.includes(a.action))).map(a=>({type:a.type,severity:a.severity,key:a.key}))});if(o.artifacts){let n=o.artifacts;return{...o,artifacts:Array.isArray(n)?n.map(r):n}}if(o.alerts)return r(o)}return o}function F(o,t){let e=[];for(let s of o){let r=Te(_.relative(t,s)),n=_.basename(s),a;try{a=ke(s,{highWaterMark:1024*1024})}catch(i){let c=i,u=`Failed to read file: ${s}`;throw c.code==="ENOENT"?u+=`
13
- \u2192 File does not exist. Check the file path and try again.`:c.code==="EACCES"?u+=`
14
- \u2192 Permission denied. Run: chmod +r "${s}"`:c.code==="EISDIR"?u+=`
15
- \u2192 Expected a file but found a directory.`:c.code&&(u+=`
16
- \u2192 Error code: ${c.code}`),new Error(u,{cause:i})}e.push([`Content-Disposition: form-data; name="${r}"; filename="${n}"\r
17
- `,`Content-Type: application/octet-stream\r
18
- \r
19
- `,a])}return e}function Ee(o,t="data.json"){let e=_.extname(t);return[`Content-Disposition: form-data; name="${_.basename(t,e)}"; filename="${t}"\r
2
+
3
+ // package.json
4
+ var package_default = {
5
+ name: "@socketsecurity/sdk",
6
+ version: "3.0.29",
7
+ license: "MIT",
8
+ description: "SDK for the Socket API client",
9
+ author: {
10
+ name: "Socket Inc",
11
+ email: "eng@socket.dev",
12
+ url: "https://socket.dev"
13
+ },
14
+ homepage: "https://github.com/SocketDev/socket-sdk-js",
15
+ repository: {
16
+ type: "git",
17
+ url: "git://github.com/SocketDev/socket-sdk-js.git"
18
+ },
19
+ type: "module",
20
+ main: "./dist/index.mjs",
21
+ types: "./dist/index.d.ts",
22
+ exports: {
23
+ ".": {
24
+ types: "./dist/index.d.ts",
25
+ default: "./dist/index.mjs"
26
+ },
27
+ "./package.json": "./package.json",
28
+ "./testing": {
29
+ types: "./dist/testing.d.ts",
30
+ default: "./dist/testing.mjs"
31
+ },
32
+ "./types/api": {
33
+ types: "./types/api.d.ts",
34
+ default: "./types/api.d.ts"
35
+ },
36
+ "./types/api-helpers": {
37
+ types: "./types/api-helpers.d.ts",
38
+ default: "./types/api-helpers.d.ts"
39
+ }
40
+ },
41
+ scripts: {
42
+ build: "node scripts/build.mjs",
43
+ bump: "node scripts/bump.mjs",
44
+ check: "node scripts/check.mjs",
45
+ clean: "node scripts/clean.mjs",
46
+ cover: "node scripts/cover.mjs",
47
+ fix: "node scripts/lint.mjs --fix",
48
+ "generate-sdk": "node scripts/generate-sdk.mjs",
49
+ lint: "node scripts/lint.mjs",
50
+ precommit: "pnpm run check --lint --staged",
51
+ prepare: "husky",
52
+ prepublishOnly: "echo 'ERROR: Use GitHub Actions workflow for publishing' && exit 1",
53
+ publish: "node scripts/publish.mjs",
54
+ claude: "node scripts/claude.mjs",
55
+ test: "node scripts/test.mjs",
56
+ type: "tsgo --noEmit -p .config/tsconfig.check.json",
57
+ update: "node scripts/update.mjs"
58
+ },
59
+ devDependencies: {
60
+ "@babel/parser": "7.26.3",
61
+ "@babel/traverse": "7.26.4",
62
+ "@babel/types": "7.26.3",
63
+ "@biomejs/biome": "2.2.4",
64
+ "@dotenvx/dotenvx": "1.49.0",
65
+ "@eslint/compat": "1.3.2",
66
+ "@eslint/js": "9.35.0",
67
+ "@socketregistry/packageurl-js": "1.3.2",
68
+ "@socketsecurity/lib": "3.0.3",
69
+ "@types/node": "24.9.2",
70
+ "@typescript/native-preview": "7.0.0-dev.20250926.1",
71
+ "@vitest/coverage-v8": "4.0.3",
72
+ del: "8.0.1",
73
+ "dev-null-cli": "2.0.0",
74
+ esbuild: "0.25.11",
75
+ eslint: "9.35.0",
76
+ "eslint-import-resolver-typescript": "4.4.4",
77
+ "eslint-plugin-import-x": "4.16.1",
78
+ "eslint-plugin-jsdoc": "57.0.8",
79
+ "eslint-plugin-n": "17.23.1",
80
+ "eslint-plugin-sort-destructure-keys": "2.0.0",
81
+ "eslint-plugin-unicorn": "56.0.1",
82
+ "fast-glob": "3.3.3",
83
+ globals: "16.4.0",
84
+ "http2-wrapper": "2.2.1",
85
+ husky: "9.1.7",
86
+ "magic-string": "0.30.14",
87
+ nock: "14.0.10",
88
+ "npm-run-all2": "8.0.4",
89
+ "openapi-typescript": "6.7.6",
90
+ semver: "7.7.2",
91
+ taze: "19.6.0",
92
+ "type-coverage": "2.29.7",
93
+ "typescript-eslint": "8.44.1",
94
+ vitest: "4.0.3",
95
+ "yoctocolors-cjs": "2.1.3"
96
+ },
97
+ pnpm: {
98
+ ignoredBuiltDependencies: [
99
+ "esbuild",
100
+ "unrs-resolver"
101
+ ],
102
+ overrides: {
103
+ vite: "7.1.12"
104
+ }
105
+ },
106
+ engines: {
107
+ node: ">=18",
108
+ pnpm: ">=10.16.0"
109
+ },
110
+ files: [
111
+ "CHANGELOG.md",
112
+ "data/*.json",
113
+ "dist/*.d.ts",
114
+ "dist/*.js",
115
+ "dist/*.mjs",
116
+ "types/*.d.ts"
117
+ ],
118
+ typeCoverage: {
119
+ cache: true,
120
+ atLeast: 99,
121
+ ignoreAsAssertion: true,
122
+ ignoreCatch: true,
123
+ ignoreEmptyType: true,
124
+ "ignore-non-null-assertion": true,
125
+ "ignore-type-assertion": true,
126
+ "ignore-files": "test/*",
127
+ strict: true
128
+ }
129
+ };
130
+
131
+ // src/user-agent.ts
132
+ function createUserAgentFromPkgJson(pkgData) {
133
+ const { homepage } = pkgData;
134
+ const name = pkgData.name.replace("@", "").replace("/", "-");
135
+ return `${name}/${pkgData.version}${homepage ? ` (${homepage})` : ""}`;
136
+ }
137
+
138
+ // src/constants.ts
139
+ import {
140
+ SOCKET_API_TOKENS_URL,
141
+ SOCKET_CONTACT_URL,
142
+ SOCKET_DASHBOARD_URL
143
+ } from "@socketsecurity/lib/constants/socket";
144
+ var DEFAULT_USER_AGENT = createUserAgentFromPkgJson(package_default);
145
+ var DEFAULT_HTTP_TIMEOUT = 3e4;
146
+ var DEFAULT_RETRIES = 3;
147
+ var DEFAULT_RETRY_DELAY = 1e3;
148
+ var MAX_HTTP_TIMEOUT = 5 * 60 * 1e3;
149
+ var MIN_HTTP_TIMEOUT = 5e3;
150
+ var MAX_RESPONSE_SIZE = 10 * 1024 * 1024;
151
+ var MAX_STREAM_SIZE = 100 * 1024 * 1024;
152
+ var SOCKET_PUBLIC_BLOB_STORE_URL = "https://socketusercontent.com";
153
+ var httpAgentNames = /* @__PURE__ */ new Set(["http", "https", "http2"]);
154
+ var publicPolicy = /* @__PURE__ */ new Map([
155
+ // error (1):
156
+ ["malware", "error"],
157
+ // warn (7):
158
+ ["criticalCVE", "warn"],
159
+ ["didYouMean", "warn"],
160
+ ["gitDependency", "warn"],
161
+ ["httpDependency", "warn"],
162
+ ["licenseSpdxDisj", "warn"],
163
+ ["obfuscatedFile", "warn"],
164
+ ["troll", "warn"],
165
+ // monitor (7):
166
+ ["deprecated", "monitor"],
167
+ ["mediumCVE", "monitor"],
168
+ ["mildCVE", "monitor"],
169
+ ["shrinkwrap", "monitor"],
170
+ ["telemetry", "monitor"],
171
+ ["unpopularPackage", "monitor"],
172
+ ["unstableOwnership", "monitor"],
173
+ // ignore (85):
174
+ ["ambiguousClassifier", "ignore"],
175
+ ["badEncoding", "ignore"],
176
+ ["badSemver", "ignore"],
177
+ ["badSemverDependency", "ignore"],
178
+ ["bidi", "ignore"],
179
+ ["binScriptConfusion", "ignore"],
180
+ ["chromeContentScript", "ignore"],
181
+ ["chromeHostPermission", "ignore"],
182
+ ["chromePermission", "ignore"],
183
+ ["chromeWildcardHostPermission", "ignore"],
184
+ ["chronoAnomaly", "ignore"],
185
+ ["compromisedSSHKey", "ignore"],
186
+ ["copyleftLicense", "ignore"],
187
+ ["cve", "ignore"],
188
+ ["debugAccess", "ignore"],
189
+ ["deprecatedLicense", "ignore"],
190
+ ["deprecatedException", "ignore"],
191
+ ["dynamicRequire", "ignore"],
192
+ ["emptyPackage", "ignore"],
193
+ ["envVars", "ignore"],
194
+ ["explicitlyUnlicensedItem", "ignore"],
195
+ ["extraneousDependency", "ignore"],
196
+ ["fileDependency", "ignore"],
197
+ ["filesystemAccess", "ignore"],
198
+ ["floatingDependency", "ignore"],
199
+ ["gitHubDependency", "ignore"],
200
+ ["gptAnomaly", "ignore"],
201
+ ["gptDidYouMean", "ignore"],
202
+ ["gptMalware", "ignore"],
203
+ ["gptSecurity", "ignore"],
204
+ ["hasNativeCode", "ignore"],
205
+ ["highEntropyStrings", "ignore"],
206
+ ["homoglyphs", "ignore"],
207
+ ["installScripts", "ignore"],
208
+ ["invalidPackageJSON", "ignore"],
209
+ ["invisibleChars", "ignore"],
210
+ ["licenseChange", "ignore"],
211
+ ["licenseException", "ignore"],
212
+ ["longStrings", "ignore"],
213
+ ["majorRefactor", "ignore"],
214
+ ["manifestConfusion", "ignore"],
215
+ ["minifiedFile", "ignore"],
216
+ ["miscLicenseIssues", "ignore"],
217
+ ["missingAuthor", "ignore"],
218
+ ["missingDependency", "ignore"],
219
+ ["missingLicense", "ignore"],
220
+ ["missingTarball", "ignore"],
221
+ ["mixedLicense", "ignore"],
222
+ ["modifiedException", "ignore"],
223
+ ["modifiedLicense", "ignore"],
224
+ ["networkAccess", "ignore"],
225
+ ["newAuthor", "ignore"],
226
+ ["noAuthorData", "ignore"],
227
+ ["noBugTracker", "ignore"],
228
+ ["noLicenseFound", "ignore"],
229
+ ["noREADME", "ignore"],
230
+ ["noRepository", "ignore"],
231
+ ["noTests", "ignore"],
232
+ ["noV1", "ignore"],
233
+ ["noWebsite", "ignore"],
234
+ ["nonOSILicense", "ignore"],
235
+ ["nonSPDXLicense", "ignore"],
236
+ ["nonpermissiveLicense", "ignore"],
237
+ ["notice", "ignore"],
238
+ ["obfuscatedRequire", "ignore"],
239
+ ["peerDependency", "ignore"],
240
+ ["potentialVulnerability", "ignore"],
241
+ ["semverAnomaly", "ignore"],
242
+ ["shellAccess", "ignore"],
243
+ ["shellScriptOverride", "ignore"],
244
+ ["socketUpgradeAvailable", "ignore"],
245
+ ["suspiciousStarActivity", "ignore"],
246
+ ["suspiciousString", "ignore"],
247
+ ["trivialPackage", "ignore"],
248
+ ["typeModuleCompatibility", "ignore"],
249
+ ["uncaughtOptionalDependency", "ignore"],
250
+ ["unclearLicense", "ignore"],
251
+ ["unidentifiedLicense", "ignore"],
252
+ ["unmaintained", "ignore"],
253
+ ["unpublished", "ignore"],
254
+ ["unresolvedRequire", "ignore"],
255
+ ["unsafeCopyright", "ignore"],
256
+ ["unusedDependency", "ignore"],
257
+ ["urlStrings", "ignore"],
258
+ ["usesEval", "ignore"],
259
+ ["zeroWidth", "ignore"]
260
+ ]);
261
+
262
+ // src/utils.ts
263
+ import path from "node:path";
264
+ import { memoize } from "@socketsecurity/lib/memoization";
265
+ import { normalizePath } from "@socketsecurity/lib/path";
266
+ var normalizeBaseUrl = memoize(
267
+ (baseUrl) => {
268
+ return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
269
+ },
270
+ { name: "normalizeBaseUrl" }
271
+ );
272
+ function promiseWithResolvers() {
273
+ if (Promise.withResolvers) {
274
+ return Promise.withResolvers();
275
+ }
276
+ const obj = {};
277
+ obj.promise = new Promise((resolver, reject) => {
278
+ obj.resolve = resolver;
279
+ obj.reject = reject;
280
+ });
281
+ return obj;
282
+ }
283
+ function queryToSearchParams(init) {
284
+ const params = new URLSearchParams(
285
+ init
286
+ );
287
+ const normalized = { __proto__: null };
288
+ const entries = params.entries();
289
+ for (const entry of entries) {
290
+ let key = entry[0];
291
+ const value = entry[1];
292
+ if (key === "defaultBranch") {
293
+ key = "default_branch";
294
+ } else if (key === "perPage") {
295
+ key = "per_page";
296
+ }
297
+ if (value) {
298
+ normalized[key] = value;
299
+ }
300
+ }
301
+ return new URLSearchParams(normalized);
302
+ }
303
+ function resolveAbsPaths(filepaths, pathsRelativeTo) {
304
+ const basePath = resolveBasePath(pathsRelativeTo);
305
+ return filepaths.map((p) => normalizePath(path.resolve(basePath, p)));
306
+ }
307
+ function resolveBasePath(pathsRelativeTo = ".") {
308
+ return normalizePath(path.resolve(process.cwd(), pathsRelativeTo));
309
+ }
310
+
311
+ // src/file-upload.ts
312
+ import events from "node:events";
313
+ import { createReadStream } from "node:fs";
314
+ import path2 from "node:path";
315
+ import { Readable } from "node:stream";
316
+ import { normalizePath as normalizePath2 } from "@socketsecurity/lib/path";
317
+
318
+ // src/http-client.ts
319
+ import http from "node:http";
320
+ import https from "node:https";
321
+ import { debugLog } from "@socketsecurity/lib/debug";
322
+ import { jsonParse } from "@socketsecurity/lib/json";
323
+ import { perfTimer } from "@socketsecurity/lib/performance";
324
+ var ResponseError = class _ResponseError extends Error {
325
+ response;
326
+ /**
327
+ * Create a new ResponseError from an HTTP response.
328
+ * Automatically formats error message with status code and message.
329
+ */
330
+ constructor(response, message = "") {
331
+ const statusCode = response.statusCode ?? "unknown";
332
+ const statusMessage = response.statusMessage ?? "No status message";
333
+ super(
334
+ /* c8 ignore next - fallback empty message if not provided */
335
+ `Socket API ${message || "Request failed"} (${statusCode}): ${statusMessage}`
336
+ );
337
+ this.name = "ResponseError";
338
+ this.response = response;
339
+ Error.captureStackTrace(this, _ResponseError);
340
+ }
341
+ };
342
+ async function createDeleteRequest(baseUrl, urlPath, options) {
343
+ const req = getHttpModule(baseUrl).request(`${baseUrl}${urlPath}`, {
344
+ method: "DELETE",
345
+ ...options
346
+ }).end();
347
+ return await getResponse(req);
348
+ }
349
+ async function createGetRequest(baseUrl, urlPath, options) {
350
+ const stopTimer = perfTimer("http:get", { urlPath });
351
+ try {
352
+ const req = getHttpModule(baseUrl).request(`${baseUrl}${urlPath}`, {
353
+ method: "GET",
354
+ ...options
355
+ }).end();
356
+ const response = await getResponse(req);
357
+ stopTimer({ statusCode: response.statusCode });
358
+ return response;
359
+ } catch (error) {
360
+ stopTimer({ error: true });
361
+ throw error;
362
+ }
363
+ }
364
+ async function createRequestWithJson(method, baseUrl, urlPath, json, options) {
365
+ const stopTimer = perfTimer(`http:${method.toLowerCase()}`, {
366
+ urlPath
367
+ });
368
+ try {
369
+ const body = JSON.stringify(json);
370
+ const req = getHttpModule(baseUrl).request(`${baseUrl}${urlPath}`, {
371
+ method,
372
+ ...options,
373
+ headers: {
374
+ ...options.headers,
375
+ "Content-Length": Buffer.byteLength(body, "utf8"),
376
+ "Content-Type": "application/json"
377
+ }
378
+ });
379
+ req.write(body);
380
+ req.end();
381
+ const response = await getResponse(req);
382
+ stopTimer({ statusCode: response.statusCode });
383
+ return response;
384
+ } catch (error) {
385
+ stopTimer({ error: true });
386
+ throw error;
387
+ }
388
+ }
389
+ async function getErrorResponseBody(response) {
390
+ return await new Promise((resolve, reject) => {
391
+ let body = "";
392
+ let totalBytes = 0;
393
+ response.setEncoding("utf8");
394
+ response.on("data", (chunk) => {
395
+ const chunkBytes = Buffer.byteLength(chunk, "utf8");
396
+ totalBytes += chunkBytes;
397
+ if (totalBytes > MAX_RESPONSE_SIZE) {
398
+ response.destroy();
399
+ const sizeMB = (totalBytes / (1024 * 1024)).toFixed(2);
400
+ const maxMB = (MAX_RESPONSE_SIZE / (1024 * 1024)).toFixed(2);
401
+ const message = [
402
+ `Response exceeds maximum size limit (${sizeMB}MB > ${maxMB}MB)`,
403
+ "\u2192 The API response is too large to process safely.",
404
+ "\u2192 Try: Use pagination parameters (limit, offset) to reduce response size.",
405
+ "\u2192 Try: Request specific fields instead of full objects.",
406
+ "\u2192 Contact support if you need to process larger responses."
407
+ ].join("\n");
408
+ reject(new Error(message));
409
+ return;
410
+ }
411
+ body += chunk;
412
+ });
413
+ response.on("end", () => resolve(body));
414
+ response.on("error", (e) => reject(e));
415
+ });
416
+ }
417
+ function getHttpModule(url) {
418
+ return url.startsWith("https:") ? https : http;
419
+ }
420
+ async function getResponse(req) {
421
+ return await new Promise((resolve, reject) => {
422
+ let timedOut = false;
423
+ req.on("response", (response) => {
424
+ if (timedOut) {
425
+ return;
426
+ }
427
+ resolve(response);
428
+ });
429
+ req.on("timeout", () => {
430
+ timedOut = true;
431
+ req.destroy();
432
+ const method = req.method || "REQUEST";
433
+ const path3 = req.path || "unknown";
434
+ const timeout = req.timeout || "configured timeout";
435
+ const message = [
436
+ `${method} request timed out after ${timeout}ms: ${path3}`,
437
+ "\u2192 The Socket API did not respond in time.",
438
+ "\u2192 Try: Increase timeout option or check network connectivity.",
439
+ "\u2192 If problem persists, Socket API may be experiencing issues."
440
+ ].join("\n");
441
+ reject(new Error(message));
442
+ });
443
+ req.on("error", (e) => {
444
+ if (!timedOut) {
445
+ const err = e;
446
+ const method = req.method || "REQUEST";
447
+ const path3 = req.path || "unknown";
448
+ let message = `${method} request failed: ${path3}`;
449
+ if (err.code === "ECONNREFUSED") {
450
+ message += [
451
+ "",
452
+ "\u2192 Connection refused. Socket API server is unreachable.",
453
+ "\u2192 Check: Network connectivity and firewall settings.",
454
+ "\u2192 Verify: Base URL is correct (default: https://api.socket.dev)"
455
+ ].join("\n");
456
+ } else if (err.code === "ENOTFOUND") {
457
+ message += [
458
+ "",
459
+ "\u2192 DNS lookup failed. Cannot resolve hostname.",
460
+ "\u2192 Check: Internet connection and DNS settings.",
461
+ "\u2192 Verify: Base URL hostname is correct."
462
+ ].join("\n");
463
+ } else if (err.code === "ETIMEDOUT") {
464
+ message += [
465
+ "",
466
+ "\u2192 Connection timed out. Network or server issue.",
467
+ "\u2192 Try: Check network connectivity and retry.",
468
+ "\u2192 If using proxy, verify proxy configuration."
469
+ ].join("\n");
470
+ } else if (err.code === "ECONNRESET") {
471
+ message += [
472
+ "",
473
+ "\u2192 Connection reset by server. Possible network interruption.",
474
+ "\u2192 Try: Retry the request. Enable retries option if not set."
475
+ ].join("\n");
476
+ } else if (err.code === "EPIPE") {
477
+ message += [
478
+ "",
479
+ "\u2192 Broken pipe. Server closed connection unexpectedly.",
480
+ "\u2192 Possible: Authentication issue or server error.",
481
+ "\u2192 Check: API token is valid and has required permissions."
482
+ ].join("\n");
483
+ } else if (err.code === "CERT_HAS_EXPIRED" || err.code === "UNABLE_TO_VERIFY_LEAF_SIGNATURE") {
484
+ message += [
485
+ "",
486
+ "\u2192 SSL/TLS certificate error.",
487
+ "\u2192 Check: System time and date are correct.",
488
+ "\u2192 Try: Update CA certificates on your system."
489
+ ].join("\n");
490
+ } else if (err.code) {
491
+ message += `
492
+ \u2192 Error code: ${err.code}`;
493
+ }
494
+ const enhancedError = new Error(message, { cause: e });
495
+ reject(enhancedError);
496
+ }
497
+ });
498
+ });
499
+ }
500
+ async function getResponseJson(response, method) {
501
+ const stopTimer = perfTimer("http:parse-json");
502
+ try {
503
+ if (!isResponseOk(response)) {
504
+ throw new ResponseError(
505
+ response,
506
+ method ? `${method} Request failed` : void 0
507
+ );
508
+ }
509
+ const responseBody = await getErrorResponseBody(response);
510
+ if (responseBody === "") {
511
+ debugLog("API response: empty response treated as {}");
512
+ stopTimer({ success: true });
513
+ return {};
514
+ }
515
+ try {
516
+ const responseJson = jsonParse(responseBody);
517
+ debugLog("API response:", responseJson);
518
+ stopTimer({ success: true });
519
+ return responseJson;
520
+ } catch (e) {
521
+ stopTimer({ error: true });
522
+ if (e instanceof SyntaxError) {
523
+ const contentType = response.headers["content-type"];
524
+ const preview = responseBody.length > 200 ? `${responseBody.slice(0, 200)}...` : responseBody;
525
+ const messageParts = [
526
+ "Socket API returned invalid JSON response",
527
+ `\u2192 Response preview: ${preview}`,
528
+ `\u2192 Parse error: ${e.message}`
529
+ ];
530
+ if (contentType && !contentType.includes("application/json")) {
531
+ messageParts.push(
532
+ `\u2192 Unexpected Content-Type: ${contentType} (expected application/json)`,
533
+ "\u2192 The API may have returned an error page instead of JSON."
534
+ );
535
+ } else if (responseBody.startsWith("<")) {
536
+ messageParts.push(
537
+ "\u2192 Response appears to be HTML, not JSON.",
538
+ "\u2192 This may indicate an API endpoint error or network interception."
539
+ );
540
+ } else if (responseBody.length === 0) {
541
+ messageParts.push("\u2192 Response body is empty when JSON was expected.");
542
+ } else if (responseBody.includes("502 Bad Gateway") || responseBody.includes("503 Service")) {
543
+ messageParts.push(
544
+ "\u2192 Response indicates a server error.",
545
+ "\u2192 The Socket API may be temporarily unavailable."
546
+ );
547
+ }
548
+ const enhancedError = new Error(messageParts.join("\n"), {
549
+ cause: e
550
+ });
551
+ enhancedError.name = "SyntaxError";
552
+ enhancedError.originalResponse = responseBody;
553
+ Object.setPrototypeOf(enhancedError, SyntaxError.prototype);
554
+ throw enhancedError;
555
+ }
556
+ if (e instanceof Error) {
557
+ throw e;
558
+ }
559
+ const unknownError = new Error("Unknown JSON parsing error", {
560
+ cause: e
561
+ });
562
+ unknownError.name = "SyntaxError";
563
+ unknownError.originalResponse = responseBody;
564
+ Object.setPrototypeOf(unknownError, SyntaxError.prototype);
565
+ throw unknownError;
566
+ }
567
+ } catch (error) {
568
+ stopTimer({ error: true });
569
+ throw error;
570
+ }
571
+ }
572
+ function isResponseOk(response) {
573
+ const { statusCode } = response;
574
+ return statusCode ? statusCode >= 200 && statusCode < 300 : false;
575
+ }
576
+ function reshapeArtifactForPublicPolicy(data, isAuthenticated, actions) {
577
+ if (!isAuthenticated) {
578
+ const allowedActions = actions ? actions.split(",") : void 0;
579
+ const reshapeArtifact = (artifact) => ({
580
+ name: artifact.name,
581
+ version: artifact.version,
582
+ size: artifact.size,
583
+ author: artifact.author,
584
+ type: artifact.type,
585
+ supplyChainRisk: artifact.supplyChainRisk,
586
+ scorecards: artifact.scorecards,
587
+ topLevelAncestors: artifact.topLevelAncestors,
588
+ // Compact the alerts array to reduce response size for non-authenticated
589
+ // requests.
590
+ alerts: artifact.alerts?.filter((alert) => {
591
+ if (alert.severity === "low") {
592
+ return false;
593
+ }
594
+ if (allowedActions && alert.action && !allowedActions.includes(alert.action)) {
595
+ return false;
596
+ }
597
+ return true;
598
+ }).map((alert) => ({
599
+ type: alert.type,
600
+ severity: alert.severity,
601
+ key: alert.key
602
+ }))
603
+ });
604
+ if (data["artifacts"]) {
605
+ const artifacts = data["artifacts"];
606
+ return {
607
+ ...data,
608
+ artifacts: Array.isArray(artifacts) ? artifacts.map(reshapeArtifact) : artifacts
609
+ };
610
+ }
611
+ if (data["alerts"]) {
612
+ return reshapeArtifact(
613
+ data
614
+ );
615
+ }
616
+ }
617
+ return data;
618
+ }
619
+
620
+ // src/file-upload.ts
621
+ function createRequestBodyForFilepaths(filepaths, basePath) {
622
+ const requestBody = [];
623
+ for (const absPath of filepaths) {
624
+ const relPath = normalizePath2(path2.relative(basePath, absPath));
625
+ const filename = path2.basename(absPath);
626
+ let stream;
627
+ try {
628
+ stream = createReadStream(absPath, { highWaterMark: 1024 * 1024 });
629
+ } catch (error) {
630
+ const err = error;
631
+ let message = `Failed to read file: ${absPath}`;
632
+ if (err.code === "ENOENT") {
633
+ message += "\n\u2192 File does not exist. Check the file path and try again.";
634
+ } else if (err.code === "EACCES") {
635
+ message += `
636
+ \u2192 Permission denied. Run: chmod +r "${absPath}"`;
637
+ } else if (err.code === "EISDIR") {
638
+ message += "\n\u2192 Expected a file but found a directory.";
639
+ } else if (err.code) {
640
+ message += `
641
+ \u2192 Error code: ${err.code}`;
642
+ }
643
+ throw new Error(message, { cause: error });
644
+ }
645
+ requestBody.push([
646
+ `Content-Disposition: form-data; name="${relPath}"; filename="${filename}"\r
647
+ `,
648
+ "Content-Type: application/octet-stream\r\n\r\n",
649
+ stream
650
+ ]);
651
+ }
652
+ return requestBody;
653
+ }
654
+ function createRequestBodyForJson(jsonData, basename = "data.json") {
655
+ const ext = path2.extname(basename);
656
+ const name = path2.basename(basename, ext);
657
+ return [
658
+ `Content-Disposition: form-data; name="${name}"; filename="${basename}"\r
20
659
  Content-Type: application/json\r
21
660
  \r
22
- `,Pe.from(JSON.stringify(o),{highWaterMark:1024*1024}),`\r
23
- `]}async function v(o,t,e,s){return await new Promise(async(r,n)=>{let a=`NodeMultipartBoundary${Date.now()}`,i=`--${a}\r
24
- `,c=`--${a}--\r
25
- `,u=[...e.flatMap(p=>[i,...Array.isArray(p)?p:[p]]),c],l=new URL(t,o),h=P(o).request(l,{method:"POST",...s,headers:{...s?.headers,"Content-Type":`multipart/form-data; boundary=${a}`}});h.flushHeaders(),T(h).then(r,n);let g=!1;h.on("error",()=>g=!0),h.on("close",()=>g=!0);try{for(let p of u){if(g)break;if(typeof p=="string")h.write(p)||await W.once(h,"drain");else if(typeof p?.pipe=="function"){let f=p;try{for await(let S of f){if(g)break;h.write(S)||await W.once(h,"drain")}}catch(S){let w=S,E="Failed to read file during upload";throw w.code==="ENOENT"?E+=`
26
- \u2192 File was deleted during upload. Ensure files remain accessible during the upload process.`:w.code==="EACCES"?E+=`
27
- \u2192 Permission denied while reading file. Check file permissions.`:w.code&&(E+=`
28
- \u2192 Error code: ${w.code}`),new Error(E,{cause:S})}!g&&!h.write(`\r
29
- `)&&await W.once(h,"drain"),typeof p.destroy=="function"&&p.destroy()}else throw new TypeError('Expected "string" or "stream" type')}}catch(p){h.destroy(p),n(p)}finally{g||h.end()}})}import{existsSync as Oe,readFileSync as be}from"node:fs";import{join as Ie}from"node:path";import{memoize as C,once as Ae}from"@socketsecurity/lib/memoization";var b=Ae(()=>{try{let o=Ie(__dirname,"..","data","api-method-quota-and-permissions.json");if(!Oe(o))throw new Error(`Requirements file not found at: ${o}`);let t=be(o,"utf8");return JSON.parse(t)}catch(o){throw new Error("Failed to load SDK method requirements",{cause:o})}});function ue(o){return o.reduce((t,e)=>t+de(e),0)}function Ce(){let o=b(),t={};return Object.entries(o.api).forEach(([e,s])=>{t[e]={permissions:[...s.permissions],quota:s.quota}}),t}var $e=C(o=>{let e=b().api[o];if(!e)throw new Error(`Unknown SDK method: "${String(o)}"`);return{permissions:[...e.permissions],quota:e.quota}},{name:"getMethodRequirements"}),Ue=C(o=>{let t=b();return Object.entries(t.api).filter(([,e])=>o.some(s=>e.permissions.includes(s))).map(([e])=>e).sort()},{name:"getMethodsByPermissions"}),Fe=C(o=>{let t=b();return Object.entries(t.api).filter(([,e])=>e.quota===o).map(([e])=>e).sort()},{name:"getMethodsByQuotaCost"}),de=C(o=>{let e=b().api[o];if(!e)throw new Error(`Unknown SDK method: "${String(o)}"`);return e.quota},{name:"getQuotaCost"}),ve=C(()=>{let o=b(),t={};return Object.entries(o.api).forEach(([e,s])=>{let r=`${s.quota} units`;t[r]||(t[r]=[]),t[r].push(e)}),Object.keys(t).forEach(e=>{t[e]?.sort()}),t},{name:"getQuotaUsageSummary"}),xe=C(o=>{let e=b().api[o];if(!e)throw new Error(`Unknown SDK method: "${String(o)}"`);return[...e.permissions]},{name:"getRequiredPermissions"});function Le(o,t){let e=ue(t);return o>=e}import{createWriteStream as Me}from"node:fs";import H from"node:readline";import{createTtlCache as _e}from"@socketsecurity/lib/cache-with-ttl";import{UNKNOWN_ERROR as K}from"@socketsecurity/lib/constants/core";import{getAbortSignal as De}from"@socketsecurity/lib/constants/process";import{SOCKET_PUBLIC_API_TOKEN as le}from"@socketsecurity/lib/constants/socket";import{debugLog as ge,isDebugNs as qe}from"@socketsecurity/lib/debug";import{validateFiles as V}from"@socketsecurity/lib/fs";import{jsonParse as pe}from"@socketsecurity/lib/json";import{getOwn as Be,isObjectObject as me}from"@socketsecurity/lib/objects";import{pRetry as Ne}from"@socketsecurity/lib/promises";import{setMaxEventTargetListeners as je}from"@socketsecurity/lib/suppress-warnings";import{urlSearchParamAsBoolean as Ge}from"@socketsecurity/lib/url";var D=De(),Y=class{#a;#e;#i;#o;#t;#c;#u;constructor(t,e){if(typeof t!="string")throw new TypeError('"apiToken" is required and must be a string');let r=t.trim();if(!r)throw new Error('"apiToken" cannot be empty or whitespace-only');if(r.length>1024)throw new Error('"apiToken" exceeds maximum length of 1024 characters');let{agent:n,baseUrl:a="https://api.socket.dev/v0/",cache:i=!1,cacheTtl:c=300*1e3,onFileValidation:u,retries:l=ee,retryDelay:h=te,timeout:g=Z,userAgent:p}={__proto__:null,...e};if(g!==void 0&&(typeof g!="number"||g<N||g>B))throw new TypeError(`"timeout" must be a number between ${N} and ${B} milliseconds`);let f=n?Object.keys(n):[],S=n,w=f.length&&f.every(E=>G.has(E))?S.https||S.http||S.http2:n;this.#a=r,this.#e=Q(a),this.#i=i?_e({memoize:!0,prefix:"socket-sdk",ttl:c}):void 0,this.#o=u,this.#c=l,this.#u=h,this.#t={...w?{agent:w}:{},headers:{Authorization:`Basic ${btoa(`${r}:`)}`,"User-Agent":p??q},signal:D,...g?{timeout:g}:{}}}#p(t){if(!t)return;let e=Array.isArray(t)?t[0]:t;if(!e)return;let s=Number.parseInt(e,10);if(!Number.isNaN(s)&&s>=0)return s*1e3;let r=new Date(e);if(!Number.isNaN(r.getTime())){let n=r.getTime()-Date.now();if(n>0)return n}}async#r(t){let e=await Ne(t,{baseDelayMs:this.#u,onRetry:(s,r,n)=>{if(!(r instanceof R))return;let{statusCode:a}=r.response;if(a===401||a===403)throw r;if(a===429){let i=this.#p(r.response.headers["retry-after"]);if(i!==void 0)return i}},onRetryRethrow:!0,retries:this.#c});if(e===void 0)throw new Error("Request aborted");return e}async#d(t,e){return this.#i?await this.#i.getOrFetch(t,async()=>await this.#r(e)):await this.#r(e)}async*#m(t,e){let s;try{s=await this.#r(()=>this.#l(t,e))}catch(a){yield await this.#s(a);return}if(!s)throw new Error("Failed to get response from batch PURL request");let r=H.createInterface({input:s,crlfDelay:Number.POSITIVE_INFINITY,signal:D}),n=this.#a===le;for await(let a of r){let c=a.trim()?pe(a,{throws:!1}):null;me(c)&&(yield this.#n(n?M(c,!1,e?.actions):c))}}async#l(t,e){let s=P(this.#e).request(`${this.#e}purl?${k(e)}`,{method:"POST",...this.#t}).end(JSON.stringify(t)),r=await T(s);if(!O(r))throw new R(r);return r}#g(t){if(t instanceof SyntaxError){let r=t.originalResponse||"";return r||(r=t.message.match(/Invalid JSON response:\n([\s\S]*?)\n→/)?.[1]||""),{cause:`Please report this. JSON.parse threw an error over the following response: \`${(r.slice(0,100)||"").trim()}${r.length>100?"\u2026":""}\``,data:void 0,error:"Server returned invalid JSON",status:0,success:!1}}return{cause:(t?String(t).trim():"")||K,data:void 0,error:"API request failed",status:0,success:!1}}async#h(t){let e=[],s=0,r=50*1024*1024;for await(let n of t){if(s+=n.length,s>r)throw new Error("Response body exceeds maximum size limit");e.push(n)}return Buffer.concat(e).toString("utf8")}async#s(t){if(!(t instanceof R))throw new Error("Unexpected Socket API error",{cause:t});let{statusCode:e}=t.response;if(e&&e>=500)throw new Error(`Socket API server error (${e})`,{cause:t});let s=await L(t.response),r;try{let u=JSON.parse(s);if(typeof u?.error?.message=="string"&&(r=u.error.message,u.error.details)){let l=typeof u.error.details=="string"?u.error.details:JSON.stringify(u.error.details);r=`${r} - Details: ${l}`}}catch{r=s}let n=t.message??K,a=r?.trim();if(a&&!n.includes(a)){let u=t.response?.statusMessage;u&&n.includes(u)?n=n.replace(u,a):n=`${n}: ${a}`}let i;if(e===401)i=["\u2192 Authentication failed. API token is invalid or expired.","\u2192 Check: Your API token is correct and active.",`\u2192 Generate a new token at: ${re}`].join(`
30
- `);else if(e===403)i=["\u2192 Authorization failed. Insufficient permissions.","\u2192 Check: Your API token has required permissions for this operation.","\u2192 Check: You have access to the specified organization/repository.",`\u2192 Verify: Organization settings at ${oe}`].join(`
31
- `);else if(e===404)i=["\u2192 Resource not found.","\u2192 Verify: Package name, version, or resource ID is correct.","\u2192 Check: Organization or repository exists and is accessible."].join(`
32
- `);else if(e===429){let u=t.response.headers["retry-after"];i=["\u2192 Rate limit exceeded. Too many requests.",`\u2192 ${u?`Retry after ${u} seconds.`:"Wait before retrying."}`,"\u2192 Try: Implement exponential backoff or enable SDK retry option.",`\u2192 Contact support to increase rate limits: ${ne}`].join(`
33
- `)}else e===400?i=["\u2192 Bad request. Invalid parameters or request body.","\u2192 Check: All required parameters are provided and correctly formatted.","\u2192 Verify: Package URLs (PURLs) follow correct format."].join(`
34
- `):e===413&&(i=["\u2192 Payload too large. Request exceeds size limits.","\u2192 Try: Reduce the number of files or packages in a single request.","\u2192 Try: Use batch operations with smaller chunks."].join(`
35
- `));return{cause:i?[a,"",i].filter(Boolean).join(`
36
- `):r,data:void 0,error:n,status:e??0,success:!1}}#n(t){return{cause:void 0,data:t,error:void 0,status:200,success:!0}}async#f(t,e){return e==="response"?t:e==="text"?await this.#h(t):e==="json"?await d(t):t}async batchPackageFetch(t,e){let s;try{s=await this.#l(t,e)}catch(c){return await this.#s(c)}if(!s)throw new Error("Failed to get response from batch PURL request");let r=H.createInterface({input:s,crlfDelay:Number.POSITIVE_INFINITY,signal:D}),n=this.#a===le,a=[];for await(let c of r){let l=c.trim()?pe(c,{throws:!1}):null;me(l)&&a.push(n?M(l,!1,e?.actions):l)}let i=Ge(Be(e,"compact"));return this.#n(a)}async*batchPackageStream(t,e){let{chunkSize:s=100,concurrencyLimit:r=10,queryParams:n}={__proto__:null,...e},a=r*2;je(D,a);let{components:i}=t,{length:c}=i,u=[],l=0,h=()=>{if(l>=c)return;let p=this.#m({components:i.slice(l,l+s)},n);g(p),l+=s},g=p=>{let{promise:f,reject:S,resolve:w}=z();u.push({generator:p,promise:f}),p.next().then(E=>w({generator:p,iteratorResult:E}),S)};for(;u.length<r&&l<c;)h();for(;u.length>0;){let{generator:p,iteratorResult:f}=await Promise.race(u.map(w=>w.promise)),S=u.findIndex(w=>w.generator===p);S!==-1&&(u.splice(S,1),f.value&&(yield f.value),f.done?h():g(p))}}async createDependenciesSnapshot(t,e){let{pathsRelativeTo:s=".",queryParams:r}={__proto__:null,...e},n=I(s),a=U(t,n),{invalidPaths:i,validPaths:c}=V(a);if(this.#o&&i.length>0){let u=await this.#o(c,i,{operation:"createDependenciesSnapshot"});if(!u.shouldContinue)return{cause:u.errorCause,data:void 0,error:u.errorMessage??"File validation failed",status:400,success:!1}}if(!this.#o&&i.length>0){let u=i.slice(0,3).join(`
37
- - `),l=i.length>3?`
38
- ... and ${i.length-3} more`:"";console.warn(`Warning: ${i.length} files skipped (unreadable):
39
- - ${u}${l}
661
+ `,
662
+ Readable.from(JSON.stringify(jsonData), { highWaterMark: 1024 * 1024 }),
663
+ "\r\n"
664
+ ];
665
+ }
666
+ async function createUploadRequest(baseUrl, urlPath, requestBodyNoBoundaries, options) {
667
+ return await new Promise(async (pass, fail) => {
668
+ const boundary = `NodeMultipartBoundary${Date.now()}`;
669
+ const boundarySep = `--${boundary}\r
670
+ `;
671
+ const finalBoundary = `--${boundary}--\r
672
+ `;
673
+ const requestBody = [
674
+ ...requestBodyNoBoundaries.flatMap((part) => [
675
+ boundarySep,
676
+ /* c8 ignore next - Array.isArray branch for part is defensive coding for edge cases. */
677
+ ...Array.isArray(part) ? part : [part]
678
+ ]),
679
+ finalBoundary
680
+ ];
681
+ const url = new URL(urlPath, baseUrl);
682
+ const req = getHttpModule(baseUrl).request(url, {
683
+ method: "POST",
684
+ ...options,
685
+ headers: {
686
+ ...options?.headers,
687
+ "Content-Type": `multipart/form-data; boundary=${boundary}`
688
+ }
689
+ });
690
+ req.flushHeaders();
691
+ getResponse(req).then(pass, fail);
692
+ let aborted = false;
693
+ req.on("error", () => aborted = true);
694
+ req.on("close", () => aborted = true);
695
+ try {
696
+ for (const part of requestBody) {
697
+ if (aborted) {
698
+ break;
699
+ }
700
+ if (typeof part === "string") {
701
+ if (!req.write(part)) {
702
+ await events.once(req, "drain");
703
+ }
704
+ } else if (typeof part?.pipe === "function") {
705
+ const stream = part;
706
+ try {
707
+ for await (const chunk of stream) {
708
+ if (aborted) {
709
+ break;
710
+ }
711
+ if (!req.write(chunk)) {
712
+ await events.once(req, "drain");
713
+ }
714
+ }
715
+ } catch (streamError) {
716
+ const err = streamError;
717
+ let message = "Failed to read file during upload";
718
+ if (err.code === "ENOENT") {
719
+ message += "\n\u2192 File was deleted during upload. Ensure files remain accessible during the upload process.";
720
+ } else if (err.code === "EACCES") {
721
+ message += "\n\u2192 Permission denied while reading file. Check file permissions.";
722
+ } else if (err.code) {
723
+ message += `
724
+ \u2192 Error code: ${err.code}`;
725
+ }
726
+ throw new Error(message, { cause: streamError });
727
+ }
728
+ if (!aborted && !req.write("\r\n")) {
729
+ await events.once(req, "drain");
730
+ }
731
+ if (typeof part.destroy === "function") {
732
+ part.destroy();
733
+ }
734
+ } else {
735
+ throw new TypeError('Expected "string" or "stream" type');
736
+ }
737
+ }
738
+ } catch (e) {
739
+ req.destroy(e);
740
+ fail(e);
741
+ } finally {
742
+ if (!aborted) {
743
+ req.end();
744
+ }
745
+ }
746
+ });
747
+ }
748
+
749
+ // src/quota-utils.ts
750
+ import { existsSync, readFileSync } from "node:fs";
751
+ import { join } from "node:path";
752
+ import { memoize as memoize2, once } from "@socketsecurity/lib/memoization";
753
+ var loadRequirements = once(() => {
754
+ try {
755
+ const requirementsPath = join(
756
+ __dirname,
757
+ "..",
758
+ "data",
759
+ "api-method-quota-and-permissions.json"
760
+ );
761
+ if (!existsSync(requirementsPath)) {
762
+ throw new Error(`Requirements file not found at: ${requirementsPath}`);
763
+ }
764
+ const data = readFileSync(requirementsPath, "utf8");
765
+ return JSON.parse(data);
766
+ } catch (e) {
767
+ throw new Error("Failed to load SDK method requirements", { cause: e });
768
+ }
769
+ });
770
+ function calculateTotalQuotaCost(methodNames) {
771
+ return methodNames.reduce((total, methodName) => {
772
+ return total + getQuotaCost(methodName);
773
+ }, 0);
774
+ }
775
+ function getAllMethodRequirements() {
776
+ const reqs = loadRequirements();
777
+ const result = {};
778
+ Object.entries(reqs.api).forEach(([methodName, requirement]) => {
779
+ result[methodName] = {
780
+ permissions: [...requirement.permissions],
781
+ quota: requirement.quota
782
+ };
783
+ });
784
+ return result;
785
+ }
786
+ var getMethodRequirements = memoize2(
787
+ (methodName) => {
788
+ const reqs = loadRequirements();
789
+ const requirement = reqs.api[methodName];
790
+ if (!requirement) {
791
+ throw new Error(`Unknown SDK method: "${String(methodName)}"`);
792
+ }
793
+ return {
794
+ permissions: [...requirement.permissions],
795
+ quota: requirement.quota
796
+ };
797
+ },
798
+ { name: "getMethodRequirements" }
799
+ );
800
+ var getMethodsByPermissions = memoize2(
801
+ (permissions) => {
802
+ const reqs = loadRequirements();
803
+ return Object.entries(reqs.api).filter(([, requirement]) => {
804
+ return permissions.some(
805
+ (permission) => requirement.permissions.includes(permission)
806
+ );
807
+ }).map(([methodName]) => methodName).sort();
808
+ },
809
+ { name: "getMethodsByPermissions" }
810
+ );
811
+ var getMethodsByQuotaCost = memoize2(
812
+ (quotaCost) => {
813
+ const reqs = loadRequirements();
814
+ return Object.entries(reqs.api).filter(([, requirement]) => requirement.quota === quotaCost).map(([methodName]) => methodName).sort();
815
+ },
816
+ { name: "getMethodsByQuotaCost" }
817
+ );
818
+ var getQuotaCost = memoize2(
819
+ (methodName) => {
820
+ const reqs = loadRequirements();
821
+ const requirement = reqs.api[methodName];
822
+ if (!requirement) {
823
+ throw new Error(`Unknown SDK method: "${String(methodName)}"`);
824
+ }
825
+ return requirement.quota;
826
+ },
827
+ { name: "getQuotaCost" }
828
+ );
829
+ var getQuotaUsageSummary = memoize2(
830
+ () => {
831
+ const reqs = loadRequirements();
832
+ const summary = {};
833
+ Object.entries(reqs.api).forEach(([methodName, requirement]) => {
834
+ const costKey = `${requirement.quota} units`;
835
+ if (!summary[costKey]) {
836
+ summary[costKey] = [];
837
+ }
838
+ summary[costKey].push(methodName);
839
+ });
840
+ Object.keys(summary).forEach((costKey) => {
841
+ summary[costKey]?.sort();
842
+ });
843
+ return summary;
844
+ },
845
+ { name: "getQuotaUsageSummary" }
846
+ );
847
+ var getRequiredPermissions = memoize2(
848
+ (methodName) => {
849
+ const reqs = loadRequirements();
850
+ const requirement = reqs.api[methodName];
851
+ if (!requirement) {
852
+ throw new Error(`Unknown SDK method: "${String(methodName)}"`);
853
+ }
854
+ return [...requirement.permissions];
855
+ },
856
+ { name: "getRequiredPermissions" }
857
+ );
858
+ function hasQuotaForMethods(availableQuota, methodNames) {
859
+ const totalCost = calculateTotalQuotaCost(methodNames);
860
+ return availableQuota >= totalCost;
861
+ }
862
+
863
+ // src/socket-sdk-class.ts
864
+ import { createWriteStream } from "node:fs";
865
+ import readline from "node:readline";
866
+ import { createTtlCache } from "@socketsecurity/lib/cache-with-ttl";
867
+ import { UNKNOWN_ERROR } from "@socketsecurity/lib/constants/core";
868
+ import { getAbortSignal } from "@socketsecurity/lib/constants/process";
869
+ import { SOCKET_PUBLIC_API_TOKEN } from "@socketsecurity/lib/constants/socket";
870
+ import { debugLog as debugLog2, isDebugNs } from "@socketsecurity/lib/debug";
871
+ import { validateFiles } from "@socketsecurity/lib/fs";
872
+ import { jsonParse as jsonParse2 } from "@socketsecurity/lib/json";
873
+ import { getOwn, isObjectObject } from "@socketsecurity/lib/objects";
874
+ import { pRetry } from "@socketsecurity/lib/promises";
875
+ import { setMaxEventTargetListeners } from "@socketsecurity/lib/suppress-warnings";
876
+ import { urlSearchParamAsBoolean } from "@socketsecurity/lib/url";
877
+ var abortSignal = getAbortSignal();
878
+ var SocketSdk = class {
879
+ #apiToken;
880
+ #baseUrl;
881
+ #cache;
882
+ #onFileValidation;
883
+ #reqOptions;
884
+ #retries;
885
+ #retryDelay;
886
+ /**
887
+ * Initialize Socket SDK with API token and configuration options.
888
+ * Sets up authentication, base URL, HTTP client options, retry behavior, and caching.
889
+ */
890
+ constructor(apiToken, options) {
891
+ const MAX_API_TOKEN_LENGTH = 1024;
892
+ if (typeof apiToken !== "string") {
893
+ throw new TypeError('"apiToken" is required and must be a string');
894
+ }
895
+ const trimmedToken = apiToken.trim();
896
+ if (!trimmedToken) {
897
+ throw new Error('"apiToken" cannot be empty or whitespace-only');
898
+ }
899
+ if (trimmedToken.length > MAX_API_TOKEN_LENGTH) {
900
+ throw new Error(
901
+ `"apiToken" exceeds maximum length of ${MAX_API_TOKEN_LENGTH} characters`
902
+ );
903
+ }
904
+ const {
905
+ agent: agentOrObj,
906
+ baseUrl = "https://api.socket.dev/v0/",
907
+ cache = false,
908
+ cacheTtl = 5 * 60 * 1e3,
909
+ onFileValidation,
910
+ retries = DEFAULT_RETRIES,
911
+ retryDelay = DEFAULT_RETRY_DELAY,
912
+ timeout = DEFAULT_HTTP_TIMEOUT,
913
+ userAgent
914
+ } = { __proto__: null, ...options };
915
+ if (timeout !== void 0) {
916
+ if (typeof timeout !== "number" || timeout < MIN_HTTP_TIMEOUT || timeout > MAX_HTTP_TIMEOUT) {
917
+ throw new TypeError(
918
+ `"timeout" must be a number between ${MIN_HTTP_TIMEOUT} and ${MAX_HTTP_TIMEOUT} milliseconds`
919
+ );
920
+ }
921
+ }
922
+ const agentKeys = agentOrObj ? Object.keys(agentOrObj) : [];
923
+ const agentAsGotOptions = agentOrObj;
924
+ const agent = agentKeys.length && agentKeys.every((k) => httpAgentNames.has(k)) ? (
925
+ /* c8 ignore next 3 - Got-style agent options compatibility layer */
926
+ agentAsGotOptions.https || agentAsGotOptions.http || agentAsGotOptions.http2
927
+ ) : agentOrObj;
928
+ this.#apiToken = trimmedToken;
929
+ this.#baseUrl = normalizeBaseUrl(baseUrl);
930
+ this.#cache = cache ? createTtlCache({
931
+ memoize: true,
932
+ prefix: "socket-sdk",
933
+ ttl: cacheTtl
934
+ }) : (
935
+ /* c8 ignore next - cache disabled by default */
936
+ void 0
937
+ );
938
+ this.#onFileValidation = onFileValidation;
939
+ this.#retries = retries;
940
+ this.#retryDelay = retryDelay;
941
+ this.#reqOptions = {
942
+ ...agent ? { agent } : {},
943
+ headers: {
944
+ Authorization: `Basic ${btoa(`${trimmedToken}:`)}`,
945
+ "User-Agent": userAgent ?? DEFAULT_USER_AGENT
946
+ },
947
+ signal: abortSignal,
948
+ /* c8 ignore next - Optional timeout parameter, tested implicitly through method calls */
949
+ ...timeout ? { timeout } : {}
950
+ };
951
+ }
952
+ /**
953
+ * Parse Retry-After header value and return delay in milliseconds.
954
+ * Supports both delay-seconds (integer) and HTTP-date formats.
955
+ */
956
+ #parseRetryAfter(retryAfterValue) {
957
+ if (!retryAfterValue) {
958
+ return void 0;
959
+ }
960
+ const value = Array.isArray(retryAfterValue) ? retryAfterValue[0] : retryAfterValue;
961
+ if (!value) {
962
+ return void 0;
963
+ }
964
+ const seconds = Number.parseInt(value, 10);
965
+ if (!Number.isNaN(seconds) && seconds >= 0) {
966
+ return seconds * 1e3;
967
+ }
968
+ const date = new Date(value);
969
+ if (!Number.isNaN(date.getTime())) {
970
+ const delayMs = date.getTime() - Date.now();
971
+ if (delayMs > 0) {
972
+ return delayMs;
973
+ }
974
+ }
975
+ return void 0;
976
+ }
977
+ /**
978
+ * Execute an HTTP request with retry logic.
979
+ * Internal method for wrapping HTTP operations with exponential backoff.
980
+ */
981
+ async #executeWithRetry(operation) {
982
+ const result = await pRetry(operation, {
983
+ baseDelayMs: this.#retryDelay,
984
+ onRetry: (_attempt, error, _delay) => {
985
+ if (!(error instanceof ResponseError)) {
986
+ return void 0;
987
+ }
988
+ const { statusCode } = error.response;
989
+ if (statusCode === 401 || statusCode === 403) {
990
+ throw error;
991
+ }
992
+ if (statusCode === 429) {
993
+ const retryAfter = this.#parseRetryAfter(
994
+ error.response.headers["retry-after"]
995
+ );
996
+ if (retryAfter !== void 0) {
997
+ return retryAfter;
998
+ }
999
+ }
1000
+ return void 0;
1001
+ },
1002
+ onRetryRethrow: true,
1003
+ retries: this.#retries
1004
+ });
1005
+ if (result === void 0) {
1006
+ throw new Error("Request aborted");
1007
+ }
1008
+ return result;
1009
+ }
1010
+ /**
1011
+ * Execute a GET request with optional caching.
1012
+ * Internal method for handling cached GET requests with retry logic.
1013
+ */
1014
+ async #getCached(cacheKey, fetcher) {
1015
+ if (!this.#cache) {
1016
+ return await this.#executeWithRetry(fetcher);
1017
+ }
1018
+ return await this.#cache.getOrFetch(cacheKey, async () => {
1019
+ return await this.#executeWithRetry(fetcher);
1020
+ });
1021
+ }
1022
+ /**
1023
+ * Create async generator for streaming batch package URL processing.
1024
+ * Internal method for handling chunked PURL responses with error handling.
1025
+ */
1026
+ async *#createBatchPurlGenerator(componentsObj, queryParams) {
1027
+ let res;
1028
+ try {
1029
+ res = await this.#executeWithRetry(
1030
+ () => this.#createBatchPurlRequest(componentsObj, queryParams)
1031
+ );
1032
+ } catch (e) {
1033
+ yield await this.#handleApiError(e);
1034
+ return;
1035
+ }
1036
+ if (!res) {
1037
+ throw new Error("Failed to get response from batch PURL request");
1038
+ }
1039
+ const rli = readline.createInterface({
1040
+ input: res,
1041
+ crlfDelay: Number.POSITIVE_INFINITY,
1042
+ signal: abortSignal
1043
+ });
1044
+ const isPublicToken = this.#apiToken === SOCKET_PUBLIC_API_TOKEN;
1045
+ for await (const line of rli) {
1046
+ const trimmed = line.trim();
1047
+ const artifact = trimmed ? jsonParse2(line, { throws: false }) : (
1048
+ /* c8 ignore next - Empty line handling in batch streaming response parsing. */
1049
+ null
1050
+ );
1051
+ if (isObjectObject(artifact)) {
1052
+ yield this.#handleApiSuccess(
1053
+ /* c8 ignore next 7 - Public token artifact reshaping branch for policy compliance. */
1054
+ isPublicToken ? reshapeArtifactForPublicPolicy(
1055
+ artifact,
1056
+ false,
1057
+ queryParams?.["actions"]
1058
+ ) : artifact
1059
+ );
1060
+ }
1061
+ }
1062
+ }
1063
+ /**
1064
+ * Create HTTP request for batch package URL processing.
1065
+ * Internal method for handling PURL batch API calls with retry logic.
1066
+ */
1067
+ async #createBatchPurlRequest(componentsObj, queryParams) {
1068
+ const req = getHttpModule(this.#baseUrl).request(`${this.#baseUrl}purl?${queryToSearchParams(queryParams)}`, {
1069
+ method: "POST",
1070
+ ...this.#reqOptions
1071
+ }).end(JSON.stringify(componentsObj));
1072
+ const response = await getResponse(req);
1073
+ if (!isResponseOk(response)) {
1074
+ throw new ResponseError(response);
1075
+ }
1076
+ return response;
1077
+ }
1078
+ /**
1079
+ * Create standardized error result from query operation exceptions.
1080
+ * Internal error handling for non-throwing query API methods.
1081
+ */
1082
+ #createQueryErrorResult(e) {
1083
+ if (e instanceof SyntaxError) {
1084
+ const enhancedError = e;
1085
+ let responseText = enhancedError.originalResponse || "";
1086
+ if (!responseText) {
1087
+ const match = e.message.match(/Invalid JSON response:\n([\s\S]*?)\n→/);
1088
+ responseText = match?.[1] || "";
1089
+ }
1090
+ const preview = responseText.slice(0, 100) || "";
1091
+ return {
1092
+ cause: `Please report this. JSON.parse threw an error over the following response: \`${preview.trim()}${responseText.length > 100 ? "\u2026" : ""}\``,
1093
+ data: void 0,
1094
+ error: "Server returned invalid JSON",
1095
+ status: 0,
1096
+ success: false
1097
+ };
1098
+ }
1099
+ const errStr = e ? String(e).trim() : "";
1100
+ return {
1101
+ cause: errStr || UNKNOWN_ERROR,
1102
+ data: void 0,
1103
+ error: "API request failed",
1104
+ status: 0,
1105
+ success: false
1106
+ };
1107
+ }
1108
+ /**
1109
+ * Extract text content from HTTP response stream.
1110
+ * Internal method with size limits to prevent memory exhaustion.
1111
+ */
1112
+ /* c8 ignore start - unused utility method reserved for future text response handling */
1113
+ async #getResponseText(response) {
1114
+ const chunks = [];
1115
+ let size = 0;
1116
+ const MAX = 50 * 1024 * 1024;
1117
+ for await (const chunk of response) {
1118
+ size += chunk.length;
1119
+ if (size > MAX) {
1120
+ throw new Error("Response body exceeds maximum size limit");
1121
+ }
1122
+ chunks.push(chunk);
1123
+ }
1124
+ return Buffer.concat(chunks).toString("utf8");
1125
+ }
1126
+ /* c8 ignore stop */
1127
+ /**
1128
+ * Handle API error responses and convert to standardized error result.
1129
+ * Internal error handling with status code analysis and message formatting.
1130
+ */
1131
+ async #handleApiError(error) {
1132
+ if (!(error instanceof ResponseError)) {
1133
+ throw new Error("Unexpected Socket API error", {
1134
+ cause: error
1135
+ });
1136
+ }
1137
+ const { statusCode } = error.response;
1138
+ if (statusCode && statusCode >= 500) {
1139
+ throw new Error(`Socket API server error (${statusCode})`, {
1140
+ cause: error
1141
+ });
1142
+ }
1143
+ const bodyStr = await getErrorResponseBody(error.response);
1144
+ let body;
1145
+ try {
1146
+ const parsed = JSON.parse(bodyStr);
1147
+ if (typeof parsed?.error?.message === "string") {
1148
+ body = parsed.error.message;
1149
+ if (parsed.error.details) {
1150
+ const detailsStr = typeof parsed.error.details === "string" ? parsed.error.details : JSON.stringify(parsed.error.details);
1151
+ body = `${body} - Details: ${detailsStr}`;
1152
+ }
1153
+ }
1154
+ } catch {
1155
+ body = bodyStr;
1156
+ }
1157
+ let errorMessage = error.message ?? /* c8 ignore next - fallback for missing error message */
1158
+ UNKNOWN_ERROR;
1159
+ const trimmedBody = body?.trim();
1160
+ if (trimmedBody && !errorMessage.includes(trimmedBody)) {
1161
+ const statusMessage = error.response?.statusMessage;
1162
+ if (statusMessage && errorMessage.includes(statusMessage)) {
1163
+ errorMessage = errorMessage.replace(statusMessage, trimmedBody);
1164
+ } else {
1165
+ errorMessage = `${errorMessage}: ${trimmedBody}`;
1166
+ }
1167
+ }
1168
+ let actionableGuidance;
1169
+ if (statusCode === 401) {
1170
+ actionableGuidance = [
1171
+ "\u2192 Authentication failed. API token is invalid or expired.",
1172
+ "\u2192 Check: Your API token is correct and active.",
1173
+ `\u2192 Generate a new token at: ${SOCKET_API_TOKENS_URL}`
1174
+ ].join("\n");
1175
+ } else if (statusCode === 403) {
1176
+ actionableGuidance = [
1177
+ "\u2192 Authorization failed. Insufficient permissions.",
1178
+ "\u2192 Check: Your API token has required permissions for this operation.",
1179
+ "\u2192 Check: You have access to the specified organization/repository.",
1180
+ `\u2192 Verify: Organization settings at ${SOCKET_DASHBOARD_URL}`
1181
+ ].join("\n");
1182
+ } else if (statusCode === 404) {
1183
+ actionableGuidance = [
1184
+ "\u2192 Resource not found.",
1185
+ "\u2192 Verify: Package name, version, or resource ID is correct.",
1186
+ "\u2192 Check: Organization or repository exists and is accessible."
1187
+ ].join("\n");
1188
+ } else if (statusCode === 429) {
1189
+ const retryAfter = error.response.headers["retry-after"];
1190
+ const retryMsg = retryAfter ? `Retry after ${retryAfter} seconds.` : "Wait before retrying.";
1191
+ actionableGuidance = [
1192
+ "\u2192 Rate limit exceeded. Too many requests.",
1193
+ `\u2192 ${retryMsg}`,
1194
+ "\u2192 Try: Implement exponential backoff or enable SDK retry option.",
1195
+ `\u2192 Contact support to increase rate limits: ${SOCKET_CONTACT_URL}`
1196
+ ].join("\n");
1197
+ } else if (statusCode === 400) {
1198
+ actionableGuidance = [
1199
+ "\u2192 Bad request. Invalid parameters or request body.",
1200
+ "\u2192 Check: All required parameters are provided and correctly formatted.",
1201
+ "\u2192 Verify: Package URLs (PURLs) follow correct format."
1202
+ ].join("\n");
1203
+ } else if (statusCode === 413) {
1204
+ actionableGuidance = [
1205
+ "\u2192 Payload too large. Request exceeds size limits.",
1206
+ "\u2192 Try: Reduce the number of files or packages in a single request.",
1207
+ "\u2192 Try: Use batch operations with smaller chunks."
1208
+ ].join("\n");
1209
+ }
1210
+ const causeWithGuidance = actionableGuidance ? [trimmedBody, "", actionableGuidance].filter(Boolean).join("\n") : body;
1211
+ return {
1212
+ cause: causeWithGuidance,
1213
+ data: void 0,
1214
+ error: errorMessage,
1215
+ /* c8 ignore next - fallback for missing status code in edge cases. */
1216
+ status: statusCode ?? 0,
1217
+ success: false
1218
+ };
1219
+ }
1220
+ /**
1221
+ * Handle successful API responses and convert to standardized success result.
1222
+ * Internal success handling with consistent response formatting.
1223
+ */
1224
+ #handleApiSuccess(data) {
1225
+ return {
1226
+ cause: void 0,
1227
+ data,
1228
+ error: void 0,
1229
+ // Use generic 200 OK status for all successful API responses.
1230
+ status: 200,
1231
+ success: true
1232
+ };
1233
+ }
1234
+ /**
1235
+ * Handle query API response data based on requested response type.
1236
+ * Internal method for processing different response formats (json, text, response).
1237
+ */
1238
+ async #handleQueryResponseData(response, responseType) {
1239
+ if (responseType === "response") {
1240
+ return response;
1241
+ }
1242
+ if (responseType === "text") {
1243
+ return await this.#getResponseText(response);
1244
+ }
1245
+ if (responseType === "json") {
1246
+ return await getResponseJson(response);
1247
+ }
1248
+ return response;
1249
+ }
1250
+ /**
1251
+ * Fetch package analysis data for multiple packages in a single batch request.
1252
+ * Returns all results at once after processing is complete.
1253
+ *
1254
+ * @throws {Error} When server returns 5xx status codes
1255
+ */
1256
+ async batchPackageFetch(componentsObj, queryParams) {
1257
+ let res;
1258
+ try {
1259
+ res = await this.#createBatchPurlRequest(componentsObj, queryParams);
1260
+ } catch (e) {
1261
+ return await this.#handleApiError(e);
1262
+ }
1263
+ if (!res) {
1264
+ throw new Error("Failed to get response from batch PURL request");
1265
+ }
1266
+ const rli = readline.createInterface({
1267
+ input: res,
1268
+ crlfDelay: Number.POSITIVE_INFINITY,
1269
+ signal: abortSignal
1270
+ });
1271
+ const isPublicToken = this.#apiToken === SOCKET_PUBLIC_API_TOKEN;
1272
+ const results = [];
1273
+ for await (const line of rli) {
1274
+ const trimmed = line.trim();
1275
+ const artifact = trimmed ? jsonParse2(line, { throws: false }) : (
1276
+ /* c8 ignore next - Empty line handling in batch parsing. */
1277
+ null
1278
+ );
1279
+ if (isObjectObject(artifact)) {
1280
+ results.push(
1281
+ /* c8 ignore next 7 - Public token artifact reshaping for policy compliance. */
1282
+ isPublicToken ? reshapeArtifactForPublicPolicy(
1283
+ artifact,
1284
+ false,
1285
+ queryParams?.["actions"]
1286
+ ) : artifact
1287
+ );
1288
+ }
1289
+ }
1290
+ const compact = urlSearchParamAsBoolean(
1291
+ getOwn(queryParams, "compact")
1292
+ );
1293
+ return this.#handleApiSuccess(
1294
+ compact ? results : results
1295
+ );
1296
+ }
1297
+ /**
1298
+ * Stream package analysis data for multiple packages with chunked processing and concurrency control.
1299
+ * Returns results as they become available via async generator.
1300
+ *
1301
+ * @throws {Error} When server returns 5xx status codes
1302
+ */
1303
+ async *batchPackageStream(componentsObj, options) {
1304
+ const {
1305
+ chunkSize = 100,
1306
+ concurrencyLimit = 10,
1307
+ queryParams
1308
+ } = {
1309
+ __proto__: null,
1310
+ ...options
1311
+ };
1312
+ const neededMaxListeners = concurrencyLimit * 2;
1313
+ setMaxEventTargetListeners(abortSignal, neededMaxListeners);
1314
+ const { components } = componentsObj;
1315
+ const { length: componentsCount } = components;
1316
+ const running = [];
1317
+ let index = 0;
1318
+ const enqueueGen = () => {
1319
+ if (index >= componentsCount) {
1320
+ return;
1321
+ }
1322
+ const generator = this.#createBatchPurlGenerator(
1323
+ {
1324
+ // Chunk components.
1325
+ components: components.slice(index, index + chunkSize)
1326
+ },
1327
+ queryParams
1328
+ );
1329
+ continueGen(generator);
1330
+ index += chunkSize;
1331
+ };
1332
+ const continueGen = (generator) => {
1333
+ const {
1334
+ promise,
1335
+ reject: rejectFn,
1336
+ resolve: resolveFn
1337
+ } = promiseWithResolvers();
1338
+ running.push({
1339
+ generator,
1340
+ promise
1341
+ });
1342
+ void generator.next().then(
1343
+ (iteratorResult) => resolveFn({ generator, iteratorResult }),
1344
+ rejectFn
1345
+ );
1346
+ };
1347
+ while (running.length < concurrencyLimit && index < componentsCount) {
1348
+ enqueueGen();
1349
+ }
1350
+ while (running.length > 0) {
1351
+ const { generator, iteratorResult } = await Promise.race(
1352
+ running.map((entry) => entry.promise)
1353
+ );
1354
+ const index2 = running.findIndex((entry) => entry.generator === generator);
1355
+ if (index2 === -1) {
1356
+ continue;
1357
+ }
1358
+ running.splice(index2, 1);
1359
+ if (iteratorResult.value) {
1360
+ yield iteratorResult.value;
1361
+ }
1362
+ if (iteratorResult.done) {
1363
+ enqueueGen();
1364
+ } else {
1365
+ continueGen(generator);
1366
+ }
1367
+ }
1368
+ }
1369
+ /**
1370
+ * Create a snapshot of project dependencies by uploading manifest files.
1371
+ * Analyzes dependency files to generate a comprehensive security report.
1372
+ *
1373
+ * @throws {Error} When server returns 5xx status codes
1374
+ */
1375
+ async createDependenciesSnapshot(filepaths, options) {
1376
+ const { pathsRelativeTo = ".", queryParams } = {
1377
+ __proto__: null,
1378
+ ...options
1379
+ };
1380
+ const basePath = resolveBasePath(pathsRelativeTo);
1381
+ const absFilepaths = resolveAbsPaths(filepaths, basePath);
1382
+ const { invalidPaths, validPaths } = validateFiles(absFilepaths);
1383
+ if (this.#onFileValidation && invalidPaths.length > 0) {
1384
+ const result = await this.#onFileValidation(validPaths, invalidPaths, {
1385
+ operation: "createDependenciesSnapshot"
1386
+ });
1387
+ if (!result.shouldContinue) {
1388
+ return {
1389
+ cause: result.errorCause,
1390
+ data: void 0,
1391
+ error: result.errorMessage ?? "File validation failed",
1392
+ status: 400,
1393
+ success: false
1394
+ };
1395
+ }
1396
+ }
1397
+ if (!this.#onFileValidation && invalidPaths.length > 0) {
1398
+ const samplePaths = invalidPaths.slice(0, 3).join("\n - ");
1399
+ const remaining = invalidPaths.length > 3 ? `
1400
+ ... and ${invalidPaths.length - 3} more` : "";
1401
+ console.warn(
1402
+ `Warning: ${invalidPaths.length} files skipped (unreadable):
1403
+ - ${samplePaths}${remaining}
40
1404
  \u2192 This may occur with Yarn Berry PnP or pnpm symlinks.
41
- \u2192 Try: Run installation command to ensure files are accessible.`)}if(c.length===0){let u=i.slice(0,5).join(`
42
- - `),l=i.length>5?`
43
- ... and ${i.length-5} more`:"";return{cause:[`All ${i.length} files failed validation:`,` - ${u}${l}`,"","\u2192 Common causes:"," \u2022 Yarn Berry PnP virtual filesystem (files are not on disk)"," \u2022 pnpm symlinks pointing to inaccessible locations"," \u2022 Incorrect file permissions"," \u2022 Files were deleted after discovery","","\u2192 Solutions:"," \u2022 Yarn Berry: Use `nodeLinker: node-modules` in .yarnrc.yml"," \u2022 pnpm: Use `node-linker=hoisted` in .npmrc"," \u2022 Check file permissions with: ls -la <file>"," \u2022 Run package manager install command"].join(`
44
- `),data:void 0,error:"No readable manifest files found",status:400,success:!1}}try{let u=await this.#r(async()=>await d(await v(this.#e,`dependencies/upload?${k(r)}`,F(c,n),this.#t)));return this.#n(u)}catch(u){return await this.#s(u)}}async createOrgDiffScanFromIds(t,e){try{let s=await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/diff-scans?${k(e)}`,{},this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async createFullScan(t,e,s){let{pathsRelativeTo:r=".",...n}={__proto__:null,...s},a=I(r),i=U(e,a),{invalidPaths:c,validPaths:u}=V(i);if(this.#o&&c.length>0){let l=await this.#o(u,c,{operation:"createOrgFullScan",orgSlug:t});if(!l.shouldContinue)return{cause:l.errorCause,data:void 0,error:l.errorMessage??"File validation failed",status:400,success:!1}}if(!this.#o&&c.length>0){let l=c.slice(0,3).join(`
45
- - `),h=c.length>3?`
46
- ... and ${c.length-3} more`:"";console.warn(`Warning: ${c.length} files skipped (unreadable):
47
- - ${l}${h}
1405
+ \u2192 Try: Run installation command to ensure files are accessible.`
1406
+ );
1407
+ }
1408
+ if (validPaths.length === 0) {
1409
+ const samplePaths = invalidPaths.slice(0, 5).join("\n - ");
1410
+ const remaining = invalidPaths.length > 5 ? `
1411
+ ... and ${invalidPaths.length - 5} more` : "";
1412
+ return {
1413
+ cause: [
1414
+ `All ${invalidPaths.length} files failed validation:`,
1415
+ ` - ${samplePaths}${remaining}`,
1416
+ "",
1417
+ "\u2192 Common causes:",
1418
+ " \u2022 Yarn Berry PnP virtual filesystem (files are not on disk)",
1419
+ " \u2022 pnpm symlinks pointing to inaccessible locations",
1420
+ " \u2022 Incorrect file permissions",
1421
+ " \u2022 Files were deleted after discovery",
1422
+ "",
1423
+ "\u2192 Solutions:",
1424
+ " \u2022 Yarn Berry: Use `nodeLinker: node-modules` in .yarnrc.yml",
1425
+ " \u2022 pnpm: Use `node-linker=hoisted` in .npmrc",
1426
+ " \u2022 Check file permissions with: ls -la <file>",
1427
+ " \u2022 Run package manager install command"
1428
+ ].join("\n"),
1429
+ data: void 0,
1430
+ error: "No readable manifest files found",
1431
+ status: 400,
1432
+ success: false
1433
+ };
1434
+ }
1435
+ try {
1436
+ const data = await this.#executeWithRetry(
1437
+ async () => await getResponseJson(
1438
+ await createUploadRequest(
1439
+ this.#baseUrl,
1440
+ `dependencies/upload?${queryToSearchParams(queryParams)}`,
1441
+ createRequestBodyForFilepaths(validPaths, basePath),
1442
+ this.#reqOptions
1443
+ )
1444
+ )
1445
+ );
1446
+ return this.#handleApiSuccess(data);
1447
+ } catch (e) {
1448
+ return await this.#handleApiError(e);
1449
+ }
1450
+ }
1451
+ /**
1452
+ * Create a diff scan from two full scan IDs.
1453
+ * Compares two existing full scans to identify changes.
1454
+ *
1455
+ * @throws {Error} When server returns 5xx status codes
1456
+ */
1457
+ async createOrgDiffScanFromIds(orgSlug, queryParams) {
1458
+ try {
1459
+ const data = await this.#executeWithRetry(
1460
+ async () => await getResponseJson(
1461
+ await createRequestWithJson(
1462
+ "POST",
1463
+ this.#baseUrl,
1464
+ `orgs/${encodeURIComponent(orgSlug)}/diff-scans?${queryToSearchParams(queryParams)}`,
1465
+ {},
1466
+ this.#reqOptions
1467
+ )
1468
+ )
1469
+ );
1470
+ return this.#handleApiSuccess(data);
1471
+ } catch (e) {
1472
+ return await this.#handleApiError(e);
1473
+ }
1474
+ }
1475
+ /**
1476
+ * Create a full security scan for an organization.
1477
+ *
1478
+ * Uploads project manifest files and initiates full security analysis.
1479
+ * Returns scan metadata with guaranteed required fields.
1480
+ *
1481
+ * @param orgSlug - Organization identifier
1482
+ * @param filepaths - Array of file paths to upload (package.json, package-lock.json, etc.)
1483
+ * @param options - Scan configuration including repository, branch, and commit details
1484
+ * @returns Full scan metadata including ID and URLs
1485
+ *
1486
+ * @example
1487
+ * ```typescript
1488
+ * const result = await sdk.createFullScan('my-org',
1489
+ * ['package.json', 'package-lock.json'],
1490
+ * {
1491
+ * repo: 'my-repo',
1492
+ * branch: 'main',
1493
+ * commit_message: 'Update dependencies',
1494
+ * commit_hash: 'abc123',
1495
+ * pathsRelativeTo: './my-project'
1496
+ * }
1497
+ * )
1498
+ *
1499
+ * if (result.success) {
1500
+ * console.log('Scan ID:', result.data.id)
1501
+ * console.log('Report URL:', result.data.html_report_url)
1502
+ * }
1503
+ * ```
1504
+ *
1505
+ * @see https://docs.socket.dev/reference/createorgfullscan
1506
+ * @apiEndpoint POST /orgs/{org_slug}/full-scans
1507
+ * @quota 1 unit
1508
+ * @scopes full-scans:create
1509
+ * @throws {Error} When server returns 5xx status codes
1510
+ */
1511
+ async createFullScan(orgSlug, filepaths, options) {
1512
+ const { pathsRelativeTo = ".", ...queryParams } = {
1513
+ __proto__: null,
1514
+ ...options
1515
+ };
1516
+ const basePath = resolveBasePath(pathsRelativeTo);
1517
+ const absFilepaths = resolveAbsPaths(filepaths, basePath);
1518
+ const { invalidPaths, validPaths } = validateFiles(absFilepaths);
1519
+ if (this.#onFileValidation && invalidPaths.length > 0) {
1520
+ const result = await this.#onFileValidation(validPaths, invalidPaths, {
1521
+ operation: "createOrgFullScan",
1522
+ orgSlug
1523
+ });
1524
+ if (!result.shouldContinue) {
1525
+ return {
1526
+ cause: result.errorCause,
1527
+ data: void 0,
1528
+ error: result.errorMessage ?? "File validation failed",
1529
+ status: 400,
1530
+ success: false
1531
+ };
1532
+ }
1533
+ }
1534
+ if (!this.#onFileValidation && invalidPaths.length > 0) {
1535
+ const samplePaths = invalidPaths.slice(0, 3).join("\n - ");
1536
+ const remaining = invalidPaths.length > 3 ? `
1537
+ ... and ${invalidPaths.length - 3} more` : "";
1538
+ console.warn(
1539
+ `Warning: ${invalidPaths.length} files skipped (unreadable):
1540
+ - ${samplePaths}${remaining}
48
1541
  \u2192 This may occur with Yarn Berry PnP or pnpm symlinks.
49
- \u2192 Try: Run installation command to ensure files are accessible.`)}if(u.length===0){let l=c.slice(0,5).join(`
50
- - `),h=c.length>5?`
51
- ... and ${c.length-5} more`:"";return{cause:[`All ${c.length} files failed validation:`,` - ${l}${h}`,"","\u2192 Common causes:"," \u2022 Yarn Berry PnP virtual filesystem (files are not on disk)"," \u2022 pnpm symlinks pointing to inaccessible locations"," \u2022 Incorrect file permissions"," \u2022 Files were deleted after discovery","","\u2192 Solutions:"," \u2022 Yarn Berry: Use `nodeLinker: node-modules` in .yarnrc.yml"," \u2022 pnpm: Use `node-linker=hoisted` in .npmrc"," \u2022 Check file permissions with: ls -la <file>"," \u2022 Run package manager install command"].join(`
52
- `),data:void 0,error:"No readable manifest files found",status:400,success:!1}}try{return{cause:void 0,data:await this.#r(async()=>await d(await v(this.#e,`orgs/${encodeURIComponent(t)}/full-scans?${k(n)}`,F(u,a),this.#t))),error:void 0,status:200,success:!0}}catch(l){let h=await this.#s(l);return{cause:h.cause,data:void 0,error:h.error,status:h.status,success:!1}}}async createRepository(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/repos`,e,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async createRepositoryLabel(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/repos/labels`,e,this.#t))),error:void 0,status:201,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async deleteOrgDiffScan(t,e){try{let s=await this.#r(async()=>await d(await A(this.#e,`orgs/${encodeURIComponent(t)}/diff-scans/${encodeURIComponent(e)}`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async deleteFullScan(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await A(this.#e,`orgs/${encodeURIComponent(t)}/full-scans/${encodeURIComponent(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async deleteRepository(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await A(this.#e,`orgs/${encodeURIComponent(t)}/repos/${encodeURIComponent(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async deleteRepositoryLabel(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await A(this.#e,`orgs/${encodeURIComponent(t)}/repos/labels/${encodeURIComponent(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async exportCDX(t,e){try{let s=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/full-scans/${encodeURIComponent(e)}/sbom/export/cdx`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async exportSPDX(t,e){try{let s=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/full-scans/${encodeURIComponent(e)}/sbom/export/spdx`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async getApi(t,e){let{responseType:s="response",throws:r=!0}={__proto__:null,...e};try{let n=await m(this.#e,t,this.#t);if(!O(n)){if(r)throw new R(n);let i=await this.#s(new R(n));return{cause:i.cause,data:void 0,error:i.error,status:i.status,success:!1}}let a=await this.#f(n,s);return r?a:{cause:void 0,data:a,error:void 0,status:n.statusCode??200,success:!0}}catch(n){if(r)throw n;if(n instanceof R){let a=await this.#s(n);return{cause:a.cause,data:void 0,error:a.error,status:a.status,success:!1}}return this.#g(n)}}async getAPITokens(t){try{let e=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/tokens`,this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async getAuditLogEvents(t,e){try{let s=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/audit-log?${k(e)}`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async getDiffScanById(t,e){try{let s=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/diff-scans/${encodeURIComponent(e)}`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async getEnabledEntitlements(t){return((await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/entitlements`,this.#t))))?.items||[]).filter(r=>r&&r.enabled===!0&&r.key).map(r=>r.key)}async getEntitlements(t){return(await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/entitlements`,this.#t))))?.items||[]}async getIssuesByNpmPackage(t,e){try{let s=await this.#r(async()=>await d(await m(this.#e,`npm/${encodeURIComponent(t)}/${encodeURIComponent(e)}/issues`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async getOrgAnalytics(t){try{let e=await this.#r(async()=>await d(await m(this.#e,`analytics/org/${encodeURIComponent(t)}`,this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async listOrganizations(){try{return{cause:void 0,data:await this.#d("organizations",async()=>await d(await m(this.#e,"organizations",this.#t))),error:void 0,status:200,success:!0}}catch(t){let e=await this.#s(t);return{cause:e.cause,data:void 0,error:e.error,status:e.status,success:!1}}}async getFullScan(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/full-scans/${encodeURIComponent(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async listFullScans(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/full-scans?${k(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async getFullScanMetadata(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/full-scans/${encodeURIComponent(e)}/metadata`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async getOrgLicensePolicy(t){try{let e=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/settings/license-policy`,this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async getRepository(t,e){let s=encodeURIComponent(t),r=encodeURIComponent(e);try{return{cause:void 0,data:await this.#r(async()=>await d(await m(this.#e,`orgs/${s}/repos/${r}`,this.#t))),error:void 0,status:200,success:!0}}catch(n){let a=await this.#s(n);return{cause:a.cause,data:void 0,error:a.error,status:a.status,success:!1}}}async getRepositoryLabel(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/repos/labels/${encodeURIComponent(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async listRepositoryLabels(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/repos/labels?${k(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async listRepositories(t,e){try{return{cause:void 0,data:await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/repos?${k(e)}`,this.#t))),error:void 0,status:200,success:!0}}catch(s){let r=await this.#s(s);return{cause:r.cause,data:void 0,error:r.error,status:r.status,success:!1}}}async getOrgSecurityPolicy(t){try{let e=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/settings/security-policy`,this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async getOrgTriage(t){try{let e=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/triage`,this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async getQuota(){try{let t=await this.#d("quota",async()=>await d(await m(this.#e,"quota",this.#t)));return this.#n(t)}catch(t){return await this.#s(t)}}async getRepoAnalytics(t,e){try{let s=await this.#r(async()=>await d(await m(this.#e,`analytics/repo/${encodeURIComponent(t)}/${encodeURIComponent(e)}`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async getScoreByNpmPackage(t,e){try{let s=await this.#r(async()=>await d(await m(this.#e,`npm/${encodeURIComponent(t)}/${encodeURIComponent(e)}/score`,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async getSupportedScanFiles(){try{let t=await this.#r(async()=>await d(await m(this.#e,"report/supported",this.#t)));return this.#n(t)}catch(t){return await this.#s(t)}}async listOrgDiffScans(t){try{let e=await this.#r(async()=>await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/diff-scans`,this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async postAPIToken(t,e){try{let s=await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/tokens`,e,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async postAPITokensRevoke(t,e){try{let s=await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/tokens/${encodeURIComponent(e)}/revoke`,{},this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async postAPITokensRotate(t,e){try{let s=await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/tokens/${encodeURIComponent(e)}/rotate`,{},this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async postAPITokenUpdate(t,e,s){try{let r=await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/tokens/${encodeURIComponent(e)}/update`,s,this.#t)));return this.#n(r)}catch(r){return await this.#s(r)}}async postSettings(t){try{let e=await this.#r(async()=>await d(await y("POST",this.#e,"settings",{json:t},this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async searchDependencies(t){try{let e=await this.#r(async()=>await d(await y("POST",this.#e,"dependencies/search",t,this.#t)));return this.#n(e)}catch(e){return await this.#s(e)}}async sendApi(t,e){let{body:s,method:r="POST",throws:n=!0}={__proto__:null,...e};try{let a=await y(r,this.#e,t,s,this.#t),i=await d(a);return n?i:{cause:void 0,data:i,error:void 0,status:a.statusCode??200,success:!0}}catch(a){if(n)throw a;if(a instanceof R){let c=await this.#s(a);return{cause:c.cause,data:void 0,error:c.error,status:c.status,success:!1}}return{cause:(a?String(a).trim():"")||K,data:void 0,error:"API request failed",status:0,success:!1}}}async streamFullScan(t,e,s){let{output:r}={__proto__:null,...s};try{let n=P(this.#e).request(`${this.#e}orgs/${encodeURIComponent(t)}/full-scans/${encodeURIComponent(e)}`,{method:"GET",...this.#t}).end(),a=await T(n);if(!O(a))throw new R(a);if(typeof r=="string"){let i=Me(r),c=0;a.on("data",u=>{if(c+=u.length,c>$)throw a.destroy(),i.destroy(),new Error(`Response exceeds maximum stream size of ${$} bytes`)}),a.pipe(i),i.on("error",u=>{throw new Error(`Failed to write to file: ${r}`,{cause:u})})}else if(r===!0){let i=0;a.on("data",c=>{if(i+=c.length,i>$)throw a.destroy(),new Error(`Response exceeds maximum stream size of ${$} bytes`)}),a.pipe(process.stdout),process.stdout.on("error",c=>{throw new Error("Failed to write to stdout",{cause:c})})}return this.#n(a)}catch(n){return await this.#s(n)}}async streamPatchesFromScan(t,e){let s=await this.#r(async()=>await m(this.#e,`orgs/${encodeURIComponent(t)}/patches/scan?scan_id=${encodeURIComponent(e)}`,this.#t));if(!O(s))throw new R(s,"GET Request failed");let r=H.createInterface({input:s,crlfDelay:Number.POSITIVE_INFINITY});return new ReadableStream({async start(n){try{for await(let a of r){let i=a.trim();if(i)try{let c=JSON.parse(i);n.enqueue(c)}catch(c){ge("streamPatchesFromScan",`Failed to parse line: ${c}`)}}}catch(a){n.error(a)}finally{n.close()}}})}async updateOrgAlertTriage(t,e,s){try{let r=await this.#r(async()=>await d(await y("PUT",this.#e,`orgs/${encodeURIComponent(t)}/triage/${encodeURIComponent(e)}`,s,this.#t)));return this.#n(r)}catch(r){return await this.#s(r)}}async updateOrgLicensePolicy(t,e,s){try{let r=await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/settings/license-policy?${k(s)}`,e,this.#t)));return this.#n(r)}catch(r){return await this.#s(r)}}async updateRepository(t,e,s){try{return{cause:void 0,data:await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/repos/${encodeURIComponent(e)}`,s,this.#t))),error:void 0,status:200,success:!0}}catch(r){let n=await this.#s(r);return{cause:n.cause,data:void 0,error:n.error,status:n.status,success:!1}}}async updateRepositoryLabel(t,e,s){try{return{cause:void 0,data:await this.#r(async()=>await d(await y("PUT",this.#e,`orgs/${encodeURIComponent(t)}/repos/labels/${encodeURIComponent(e)}`,s,this.#t))),error:void 0,status:200,success:!0}}catch(r){let n=await this.#s(r);return{cause:n.cause,data:void 0,error:n.error,status:n.status,success:!1}}}async updateOrgSecurityPolicy(t,e){try{let s=await this.#r(async()=>await d(await y("POST",this.#e,`orgs/${encodeURIComponent(t)}/settings/security-policy`,e,this.#t)));return this.#n(s)}catch(s){return await this.#s(s)}}async uploadManifestFiles(t,e,s){let{pathsRelativeTo:r="."}={__proto__:null,...s},n=I(r),a=U(e,n),{invalidPaths:i,validPaths:c}=V(a);if(this.#o&&i.length>0){let u=await this.#o(c,i,{operation:"uploadManifestFiles",orgSlug:t});if(!u.shouldContinue)return{error:u.errorMessage??"File validation failed",status:400,success:!1,...u.errorCause?{cause:u.errorCause}:{}}}if(!this.#o&&i.length>0){let u=i.slice(0,3).join(`
53
- - `),l=i.length>3?`
54
- ... and ${i.length-3} more`:"";console.warn(`Warning: ${i.length} files skipped (unreadable):
55
- - ${u}${l}
1542
+ \u2192 Try: Run installation command to ensure files are accessible.`
1543
+ );
1544
+ }
1545
+ if (validPaths.length === 0) {
1546
+ const samplePaths = invalidPaths.slice(0, 5).join("\n - ");
1547
+ const remaining = invalidPaths.length > 5 ? `
1548
+ ... and ${invalidPaths.length - 5} more` : "";
1549
+ return {
1550
+ cause: [
1551
+ `All ${invalidPaths.length} files failed validation:`,
1552
+ ` - ${samplePaths}${remaining}`,
1553
+ "",
1554
+ "\u2192 Common causes:",
1555
+ " \u2022 Yarn Berry PnP virtual filesystem (files are not on disk)",
1556
+ " \u2022 pnpm symlinks pointing to inaccessible locations",
1557
+ " \u2022 Incorrect file permissions",
1558
+ " \u2022 Files were deleted after discovery",
1559
+ "",
1560
+ "\u2192 Solutions:",
1561
+ " \u2022 Yarn Berry: Use `nodeLinker: node-modules` in .yarnrc.yml",
1562
+ " \u2022 pnpm: Use `node-linker=hoisted` in .npmrc",
1563
+ " \u2022 Check file permissions with: ls -la <file>",
1564
+ " \u2022 Run package manager install command"
1565
+ ].join("\n"),
1566
+ data: void 0,
1567
+ error: "No readable manifest files found",
1568
+ status: 400,
1569
+ success: false
1570
+ };
1571
+ }
1572
+ try {
1573
+ const data = await this.#executeWithRetry(
1574
+ async () => await getResponseJson(
1575
+ await createUploadRequest(
1576
+ this.#baseUrl,
1577
+ `orgs/${encodeURIComponent(orgSlug)}/full-scans?${queryToSearchParams(queryParams)}`,
1578
+ createRequestBodyForFilepaths(validPaths, basePath),
1579
+ this.#reqOptions
1580
+ )
1581
+ )
1582
+ );
1583
+ return {
1584
+ cause: void 0,
1585
+ data,
1586
+ error: void 0,
1587
+ status: 200,
1588
+ success: true
1589
+ };
1590
+ } catch (e) {
1591
+ const errorResult = await this.#handleApiError(e);
1592
+ return {
1593
+ cause: errorResult.cause,
1594
+ data: void 0,
1595
+ error: errorResult.error,
1596
+ status: errorResult.status,
1597
+ success: false
1598
+ };
1599
+ }
1600
+ }
1601
+ /**
1602
+ * Create a new repository in an organization.
1603
+ *
1604
+ * Registers a repository for monitoring and security scanning.
1605
+ *
1606
+ * @param orgSlug - Organization identifier
1607
+ * @param params - Repository configuration (name, description, homepage, etc.)
1608
+ * @returns Created repository details
1609
+ *
1610
+ * @example
1611
+ * ```typescript
1612
+ * const result = await sdk.createRepository('my-org', {
1613
+ * name: 'my-repo',
1614
+ * description: 'My project repository',
1615
+ * homepage: 'https://example.com'
1616
+ * })
1617
+ *
1618
+ * if (result.success) {
1619
+ * console.log('Repository created:', result.data.id)
1620
+ * }
1621
+ * ```
1622
+ *
1623
+ * @see https://docs.socket.dev/reference/createorgrepo
1624
+ * @apiEndpoint POST /orgs/{org_slug}/repos
1625
+ * @quota 1 unit
1626
+ * @scopes repo:write
1627
+ * @throws {Error} When server returns 5xx status codes
1628
+ */
1629
+ async createRepository(orgSlug, params) {
1630
+ try {
1631
+ const data = await this.#executeWithRetry(
1632
+ async () => await getResponseJson(
1633
+ await createRequestWithJson(
1634
+ "POST",
1635
+ this.#baseUrl,
1636
+ `orgs/${encodeURIComponent(orgSlug)}/repos`,
1637
+ params,
1638
+ this.#reqOptions
1639
+ )
1640
+ )
1641
+ );
1642
+ return {
1643
+ cause: void 0,
1644
+ data,
1645
+ error: void 0,
1646
+ status: 200,
1647
+ success: true
1648
+ };
1649
+ } catch (e) {
1650
+ const errorResult = await this.#handleApiError(e);
1651
+ return {
1652
+ cause: errorResult.cause,
1653
+ data: void 0,
1654
+ error: errorResult.error,
1655
+ status: errorResult.status,
1656
+ success: false
1657
+ };
1658
+ }
1659
+ }
1660
+ /**
1661
+ * Create a new repository label for an organization.
1662
+ *
1663
+ * Labels can be used to group and organize repositories and apply security/license policies.
1664
+ *
1665
+ * @param orgSlug - Organization identifier
1666
+ * @param labelData - Label configuration (must include name property)
1667
+ * @returns Created label with guaranteed id and name fields
1668
+ *
1669
+ * @example
1670
+ * ```typescript
1671
+ * const result = await sdk.createRepositoryLabel('my-org', { name: 'production' })
1672
+ *
1673
+ * if (result.success) {
1674
+ * console.log('Label created:', result.data.id)
1675
+ * console.log('Label name:', result.data.name)
1676
+ * }
1677
+ * ```
1678
+ *
1679
+ * @see https://docs.socket.dev/reference/createorgrepolabel
1680
+ * @apiEndpoint POST /orgs/{org_slug}/repos/labels
1681
+ * @quota 1 unit
1682
+ * @scopes repo-label:create
1683
+ * @throws {Error} When server returns 5xx status codes
1684
+ */
1685
+ async createRepositoryLabel(orgSlug, labelData) {
1686
+ try {
1687
+ const data = await this.#executeWithRetry(
1688
+ async () => await getResponseJson(
1689
+ await createRequestWithJson(
1690
+ "POST",
1691
+ this.#baseUrl,
1692
+ `orgs/${encodeURIComponent(orgSlug)}/repos/labels`,
1693
+ labelData,
1694
+ this.#reqOptions
1695
+ )
1696
+ )
1697
+ );
1698
+ return {
1699
+ cause: void 0,
1700
+ data,
1701
+ error: void 0,
1702
+ status: 201,
1703
+ success: true
1704
+ };
1705
+ } catch (e) {
1706
+ const errorResult = await this.#handleApiError(e);
1707
+ return {
1708
+ cause: errorResult.cause,
1709
+ data: void 0,
1710
+ error: errorResult.error,
1711
+ status: errorResult.status,
1712
+ success: false
1713
+ };
1714
+ }
1715
+ }
1716
+ /**
1717
+ * Delete a diff scan from an organization.
1718
+ * Permanently removes diff scan data and results.
1719
+ *
1720
+ * @throws {Error} When server returns 5xx status codes
1721
+ */
1722
+ async deleteOrgDiffScan(orgSlug, diffScanId) {
1723
+ try {
1724
+ const data = await this.#executeWithRetry(
1725
+ async () => await getResponseJson(
1726
+ await createDeleteRequest(
1727
+ this.#baseUrl,
1728
+ `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`,
1729
+ this.#reqOptions
1730
+ )
1731
+ )
1732
+ );
1733
+ return this.#handleApiSuccess(data);
1734
+ } catch (e) {
1735
+ return await this.#handleApiError(e);
1736
+ }
1737
+ }
1738
+ /**
1739
+ * Delete a full scan from an organization.
1740
+ *
1741
+ * Permanently removes scan data and results.
1742
+ *
1743
+ * @param orgSlug - Organization identifier
1744
+ * @param scanId - Full scan identifier to delete
1745
+ * @returns Success confirmation
1746
+ *
1747
+ * @example
1748
+ * ```typescript
1749
+ * const result = await sdk.deleteFullScan('my-org', 'scan_123')
1750
+ *
1751
+ * if (result.success) {
1752
+ * console.log('Scan deleted successfully')
1753
+ * }
1754
+ * ```
1755
+ *
1756
+ * @see https://docs.socket.dev/reference/deleteorgfullscan
1757
+ * @apiEndpoint DELETE /orgs/{org_slug}/full-scans/{full_scan_id}
1758
+ * @quota 1 unit
1759
+ * @scopes full-scans:delete
1760
+ * @throws {Error} When server returns 5xx status codes
1761
+ */
1762
+ async deleteFullScan(orgSlug, scanId) {
1763
+ try {
1764
+ const data = await this.#executeWithRetry(
1765
+ async () => await getResponseJson(
1766
+ await createDeleteRequest(
1767
+ this.#baseUrl,
1768
+ `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(scanId)}`,
1769
+ this.#reqOptions
1770
+ )
1771
+ )
1772
+ );
1773
+ return {
1774
+ cause: void 0,
1775
+ data,
1776
+ error: void 0,
1777
+ status: 200,
1778
+ success: true
1779
+ };
1780
+ } catch (e) {
1781
+ const errorResult = await this.#handleApiError(e);
1782
+ return {
1783
+ cause: errorResult.cause,
1784
+ data: void 0,
1785
+ error: errorResult.error,
1786
+ status: errorResult.status,
1787
+ success: false
1788
+ };
1789
+ }
1790
+ }
1791
+ /**
1792
+ * Delete a repository from an organization.
1793
+ *
1794
+ * Removes repository monitoring and associated scan data.
1795
+ *
1796
+ * @param orgSlug - Organization identifier
1797
+ * @param repoSlug - Repository slug/name to delete
1798
+ * @returns Success confirmation
1799
+ *
1800
+ * @example
1801
+ * ```typescript
1802
+ * const result = await sdk.deleteRepository('my-org', 'old-repo')
1803
+ *
1804
+ * if (result.success) {
1805
+ * console.log('Repository deleted')
1806
+ * }
1807
+ * ```
1808
+ *
1809
+ * @see https://docs.socket.dev/reference/deleteorgrepo
1810
+ * @apiEndpoint DELETE /orgs/{org_slug}/repos/{repo_slug}
1811
+ * @quota 1 unit
1812
+ * @scopes repo:write
1813
+ * @throws {Error} When server returns 5xx status codes
1814
+ */
1815
+ async deleteRepository(orgSlug, repoSlug) {
1816
+ try {
1817
+ const data = await this.#executeWithRetry(
1818
+ async () => await getResponseJson(
1819
+ await createDeleteRequest(
1820
+ this.#baseUrl,
1821
+ `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}`,
1822
+ this.#reqOptions
1823
+ )
1824
+ )
1825
+ );
1826
+ return {
1827
+ cause: void 0,
1828
+ data,
1829
+ error: void 0,
1830
+ status: 200,
1831
+ success: true
1832
+ };
1833
+ } catch (e) {
1834
+ const errorResult = await this.#handleApiError(e);
1835
+ return {
1836
+ cause: errorResult.cause,
1837
+ data: void 0,
1838
+ error: errorResult.error,
1839
+ status: errorResult.status,
1840
+ success: false
1841
+ };
1842
+ }
1843
+ }
1844
+ /**
1845
+ * Delete a repository label from an organization.
1846
+ *
1847
+ * Removes label and all its associations (repositories, security policy, license policy, etc.).
1848
+ *
1849
+ * @param orgSlug - Organization identifier
1850
+ * @param labelId - Label identifier
1851
+ * @returns Deletion confirmation
1852
+ *
1853
+ * @example
1854
+ * ```typescript
1855
+ * const result = await sdk.deleteRepositoryLabel('my-org', 'label-id-123')
1856
+ *
1857
+ * if (result.success) {
1858
+ * console.log('Label deleted:', result.data.status)
1859
+ * }
1860
+ * ```
1861
+ *
1862
+ * @see https://docs.socket.dev/reference/deleteorgrepolabel
1863
+ * @apiEndpoint DELETE /orgs/{org_slug}/repos/labels/{label_id}
1864
+ * @quota 1 unit
1865
+ * @scopes repo-label:delete
1866
+ * @throws {Error} When server returns 5xx status codes
1867
+ */
1868
+ async deleteRepositoryLabel(orgSlug, labelId) {
1869
+ try {
1870
+ const data = await this.#executeWithRetry(
1871
+ async () => await getResponseJson(
1872
+ await createDeleteRequest(
1873
+ this.#baseUrl,
1874
+ `orgs/${encodeURIComponent(orgSlug)}/repos/labels/${encodeURIComponent(labelId)}`,
1875
+ this.#reqOptions
1876
+ )
1877
+ )
1878
+ );
1879
+ return {
1880
+ cause: void 0,
1881
+ data,
1882
+ error: void 0,
1883
+ status: 200,
1884
+ success: true
1885
+ };
1886
+ } catch (e) {
1887
+ const errorResult = await this.#handleApiError(e);
1888
+ return {
1889
+ cause: errorResult.cause,
1890
+ data: void 0,
1891
+ error: errorResult.error,
1892
+ status: errorResult.status,
1893
+ success: false
1894
+ };
1895
+ }
1896
+ }
1897
+ /**
1898
+ * Delete a legacy scan report permanently.
1899
+ /**
1900
+ * Export scan results in CycloneDX SBOM format.
1901
+ * Returns Software Bill of Materials compliant with CycloneDX standard.
1902
+ *
1903
+ * @throws {Error} When server returns 5xx status codes
1904
+ */
1905
+ async exportCDX(orgSlug, fullScanId) {
1906
+ try {
1907
+ const data = await this.#executeWithRetry(
1908
+ async () => await getResponseJson(
1909
+ await createGetRequest(
1910
+ this.#baseUrl,
1911
+ `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/cdx`,
1912
+ this.#reqOptions
1913
+ )
1914
+ )
1915
+ );
1916
+ return this.#handleApiSuccess(data);
1917
+ } catch (e) {
1918
+ return await this.#handleApiError(e);
1919
+ }
1920
+ }
1921
+ /**
1922
+ * Export scan results in SPDX SBOM format.
1923
+ * Returns Software Bill of Materials compliant with SPDX standard.
1924
+ *
1925
+ * @throws {Error} When server returns 5xx status codes
1926
+ */
1927
+ async exportSPDX(orgSlug, fullScanId) {
1928
+ try {
1929
+ const data = await this.#executeWithRetry(
1930
+ async () => await getResponseJson(
1931
+ await createGetRequest(
1932
+ this.#baseUrl,
1933
+ `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/spdx`,
1934
+ this.#reqOptions
1935
+ )
1936
+ )
1937
+ );
1938
+ return this.#handleApiSuccess(data);
1939
+ } catch (e) {
1940
+ return await this.#handleApiError(e);
1941
+ }
1942
+ }
1943
+ /**
1944
+ * Execute a raw GET request to any API endpoint with configurable response type.
1945
+ * Supports both throwing (default) and non-throwing modes.
1946
+ * @param urlPath - API endpoint path (e.g., 'organizations')
1947
+ * @param options - Request options including responseType and throws behavior
1948
+ * @returns Raw response, parsed data, or SocketSdkGenericResult based on options
1949
+ */
1950
+ async getApi(urlPath, options) {
1951
+ const { responseType = "response", throws = true } = {
1952
+ __proto__: null,
1953
+ ...options
1954
+ };
1955
+ try {
1956
+ const response = await createGetRequest(
1957
+ this.#baseUrl,
1958
+ urlPath,
1959
+ this.#reqOptions
1960
+ );
1961
+ if (!isResponseOk(response)) {
1962
+ if (throws) {
1963
+ throw new ResponseError(response);
1964
+ }
1965
+ const errorResult = await this.#handleApiError(
1966
+ new ResponseError(response)
1967
+ );
1968
+ return {
1969
+ cause: errorResult.cause,
1970
+ data: void 0,
1971
+ error: errorResult.error,
1972
+ status: errorResult.status,
1973
+ success: false
1974
+ };
1975
+ }
1976
+ const data = await this.#handleQueryResponseData(
1977
+ response,
1978
+ responseType
1979
+ );
1980
+ if (throws) {
1981
+ return data;
1982
+ }
1983
+ return {
1984
+ cause: void 0,
1985
+ data,
1986
+ error: void 0,
1987
+ /* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
1988
+ status: response.statusCode ?? 200,
1989
+ success: true
1990
+ };
1991
+ } catch (e) {
1992
+ if (throws) {
1993
+ throw e;
1994
+ }
1995
+ if (e instanceof ResponseError) {
1996
+ const errorResult = await this.#handleApiError(e);
1997
+ return {
1998
+ cause: errorResult.cause,
1999
+ data: void 0,
2000
+ error: errorResult.error,
2001
+ status: errorResult.status,
2002
+ success: false
2003
+ };
2004
+ }
2005
+ return this.#createQueryErrorResult(e);
2006
+ }
2007
+ }
2008
+ /**
2009
+ * Get list of API tokens for an organization.
2010
+ * Returns organization API tokens with metadata and permissions.
2011
+ *
2012
+ * @throws {Error} When server returns 5xx status codes
2013
+ */
2014
+ async getAPITokens(orgSlug) {
2015
+ try {
2016
+ const data = await this.#executeWithRetry(
2017
+ async () => await getResponseJson(
2018
+ await createGetRequest(
2019
+ this.#baseUrl,
2020
+ `orgs/${encodeURIComponent(orgSlug)}/tokens`,
2021
+ this.#reqOptions
2022
+ )
2023
+ )
2024
+ );
2025
+ return this.#handleApiSuccess(data);
2026
+ } catch (e) {
2027
+ return await this.#handleApiError(e);
2028
+ }
2029
+ }
2030
+ /**
2031
+ * Retrieve audit log events for an organization.
2032
+ * Returns chronological log of security and administrative actions.
2033
+ *
2034
+ * @throws {Error} When server returns 5xx status codes
2035
+ */
2036
+ async getAuditLogEvents(orgSlug, queryParams) {
2037
+ try {
2038
+ const data = await this.#executeWithRetry(
2039
+ async () => await getResponseJson(
2040
+ await createGetRequest(
2041
+ this.#baseUrl,
2042
+ `orgs/${encodeURIComponent(orgSlug)}/audit-log?${queryToSearchParams(queryParams)}`,
2043
+ this.#reqOptions
2044
+ )
2045
+ )
2046
+ );
2047
+ return this.#handleApiSuccess(data);
2048
+ } catch (e) {
2049
+ return await this.#handleApiError(e);
2050
+ }
2051
+ }
2052
+ /**
2053
+ * Get details for a specific diff scan.
2054
+ * Returns comparison between two full scans with artifact changes.
2055
+ *
2056
+ * @throws {Error} When server returns 5xx status codes
2057
+ */
2058
+ async getDiffScanById(orgSlug, diffScanId) {
2059
+ try {
2060
+ const data = await this.#executeWithRetry(
2061
+ async () => await getResponseJson(
2062
+ await createGetRequest(
2063
+ this.#baseUrl,
2064
+ `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`,
2065
+ this.#reqOptions
2066
+ )
2067
+ )
2068
+ );
2069
+ return this.#handleApiSuccess(data);
2070
+ } catch (e) {
2071
+ return await this.#handleApiError(e);
2072
+ }
2073
+ }
2074
+ /**
2075
+ * Retrieve the enabled entitlements for an organization.
2076
+ *
2077
+ * This method fetches the organization's entitlements and filters for only* the enabled ones, returning their keys. Entitlements represent Socket
2078
+ * Products that the organization has access to use.
2079
+ */
2080
+ async getEnabledEntitlements(orgSlug) {
2081
+ const data = await this.#executeWithRetry(
2082
+ async () => await getResponseJson(
2083
+ await createGetRequest(
2084
+ this.#baseUrl,
2085
+ `orgs/${encodeURIComponent(orgSlug)}/entitlements`,
2086
+ this.#reqOptions
2087
+ )
2088
+ )
2089
+ );
2090
+ const items = data?.items || [];
2091
+ return items.filter((item) => item && item.enabled === true && item.key).map((item) => item.key);
2092
+ }
2093
+ /**
2094
+ * Retrieve all entitlements for an organization.
2095
+ *
2096
+ * This method fetches all entitlements (both enabled and disabled) for
2097
+ * an organization, returning the complete list with their status.
2098
+ */
2099
+ async getEntitlements(orgSlug) {
2100
+ const data = await this.#executeWithRetry(
2101
+ async () => await getResponseJson(
2102
+ await createGetRequest(
2103
+ this.#baseUrl,
2104
+ `orgs/${encodeURIComponent(orgSlug)}/entitlements`,
2105
+ this.#reqOptions
2106
+ )
2107
+ )
2108
+ );
2109
+ return data?.items || [];
2110
+ }
2111
+ /**
2112
+ * Get security issues for a specific npm package and version.
2113
+ * Returns detailed vulnerability and security alert information.
2114
+ *
2115
+ * @throws {Error} When server returns 5xx status codes
2116
+ */
2117
+ async getIssuesByNpmPackage(pkgName, version) {
2118
+ try {
2119
+ const data = await this.#executeWithRetry(
2120
+ async () => await getResponseJson(
2121
+ await createGetRequest(
2122
+ this.#baseUrl,
2123
+ `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/issues`,
2124
+ this.#reqOptions
2125
+ )
2126
+ )
2127
+ );
2128
+ return this.#handleApiSuccess(data);
2129
+ } catch (e) {
2130
+ return await this.#handleApiError(e);
2131
+ }
2132
+ }
2133
+ /**
2134
+ * Get analytics data for organization usage patterns and security metrics.
2135
+ * Returns statistical analysis for specified time period.
2136
+ *
2137
+ * @throws {Error} When server returns 5xx status codes
2138
+ */
2139
+ async getOrgAnalytics(time) {
2140
+ try {
2141
+ const data = await this.#executeWithRetry(
2142
+ async () => await getResponseJson(
2143
+ await createGetRequest(
2144
+ this.#baseUrl,
2145
+ `analytics/org/${encodeURIComponent(time)}`,
2146
+ this.#reqOptions
2147
+ )
2148
+ )
2149
+ );
2150
+ return this.#handleApiSuccess(data);
2151
+ } catch (e) {
2152
+ return await this.#handleApiError(e);
2153
+ }
2154
+ }
2155
+ /**
2156
+ * List all organizations accessible to the current user.
2157
+ *
2158
+ * Returns organization details and access permissions with guaranteed required fields.
2159
+ *
2160
+ * @returns List of organizations with metadata
2161
+ *
2162
+ * @example
2163
+ * ```typescript
2164
+ * const result = await sdk.listOrganizations()
2165
+ *
2166
+ * if (result.success) {
2167
+ * result.data.organizations.forEach(org => {
2168
+ * console.log(org.name, org.slug) // Guaranteed fields
2169
+ * })
2170
+ * }
2171
+ * ```
2172
+ *
2173
+ * @see https://docs.socket.dev/reference/getorganizations
2174
+ * @apiEndpoint GET /organizations
2175
+ * @quota 1 unit
2176
+ * @throws {Error} When server returns 5xx status codes
2177
+ */
2178
+ async listOrganizations() {
2179
+ try {
2180
+ const data = await this.#getCached(
2181
+ "organizations",
2182
+ async () => await getResponseJson(
2183
+ await createGetRequest(
2184
+ this.#baseUrl,
2185
+ "organizations",
2186
+ this.#reqOptions
2187
+ )
2188
+ )
2189
+ );
2190
+ return {
2191
+ cause: void 0,
2192
+ data,
2193
+ error: void 0,
2194
+ status: 200,
2195
+ success: true
2196
+ };
2197
+ } catch (e) {
2198
+ const errorResult = await this.#handleApiError(e);
2199
+ return {
2200
+ cause: errorResult.cause,
2201
+ data: void 0,
2202
+ error: errorResult.error,
2203
+ status: errorResult.status,
2204
+ success: false
2205
+ };
2206
+ }
2207
+ }
2208
+ /**
2209
+ * Get complete full scan results buffered in memory.
2210
+ *
2211
+ * Returns entire scan data as JSON for programmatic processing.
2212
+ * For large scans, consider using streamFullScan() instead.
2213
+ *
2214
+ * @param orgSlug - Organization identifier
2215
+ * @param scanId - Full scan identifier
2216
+ * @returns Complete full scan data including all artifacts
2217
+ *
2218
+ * @example
2219
+ * ```typescript
2220
+ * const result = await sdk.getFullScan('my-org', 'scan_123')
2221
+ *
2222
+ * if (result.success) {
2223
+ * console.log('Scan status:', result.data.scan_state)
2224
+ * console.log('Repository:', result.data.repository_slug)
2225
+ * }
2226
+ * ```
2227
+ *
2228
+ * @see https://docs.socket.dev/reference/getorgfullscan
2229
+ * @apiEndpoint GET /orgs/{org_slug}/full-scans/{full_scan_id}
2230
+ * @quota 1 unit
2231
+ * @scopes full-scans:list
2232
+ * @throws {Error} When server returns 5xx status codes
2233
+ */
2234
+ async getFullScan(orgSlug, scanId) {
2235
+ try {
2236
+ const data = await this.#executeWithRetry(
2237
+ async () => await getResponseJson(
2238
+ await createGetRequest(
2239
+ this.#baseUrl,
2240
+ `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(scanId)}`,
2241
+ this.#reqOptions
2242
+ )
2243
+ )
2244
+ );
2245
+ return {
2246
+ cause: void 0,
2247
+ data,
2248
+ error: void 0,
2249
+ status: 200,
2250
+ success: true
2251
+ };
2252
+ } catch (e) {
2253
+ const errorResult = await this.#handleApiError(e);
2254
+ return {
2255
+ cause: errorResult.cause,
2256
+ data: void 0,
2257
+ error: errorResult.error,
2258
+ status: errorResult.status,
2259
+ success: false
2260
+ };
2261
+ }
2262
+ }
2263
+ /**
2264
+ * List all full scans for an organization.
2265
+ *
2266
+ * Returns paginated list of full scan metadata with guaranteed required fields
2267
+ * for improved TypeScript autocomplete.
2268
+ *
2269
+ * @param orgSlug - Organization identifier
2270
+ * @param options - Filtering and pagination options
2271
+ * @returns List of full scans with metadata
2272
+ *
2273
+ * @example
2274
+ * ```typescript
2275
+ * const result = await sdk.listFullScans('my-org', {
2276
+ * branch: 'main',
2277
+ * per_page: 50,
2278
+ * use_cursor: true
2279
+ * })
2280
+ *
2281
+ * if (result.success) {
2282
+ * result.data.results.forEach(scan => {
2283
+ * console.log(scan.id, scan.created_at) // Guaranteed fields
2284
+ * })
2285
+ * }
2286
+ * ```
2287
+ *
2288
+ * @see https://docs.socket.dev/reference/getorgfullscanlist
2289
+ * @apiEndpoint GET /orgs/{org_slug}/full-scans
2290
+ * @quota 1 unit
2291
+ * @scopes full-scans:list
2292
+ * @throws {Error} When server returns 5xx status codes
2293
+ */
2294
+ async listFullScans(orgSlug, options) {
2295
+ try {
2296
+ const data = await this.#executeWithRetry(
2297
+ async () => await getResponseJson(
2298
+ await createGetRequest(
2299
+ this.#baseUrl,
2300
+ `orgs/${encodeURIComponent(orgSlug)}/full-scans?${queryToSearchParams(options)}`,
2301
+ this.#reqOptions
2302
+ )
2303
+ )
2304
+ );
2305
+ return {
2306
+ cause: void 0,
2307
+ data,
2308
+ error: void 0,
2309
+ status: 200,
2310
+ success: true
2311
+ };
2312
+ } catch (e) {
2313
+ const errorResult = await this.#handleApiError(e);
2314
+ return {
2315
+ cause: errorResult.cause,
2316
+ data: void 0,
2317
+ error: errorResult.error,
2318
+ status: errorResult.status,
2319
+ success: false
2320
+ };
2321
+ }
2322
+ }
2323
+ /**
2324
+ * Get metadata for a specific full scan.
2325
+ *
2326
+ * Returns scan configuration, status, and summary information without full artifact data.
2327
+ * Useful for checking scan status without downloading complete results.
2328
+ *
2329
+ * @param orgSlug - Organization identifier
2330
+ * @param scanId - Full scan identifier
2331
+ * @returns Scan metadata including status and configuration
2332
+ *
2333
+ * @example
2334
+ * ```typescript
2335
+ * const result = await sdk.getFullScanMetadata('my-org', 'scan_123')
2336
+ *
2337
+ * if (result.success) {
2338
+ * console.log('Scan state:', result.data.scan_state)
2339
+ * console.log('Branch:', result.data.branch)
2340
+ * }
2341
+ * ```
2342
+ *
2343
+ * @see https://docs.socket.dev/reference/getorgfullscanmetadata
2344
+ * @apiEndpoint GET /orgs/{org_slug}/full-scans/{full_scan_id}/metadata
2345
+ * @quota 1 unit
2346
+ * @scopes full-scans:list
2347
+ * @throws {Error} When server returns 5xx status codes
2348
+ */
2349
+ async getFullScanMetadata(orgSlug, scanId) {
2350
+ try {
2351
+ const data = await this.#executeWithRetry(
2352
+ async () => await getResponseJson(
2353
+ await createGetRequest(
2354
+ this.#baseUrl,
2355
+ `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(scanId)}/metadata`,
2356
+ this.#reqOptions
2357
+ )
2358
+ )
2359
+ );
2360
+ return {
2361
+ cause: void 0,
2362
+ data,
2363
+ error: void 0,
2364
+ status: 200,
2365
+ success: true
2366
+ };
2367
+ } catch (e) {
2368
+ const errorResult = await this.#handleApiError(e);
2369
+ return {
2370
+ cause: errorResult.cause,
2371
+ data: void 0,
2372
+ error: errorResult.error,
2373
+ status: errorResult.status,
2374
+ success: false
2375
+ };
2376
+ }
2377
+ }
2378
+ /**
2379
+ * Get organization's license policy configuration.* Returns allowed, restricted, and monitored license types.
2380
+ *
2381
+ * @throws {Error} When server returns 5xx status codes
2382
+ */
2383
+ async getOrgLicensePolicy(orgSlug) {
2384
+ try {
2385
+ const data = await this.#executeWithRetry(
2386
+ async () => await getResponseJson(
2387
+ await createGetRequest(
2388
+ this.#baseUrl,
2389
+ `orgs/${encodeURIComponent(orgSlug)}/settings/license-policy`,
2390
+ this.#reqOptions
2391
+ )
2392
+ )
2393
+ );
2394
+ return this.#handleApiSuccess(data);
2395
+ } catch (e) {
2396
+ return await this.#handleApiError(e);
2397
+ }
2398
+ }
2399
+ /**
2400
+ * Get details for a specific repository.
2401
+ *
2402
+ * Returns repository configuration, monitoring status, and metadata.
2403
+ *
2404
+ * @param orgSlug - Organization identifier
2405
+ * @param repoSlug - Repository slug/name
2406
+ * @returns Repository details with configuration
2407
+ *
2408
+ * @example
2409
+ * ```typescript
2410
+ * const result = await sdk.getRepository('my-org', 'my-repo')
2411
+ *
2412
+ * if (result.success) {
2413
+ * console.log('Repository:', result.data.name)
2414
+ * console.log('Visibility:', result.data.visibility)
2415
+ * console.log('Default branch:', result.data.default_branch)
2416
+ * }
2417
+ * ```
2418
+ *
2419
+ * @see https://docs.socket.dev/reference/getorgrepo
2420
+ * @apiEndpoint GET /orgs/{org_slug}/repos/{repo_slug}
2421
+ * @quota 1 unit
2422
+ * @scopes repo:read
2423
+ * @throws {Error} When server returns 5xx status codes
2424
+ */
2425
+ async getRepository(orgSlug, repoSlug) {
2426
+ const orgSlugParam = encodeURIComponent(orgSlug);
2427
+ const repoSlugParam = encodeURIComponent(repoSlug);
2428
+ try {
2429
+ const data = await this.#executeWithRetry(
2430
+ async () => await getResponseJson(
2431
+ await createGetRequest(
2432
+ this.#baseUrl,
2433
+ `orgs/${orgSlugParam}/repos/${repoSlugParam}`,
2434
+ this.#reqOptions
2435
+ )
2436
+ )
2437
+ );
2438
+ return {
2439
+ cause: void 0,
2440
+ data,
2441
+ error: void 0,
2442
+ status: 200,
2443
+ success: true
2444
+ };
2445
+ } catch (e) {
2446
+ const errorResult = await this.#handleApiError(e);
2447
+ return {
2448
+ cause: errorResult.cause,
2449
+ data: void 0,
2450
+ error: errorResult.error,
2451
+ status: errorResult.status,
2452
+ success: false
2453
+ };
2454
+ }
2455
+ }
2456
+ /**
2457
+ * Get details for a specific repository label.
2458
+ *
2459
+ * Returns label configuration, associated repositories, and policy settings.
2460
+ *
2461
+ * @param orgSlug - Organization identifier
2462
+ * @param labelId - Label identifier
2463
+ * @returns Label details with guaranteed id and name fields
2464
+ *
2465
+ * @example
2466
+ * ```typescript
2467
+ * const result = await sdk.getRepositoryLabel('my-org', 'label-id-123')
2468
+ *
2469
+ * if (result.success) {
2470
+ * console.log('Label name:', result.data.name)
2471
+ * console.log('Associated repos:', result.data.repository_ids)
2472
+ * console.log('Has security policy:', result.data.has_security_policy)
2473
+ * }
2474
+ * ```
2475
+ *
2476
+ * @see https://docs.socket.dev/reference/getorgrepolabel
2477
+ * @apiEndpoint GET /orgs/{org_slug}/repos/labels/{label_id}
2478
+ * @quota 1 unit
2479
+ * @scopes repo-label:list
2480
+ * @throws {Error} When server returns 5xx status codes
2481
+ */
2482
+ async getRepositoryLabel(orgSlug, labelId) {
2483
+ try {
2484
+ const data = await this.#executeWithRetry(
2485
+ async () => await getResponseJson(
2486
+ await createGetRequest(
2487
+ this.#baseUrl,
2488
+ `orgs/${encodeURIComponent(orgSlug)}/repos/labels/${encodeURIComponent(labelId)}`,
2489
+ this.#reqOptions
2490
+ )
2491
+ )
2492
+ );
2493
+ return {
2494
+ cause: void 0,
2495
+ data,
2496
+ error: void 0,
2497
+ status: 200,
2498
+ success: true
2499
+ };
2500
+ } catch (e) {
2501
+ const errorResult = await this.#handleApiError(e);
2502
+ return {
2503
+ cause: errorResult.cause,
2504
+ data: void 0,
2505
+ error: errorResult.error,
2506
+ status: errorResult.status,
2507
+ success: false
2508
+ };
2509
+ }
2510
+ }
2511
+ /**
2512
+ * List all repository labels for an organization.
2513
+ *
2514
+ * Returns paginated list of labels configured for repository organization and policy management.
2515
+ *
2516
+ * @param orgSlug - Organization identifier
2517
+ * @param options - Pagination options
2518
+ * @returns List of labels with guaranteed id and name fields
2519
+ *
2520
+ * @example
2521
+ * ```typescript
2522
+ * const result = await sdk.listRepositoryLabels('my-org', { per_page: 50, page: 1 })
2523
+ *
2524
+ * if (result.success) {
2525
+ * result.data.results.forEach(label => {
2526
+ * console.log('Label:', label.name)
2527
+ * console.log('Associated repos:', label.repository_ids?.length || 0)
2528
+ * })
2529
+ * }
2530
+ * ```
2531
+ *
2532
+ * @see https://docs.socket.dev/reference/getorgrepolabellist
2533
+ * @apiEndpoint GET /orgs/{org_slug}/repos/labels
2534
+ * @quota 1 unit
2535
+ * @scopes repo-label:list
2536
+ * @throws {Error} When server returns 5xx status codes
2537
+ */
2538
+ async listRepositoryLabels(orgSlug, options) {
2539
+ try {
2540
+ const data = await this.#executeWithRetry(
2541
+ async () => await getResponseJson(
2542
+ await createGetRequest(
2543
+ this.#baseUrl,
2544
+ `orgs/${encodeURIComponent(orgSlug)}/repos/labels?${queryToSearchParams(options)}`,
2545
+ this.#reqOptions
2546
+ )
2547
+ )
2548
+ );
2549
+ return {
2550
+ cause: void 0,
2551
+ data,
2552
+ error: void 0,
2553
+ status: 200,
2554
+ success: true
2555
+ };
2556
+ } catch (e) {
2557
+ const errorResult = await this.#handleApiError(e);
2558
+ return {
2559
+ cause: errorResult.cause,
2560
+ data: void 0,
2561
+ error: errorResult.error,
2562
+ status: errorResult.status,
2563
+ success: false
2564
+ };
2565
+ }
2566
+ }
2567
+ /**
2568
+ * List all repositories in an organization.
2569
+ *
2570
+ * Returns paginated list of repository metadata with guaranteed required fields.
2571
+ *
2572
+ * @param orgSlug - Organization identifier
2573
+ * @param options - Pagination and filtering options
2574
+ * @returns List of repositories with metadata
2575
+ *
2576
+ * @example
2577
+ * ```typescript
2578
+ * const result = await sdk.listRepositories('my-org', {
2579
+ * per_page: 50,
2580
+ * sort: 'name',
2581
+ * direction: 'asc'
2582
+ * })
2583
+ *
2584
+ * if (result.success) {
2585
+ * result.data.results.forEach(repo => {
2586
+ * console.log(repo.name, repo.visibility)
2587
+ * })
2588
+ * }
2589
+ * ```
2590
+ *
2591
+ * @see https://docs.socket.dev/reference/getorgrepolist
2592
+ * @apiEndpoint GET /orgs/{org_slug}/repos
2593
+ * @quota 1 unit
2594
+ * @scopes repo:list
2595
+ * @throws {Error} When server returns 5xx status codes
2596
+ */
2597
+ async listRepositories(orgSlug, options) {
2598
+ try {
2599
+ const data = await this.#executeWithRetry(
2600
+ async () => await getResponseJson(
2601
+ await createGetRequest(
2602
+ this.#baseUrl,
2603
+ `orgs/${encodeURIComponent(orgSlug)}/repos?${queryToSearchParams(options)}`,
2604
+ this.#reqOptions
2605
+ )
2606
+ )
2607
+ );
2608
+ return {
2609
+ cause: void 0,
2610
+ data,
2611
+ error: void 0,
2612
+ status: 200,
2613
+ success: true
2614
+ };
2615
+ } catch (e) {
2616
+ const errorResult = await this.#handleApiError(e);
2617
+ return {
2618
+ cause: errorResult.cause,
2619
+ data: void 0,
2620
+ error: errorResult.error,
2621
+ status: errorResult.status,
2622
+ success: false
2623
+ };
2624
+ }
2625
+ }
2626
+ /**
2627
+ * Get organization's security policy configuration.* Returns alert rules, severity thresholds, and enforcement settings.
2628
+ *
2629
+ * @throws {Error} When server returns 5xx status codes
2630
+ */
2631
+ async getOrgSecurityPolicy(orgSlug) {
2632
+ try {
2633
+ const data = await this.#executeWithRetry(
2634
+ async () => await getResponseJson(
2635
+ await createGetRequest(
2636
+ this.#baseUrl,
2637
+ `orgs/${encodeURIComponent(orgSlug)}/settings/security-policy`,
2638
+ this.#reqOptions
2639
+ )
2640
+ )
2641
+ );
2642
+ return this.#handleApiSuccess(data);
2643
+ } catch (e) {
2644
+ return await this.#handleApiError(e);
2645
+ }
2646
+ }
2647
+ /**
2648
+ * Get organization triage settings and status.
2649
+ * Returns alert triage configuration and current state.
2650
+ *
2651
+ * @throws {Error} When server returns 5xx status codes
2652
+ */
2653
+ async getOrgTriage(orgSlug) {
2654
+ try {
2655
+ const data = await this.#executeWithRetry(
2656
+ async () => await getResponseJson(
2657
+ await createGetRequest(
2658
+ this.#baseUrl,
2659
+ `orgs/${encodeURIComponent(orgSlug)}/triage`,
2660
+ this.#reqOptions
2661
+ )
2662
+ )
2663
+ );
2664
+ return this.#handleApiSuccess(data);
2665
+ } catch (e) {
2666
+ return await this.#handleApiError(e);
2667
+ }
2668
+ }
2669
+ /**
2670
+ * Get current API quota usage and limits.
2671
+ * Returns remaining requests, rate limits, and quota reset times.
2672
+ *
2673
+ * @throws {Error} When server returns 5xx status codes
2674
+ */
2675
+ async getQuota() {
2676
+ try {
2677
+ const data = await this.#getCached(
2678
+ "quota",
2679
+ async () => await getResponseJson(
2680
+ await createGetRequest(this.#baseUrl, "quota", this.#reqOptions)
2681
+ )
2682
+ );
2683
+ return this.#handleApiSuccess(data);
2684
+ } catch (e) {
2685
+ return await this.#handleApiError(e);
2686
+ }
2687
+ }
2688
+ /**
2689
+ * Get analytics data for a specific repository.
2690
+ * Returns security metrics, dependency trends, and vulnerability statistics.
2691
+ *
2692
+ * @throws {Error} When server returns 5xx status codes
2693
+ */
2694
+ async getRepoAnalytics(repo, time) {
2695
+ try {
2696
+ const data = await this.#executeWithRetry(
2697
+ async () => await getResponseJson(
2698
+ await createGetRequest(
2699
+ this.#baseUrl,
2700
+ `analytics/repo/${encodeURIComponent(repo)}/${encodeURIComponent(time)}`,
2701
+ this.#reqOptions
2702
+ )
2703
+ )
2704
+ );
2705
+ return this.#handleApiSuccess(data);
2706
+ } catch (e) {
2707
+ return await this.#handleApiError(e);
2708
+ }
2709
+ }
2710
+ /**
2711
+ * Get detailed results for a legacy scan report.
2712
+ /**
2713
+ /**
2714
+ * Get security score for a specific npm package and version.
2715
+ * Returns numerical security rating and scoring breakdown.
2716
+ *
2717
+ * @throws {Error} When server returns 5xx status codes
2718
+ */
2719
+ async getScoreByNpmPackage(pkgName, version) {
2720
+ try {
2721
+ const data = await this.#executeWithRetry(
2722
+ async () => await getResponseJson(
2723
+ await createGetRequest(
2724
+ this.#baseUrl,
2725
+ `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/score`,
2726
+ this.#reqOptions
2727
+ )
2728
+ )
2729
+ );
2730
+ return this.#handleApiSuccess(data);
2731
+ } catch (e) {
2732
+ return await this.#handleApiError(e);
2733
+ }
2734
+ }
2735
+ /**
2736
+ * Get list of file types and formats supported for scanning.
2737
+ * Returns supported manifest files, lockfiles, and configuration formats.
2738
+ *
2739
+ * @throws {Error} When server returns 5xx status codes
2740
+ */
2741
+ async getSupportedScanFiles() {
2742
+ try {
2743
+ const data = await this.#executeWithRetry(
2744
+ async () => await getResponseJson(
2745
+ await createGetRequest(
2746
+ this.#baseUrl,
2747
+ "report/supported",
2748
+ this.#reqOptions
2749
+ )
2750
+ )
2751
+ );
2752
+ return this.#handleApiSuccess(data);
2753
+ } catch (e) {
2754
+ return await this.#handleApiError(e);
2755
+ }
2756
+ }
2757
+ /**
2758
+ * List all diff scans for an organization.
2759
+ * Returns paginated list of diff scan metadata and status.
2760
+ *
2761
+ * @throws {Error} When server returns 5xx status codes
2762
+ */
2763
+ async listOrgDiffScans(orgSlug) {
2764
+ try {
2765
+ const data = await this.#executeWithRetry(
2766
+ async () => await getResponseJson(
2767
+ await createGetRequest(
2768
+ this.#baseUrl,
2769
+ `orgs/${encodeURIComponent(orgSlug)}/diff-scans`,
2770
+ this.#reqOptions
2771
+ )
2772
+ )
2773
+ );
2774
+ return this.#handleApiSuccess(data);
2775
+ } catch (e) {
2776
+ return await this.#handleApiError(e);
2777
+ }
2778
+ }
2779
+ /**
2780
+ * Create a new API token for an organization.
2781
+ * Generates API token with specified scopes and metadata.
2782
+ *
2783
+ * @throws {Error} When server returns 5xx status codes
2784
+ */
2785
+ async postAPIToken(orgSlug, tokenData) {
2786
+ try {
2787
+ const data = await this.#executeWithRetry(
2788
+ async () => await getResponseJson(
2789
+ await createRequestWithJson(
2790
+ "POST",
2791
+ this.#baseUrl,
2792
+ `orgs/${encodeURIComponent(orgSlug)}/tokens`,
2793
+ tokenData,
2794
+ this.#reqOptions
2795
+ )
2796
+ )
2797
+ );
2798
+ return this.#handleApiSuccess(data);
2799
+ } catch (e) {
2800
+ return await this.#handleApiError(e);
2801
+ }
2802
+ }
2803
+ /**
2804
+ * Revoke an API token for an organization.
2805
+ * Permanently disables the token and removes access.
2806
+ *
2807
+ * @throws {Error} When server returns 5xx status codes
2808
+ */
2809
+ async postAPITokensRevoke(orgSlug, tokenId) {
2810
+ try {
2811
+ const data = await this.#executeWithRetry(
2812
+ async () => await getResponseJson(
2813
+ await createRequestWithJson(
2814
+ "POST",
2815
+ this.#baseUrl,
2816
+ `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/revoke`,
2817
+ {},
2818
+ this.#reqOptions
2819
+ )
2820
+ )
2821
+ );
2822
+ return this.#handleApiSuccess(data);
2823
+ } catch (e) {
2824
+ return await this.#handleApiError(e);
2825
+ }
2826
+ }
2827
+ /**
2828
+ * Rotate an API token for an organization.
2829
+ * Generates new token value while preserving token metadata.
2830
+ *
2831
+ * @throws {Error} When server returns 5xx status codes
2832
+ */
2833
+ async postAPITokensRotate(orgSlug, tokenId) {
2834
+ try {
2835
+ const data = await this.#executeWithRetry(
2836
+ async () => await getResponseJson(
2837
+ await createRequestWithJson(
2838
+ "POST",
2839
+ this.#baseUrl,
2840
+ `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/rotate`,
2841
+ {},
2842
+ this.#reqOptions
2843
+ )
2844
+ )
2845
+ );
2846
+ return this.#handleApiSuccess(data);
2847
+ } catch (e) {
2848
+ return await this.#handleApiError(e);
2849
+ }
2850
+ }
2851
+ /**
2852
+ * Update an existing API token for an organization.
2853
+ * Modifies token metadata, scopes, or other properties.
2854
+ *
2855
+ * @throws {Error} When server returns 5xx status codes
2856
+ */
2857
+ async postAPITokenUpdate(orgSlug, tokenId, updateData) {
2858
+ try {
2859
+ const data = await this.#executeWithRetry(
2860
+ async () => await getResponseJson(
2861
+ await createRequestWithJson(
2862
+ "POST",
2863
+ this.#baseUrl,
2864
+ `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/update`,
2865
+ updateData,
2866
+ this.#reqOptions
2867
+ )
2868
+ )
2869
+ );
2870
+ return this.#handleApiSuccess(data);
2871
+ } catch (e) {
2872
+ return await this.#handleApiError(e);
2873
+ }
2874
+ }
2875
+ /**
2876
+ * Update user or organization settings.
2877
+ * Configures preferences, notifications, and security policies.
2878
+ *
2879
+ * @throws {Error} When server returns 5xx status codes
2880
+ */
2881
+ async postSettings(selectors) {
2882
+ try {
2883
+ const data = await this.#executeWithRetry(
2884
+ async () => await getResponseJson(
2885
+ await createRequestWithJson(
2886
+ "POST",
2887
+ this.#baseUrl,
2888
+ "settings",
2889
+ { json: selectors },
2890
+ this.#reqOptions
2891
+ )
2892
+ )
2893
+ );
2894
+ return this.#handleApiSuccess(data);
2895
+ } catch (e) {
2896
+ return await this.#handleApiError(e);
2897
+ }
2898
+ }
2899
+ /**
2900
+ * Search for dependencies across monitored projects.
2901
+ * Returns matching packages with security information and usage patterns.
2902
+ *
2903
+ * @throws {Error} When server returns 5xx status codes
2904
+ */
2905
+ async searchDependencies(queryParams) {
2906
+ try {
2907
+ const data = await this.#executeWithRetry(
2908
+ async () => await getResponseJson(
2909
+ await createRequestWithJson(
2910
+ "POST",
2911
+ this.#baseUrl,
2912
+ "dependencies/search",
2913
+ queryParams,
2914
+ this.#reqOptions
2915
+ )
2916
+ )
2917
+ );
2918
+ return this.#handleApiSuccess(data);
2919
+ } catch (e) {
2920
+ return await this.#handleApiError(e);
2921
+ }
2922
+ }
2923
+ /**
2924
+ * Send POST or PUT request with JSON body and return parsed JSON response.
2925
+ * Supports both throwing (default) and non-throwing modes.
2926
+ * @param urlPath - API endpoint path (e.g., 'organizations')
2927
+ * @param options - Request options including method, body, and throws behavior
2928
+ * @returns Parsed JSON response or SocketSdkGenericResult based on options
2929
+ */
2930
+ async sendApi(urlPath, options) {
2931
+ const {
2932
+ body,
2933
+ // Default to POST method for JSON API requests.
2934
+ method = "POST",
2935
+ throws = true
2936
+ } = { __proto__: null, ...options };
2937
+ try {
2938
+ const response = await createRequestWithJson(
2939
+ method,
2940
+ this.#baseUrl,
2941
+ urlPath,
2942
+ body,
2943
+ this.#reqOptions
2944
+ );
2945
+ const data = await getResponseJson(response);
2946
+ if (throws) {
2947
+ return data;
2948
+ }
2949
+ return {
2950
+ cause: void 0,
2951
+ data,
2952
+ error: void 0,
2953
+ /* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
2954
+ status: response.statusCode ?? 200,
2955
+ success: true
2956
+ };
2957
+ } catch (e) {
2958
+ if (throws) {
2959
+ throw e;
2960
+ }
2961
+ if (e instanceof ResponseError) {
2962
+ const errorResult = await this.#handleApiError(e);
2963
+ return {
2964
+ cause: errorResult.cause,
2965
+ data: void 0,
2966
+ error: errorResult.error,
2967
+ status: errorResult.status,
2968
+ success: false
2969
+ };
2970
+ }
2971
+ const errStr = e ? String(e).trim() : "";
2972
+ return {
2973
+ cause: errStr || UNKNOWN_ERROR,
2974
+ data: void 0,
2975
+ error: "API request failed",
2976
+ status: 0,
2977
+ success: false
2978
+ };
2979
+ }
2980
+ }
2981
+ /**
2982
+ * Stream a full scan's results to file or stdout.
2983
+ *
2984
+ * Provides efficient streaming for large scan datasets without loading
2985
+ * entire response into memory. Useful for processing large SBOMs.
2986
+ *
2987
+ * @param orgSlug - Organization identifier
2988
+ * @param scanId - Full scan identifier
2989
+ * @param options - Streaming options (output file path, stdout, or buffered)
2990
+ * @returns Scan result with streaming response
2991
+ *
2992
+ * @example
2993
+ * ```typescript
2994
+ * // Stream to file
2995
+ * await sdk.streamFullScan('my-org', 'scan_123', {
2996
+ * output: './scan-results.json'
2997
+ * })
2998
+ *
2999
+ * // Stream to stdout
3000
+ * await sdk.streamFullScan('my-org', 'scan_123', {
3001
+ * output: true
3002
+ * })
3003
+ *
3004
+ * // Get buffered response
3005
+ * const result = await sdk.streamFullScan('my-org', 'scan_123')
3006
+ * ```
3007
+ *
3008
+ * @see https://docs.socket.dev/reference/getorgfullscan
3009
+ * @apiEndpoint GET /orgs/{org_slug}/full-scans/{full_scan_id}
3010
+ * @quota 1 unit
3011
+ * @scopes full-scans:list
3012
+ * @throws {Error} When server returns 5xx status codes
3013
+ */
3014
+ async streamFullScan(orgSlug, scanId, options) {
3015
+ const { output } = {
3016
+ __proto__: null,
3017
+ ...options
3018
+ };
3019
+ try {
3020
+ const req = getHttpModule(this.#baseUrl).request(
3021
+ `${this.#baseUrl}orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(scanId)}`,
3022
+ {
3023
+ method: "GET",
3024
+ ...this.#reqOptions
3025
+ }
3026
+ ).end();
3027
+ const res = await getResponse(req);
3028
+ if (!isResponseOk(res)) {
3029
+ throw new ResponseError(res);
3030
+ }
3031
+ if (typeof output === "string") {
3032
+ const writeStream = createWriteStream(output);
3033
+ let bytesWritten = 0;
3034
+ res.on("data", (chunk) => {
3035
+ bytesWritten += chunk.length;
3036
+ if (bytesWritten > MAX_STREAM_SIZE) {
3037
+ res.destroy();
3038
+ writeStream.destroy();
3039
+ throw new Error(
3040
+ `Response exceeds maximum stream size of ${MAX_STREAM_SIZE} bytes`
3041
+ );
3042
+ }
3043
+ });
3044
+ res.pipe(writeStream);
3045
+ writeStream.on("error", (error) => {
3046
+ throw new Error(`Failed to write to file: ${output}`, {
3047
+ cause: error
3048
+ });
3049
+ });
3050
+ } else if (output === true) {
3051
+ let bytesWritten = 0;
3052
+ res.on("data", (chunk) => {
3053
+ bytesWritten += chunk.length;
3054
+ if (bytesWritten > MAX_STREAM_SIZE) {
3055
+ res.destroy();
3056
+ throw new Error(
3057
+ `Response exceeds maximum stream size of ${MAX_STREAM_SIZE} bytes`
3058
+ );
3059
+ }
3060
+ });
3061
+ res.pipe(process.stdout);
3062
+ process.stdout.on("error", (error) => {
3063
+ throw new Error("Failed to write to stdout", { cause: error });
3064
+ });
3065
+ }
3066
+ return this.#handleApiSuccess(res);
3067
+ } catch (e) {
3068
+ return await this.#handleApiError(e);
3069
+ }
3070
+ }
3071
+ /**
3072
+ * Stream patches for artifacts in a scan report.
3073
+ *
3074
+ * This method streams all available patches for artifacts in a scan.
3075
+ * Free tier users will only receive free patches.
3076
+ *
3077
+ * Note: This method returns a ReadableStream for processing large datasets.
3078
+ */
3079
+ async streamPatchesFromScan(orgSlug, scanId) {
3080
+ const response = await this.#executeWithRetry(
3081
+ async () => await createGetRequest(
3082
+ this.#baseUrl,
3083
+ `orgs/${encodeURIComponent(orgSlug)}/patches/scan?scan_id=${encodeURIComponent(scanId)}`,
3084
+ this.#reqOptions
3085
+ )
3086
+ );
3087
+ if (!isResponseOk(response)) {
3088
+ throw new ResponseError(response, "GET Request failed");
3089
+ }
3090
+ const rli = readline.createInterface({
3091
+ input: response,
3092
+ crlfDelay: Number.POSITIVE_INFINITY
3093
+ });
3094
+ return new ReadableStream({
3095
+ async start(controller) {
3096
+ try {
3097
+ for await (const line of rli) {
3098
+ const trimmed = line.trim();
3099
+ if (!trimmed) {
3100
+ continue;
3101
+ }
3102
+ try {
3103
+ const data = JSON.parse(trimmed);
3104
+ controller.enqueue(data);
3105
+ } catch (e) {
3106
+ debugLog2("streamPatchesFromScan", `Failed to parse line: ${e}`);
3107
+ }
3108
+ }
3109
+ } catch (error) {
3110
+ controller.error(error);
3111
+ } finally {
3112
+ controller.close();
3113
+ }
3114
+ }
3115
+ });
3116
+ }
3117
+ /**
3118
+ * Update alert triage status for an organization.
3119
+ * Modifies alert resolution status and triage decisions.
3120
+ *
3121
+ * @throws {Error} When server returns 5xx status codes
3122
+ */
3123
+ async updateOrgAlertTriage(orgSlug, alertId, triageData) {
3124
+ try {
3125
+ const data = await this.#executeWithRetry(
3126
+ async () => await getResponseJson(
3127
+ await createRequestWithJson(
3128
+ "PUT",
3129
+ this.#baseUrl,
3130
+ `orgs/${encodeURIComponent(orgSlug)}/triage/${encodeURIComponent(alertId)}`,
3131
+ triageData,
3132
+ this.#reqOptions
3133
+ )
3134
+ )
3135
+ );
3136
+ return this.#handleApiSuccess(data);
3137
+ } catch (e) {
3138
+ return await this.#handleApiError(e);
3139
+ }
3140
+ }
3141
+ /**
3142
+ * Update organization's license policy configuration.* Modifies allowed, restricted, and monitored license types.
3143
+ *
3144
+ * @throws {Error} When server returns 5xx status codes
3145
+ */
3146
+ async updateOrgLicensePolicy(orgSlug, policyData, queryParams) {
3147
+ try {
3148
+ const data = await this.#executeWithRetry(
3149
+ async () => await getResponseJson(
3150
+ await createRequestWithJson(
3151
+ "POST",
3152
+ this.#baseUrl,
3153
+ `orgs/${encodeURIComponent(orgSlug)}/settings/license-policy?${queryToSearchParams(queryParams)}`,
3154
+ policyData,
3155
+ this.#reqOptions
3156
+ )
3157
+ )
3158
+ );
3159
+ return this.#handleApiSuccess(data);
3160
+ } catch (e) {
3161
+ return await this.#handleApiError(e);
3162
+ }
3163
+ }
3164
+ /**
3165
+ * Update configuration for a repository.
3166
+ *
3167
+ * Modifies monitoring settings, branch configuration, and scan preferences.
3168
+ *
3169
+ * @param orgSlug - Organization identifier
3170
+ * @param repoSlug - Repository slug/name
3171
+ * @param params - Configuration updates (description, homepage, default_branch, etc.)
3172
+ * @returns Updated repository details
3173
+ *
3174
+ * @example
3175
+ * ```typescript
3176
+ * const result = await sdk.updateRepository('my-org', 'my-repo', {
3177
+ * description: 'Updated description',
3178
+ * default_branch: 'develop'
3179
+ * })
3180
+ *
3181
+ * if (result.success) {
3182
+ * console.log('Repository updated:', result.data.name)
3183
+ * }
3184
+ * ```
3185
+ *
3186
+ * @see https://docs.socket.dev/reference/updateorgrepo
3187
+ * @apiEndpoint POST /orgs/{org_slug}/repos/{repo_slug}
3188
+ * @quota 1 unit
3189
+ * @scopes repo:write
3190
+ * @throws {Error} When server returns 5xx status codes
3191
+ */
3192
+ async updateRepository(orgSlug, repoSlug, params) {
3193
+ try {
3194
+ const data = await this.#executeWithRetry(
3195
+ async () => await getResponseJson(
3196
+ await createRequestWithJson(
3197
+ "POST",
3198
+ this.#baseUrl,
3199
+ `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}`,
3200
+ params,
3201
+ this.#reqOptions
3202
+ )
3203
+ )
3204
+ );
3205
+ return {
3206
+ cause: void 0,
3207
+ data,
3208
+ error: void 0,
3209
+ status: 200,
3210
+ success: true
3211
+ };
3212
+ } catch (e) {
3213
+ const errorResult = await this.#handleApiError(e);
3214
+ return {
3215
+ cause: errorResult.cause,
3216
+ data: void 0,
3217
+ error: errorResult.error,
3218
+ status: errorResult.status,
3219
+ success: false
3220
+ };
3221
+ }
3222
+ }
3223
+ /**
3224
+ * Update a repository label for an organization.
3225
+ *
3226
+ * Modifies label properties like name. Label names must be non-empty and less than 1000 characters.
3227
+ *
3228
+ * @param orgSlug - Organization identifier
3229
+ * @param labelId - Label identifier
3230
+ * @param labelData - Label updates (typically name property)
3231
+ * @returns Updated label with guaranteed id and name fields
3232
+ *
3233
+ * @example
3234
+ * ```typescript
3235
+ * const result = await sdk.updateRepositoryLabel('my-org', 'label-id-123', { name: 'staging' })
3236
+ *
3237
+ * if (result.success) {
3238
+ * console.log('Label updated:', result.data.name)
3239
+ * console.log('Label ID:', result.data.id)
3240
+ * }
3241
+ * ```
3242
+ *
3243
+ * @see https://docs.socket.dev/reference/updateorgrepolabel
3244
+ * @apiEndpoint PUT /orgs/{org_slug}/repos/labels/{label_id}
3245
+ * @quota 1 unit
3246
+ * @scopes repo-label:update
3247
+ * @throws {Error} When server returns 5xx status codes
3248
+ */
3249
+ async updateRepositoryLabel(orgSlug, labelId, labelData) {
3250
+ try {
3251
+ const data = await this.#executeWithRetry(
3252
+ async () => await getResponseJson(
3253
+ await createRequestWithJson(
3254
+ "PUT",
3255
+ this.#baseUrl,
3256
+ `orgs/${encodeURIComponent(orgSlug)}/repos/labels/${encodeURIComponent(labelId)}`,
3257
+ labelData,
3258
+ this.#reqOptions
3259
+ )
3260
+ )
3261
+ );
3262
+ return {
3263
+ cause: void 0,
3264
+ data,
3265
+ error: void 0,
3266
+ status: 200,
3267
+ success: true
3268
+ };
3269
+ } catch (e) {
3270
+ const errorResult = await this.#handleApiError(e);
3271
+ return {
3272
+ cause: errorResult.cause,
3273
+ data: void 0,
3274
+ error: errorResult.error,
3275
+ status: errorResult.status,
3276
+ success: false
3277
+ };
3278
+ }
3279
+ }
3280
+ /**
3281
+ * Update organization's security policy configuration.* Modifies alert rules, severity thresholds, and enforcement settings.
3282
+ *
3283
+ * @throws {Error} When server returns 5xx status codes
3284
+ */
3285
+ async updateOrgSecurityPolicy(orgSlug, policyData) {
3286
+ try {
3287
+ const data = await this.#executeWithRetry(
3288
+ async () => await getResponseJson(
3289
+ await createRequestWithJson(
3290
+ "POST",
3291
+ this.#baseUrl,
3292
+ `orgs/${encodeURIComponent(orgSlug)}/settings/security-policy`,
3293
+ policyData,
3294
+ this.#reqOptions
3295
+ )
3296
+ )
3297
+ );
3298
+ return this.#handleApiSuccess(data);
3299
+ } catch (e) {
3300
+ return await this.#handleApiError(e);
3301
+ }
3302
+ }
3303
+ /**
3304
+ * Upload manifest files for dependency analysis.
3305
+ * Processes package files to create dependency snapshots and security analysis.
3306
+ *
3307
+ * @throws {Error} When server returns 5xx status codes
3308
+ */
3309
+ async uploadManifestFiles(orgSlug, filepaths, options) {
3310
+ const { pathsRelativeTo = "." } = {
3311
+ __proto__: null,
3312
+ ...options
3313
+ };
3314
+ const basePath = resolveBasePath(pathsRelativeTo);
3315
+ const absFilepaths = resolveAbsPaths(filepaths, basePath);
3316
+ const { invalidPaths, validPaths } = validateFiles(absFilepaths);
3317
+ if (this.#onFileValidation && invalidPaths.length > 0) {
3318
+ const result = await this.#onFileValidation(validPaths, invalidPaths, {
3319
+ operation: "uploadManifestFiles",
3320
+ orgSlug
3321
+ });
3322
+ if (!result.shouldContinue) {
3323
+ return {
3324
+ error: result.errorMessage ?? "File validation failed",
3325
+ status: 400,
3326
+ success: false,
3327
+ ...result.errorCause ? { cause: result.errorCause } : {}
3328
+ };
3329
+ }
3330
+ }
3331
+ if (!this.#onFileValidation && invalidPaths.length > 0) {
3332
+ const samplePaths = invalidPaths.slice(0, 3).join("\n - ");
3333
+ const remaining = invalidPaths.length > 3 ? `
3334
+ ... and ${invalidPaths.length - 3} more` : "";
3335
+ console.warn(
3336
+ `Warning: ${invalidPaths.length} files skipped (unreadable):
3337
+ - ${samplePaths}${remaining}
56
3338
  \u2192 This may occur with Yarn Berry PnP or pnpm symlinks.
57
- \u2192 Try: Run installation command to ensure files are accessible.`)}if(c.length===0){let u=i.slice(0,5).join(`
58
- - `),l=i.length>5?`
59
- ... and ${i.length-5} more`:"";return{cause:[`All ${i.length} files failed validation:`,` - ${u}${l}`,"","\u2192 Common causes:"," \u2022 Yarn Berry PnP virtual filesystem (files are not on disk)"," \u2022 pnpm symlinks pointing to inaccessible locations"," \u2022 Incorrect file permissions"," \u2022 Files were deleted after discovery","","\u2192 Solutions:"," \u2022 Yarn Berry: Use `nodeLinker: node-modules` in .yarnrc.yml"," \u2022 pnpm: Use `node-linker=hoisted` in .npmrc"," \u2022 Check file permissions with: ls -la <file>"," \u2022 Run package manager install command"].join(`
60
- `),error:"No readable manifest files found",status:400,success:!1}}try{let u=await this.#r(async()=>await d(await v(this.#e,`orgs/${encodeURIComponent(t)}/upload-manifest-files`,F(c,n),this.#t)));return this.#n(u)}catch(u){return await this.#s(u)}}async viewPatch(t,e){return await d(await m(this.#e,`orgs/${encodeURIComponent(t)}/patches/view/${encodeURIComponent(e)}`,this.#t))}async downloadPatch(t,e){let s=await import("node:https"),r=await import("node:http"),n=`/blob/${encodeURIComponent(t)}`,i=`${e?.baseUrl||se}${n}`,c=i.startsWith("https:");return await new Promise((u,l)=>{(c?s:r).get(i,g=>{if(g.statusCode===404){let f=[`Blob not found: ${t}`,`\u2192 URL: ${i}`,"\u2192 The patch file may have expired or the hash is incorrect.","\u2192 Verify: The blob hash is correct.","\u2192 Note: Blob URLs may expire after a certain time period."].join(`
61
- `);l(new Error(f));return}if(g.statusCode!==200){let f=[`Failed to download blob: ${g.statusCode} ${g.statusMessage}`,`\u2192 Hash: ${t}`,`\u2192 URL: ${i}`,"\u2192 The blob storage service may be temporarily unavailable.",g.statusCode&&g.statusCode>=500?"\u2192 Try: Retry the download after a short delay.":"\u2192 Verify: The blob hash and URL are correct."].join(`
62
- `);l(new Error(f));return}let p="";g.on("data",f=>{p+=f}),g.on("end",()=>{u(p)}),g.on("error",f=>{l(f)})}).on("error",g=>{let p=g,f=[`Error downloading blob: ${t}`,`\u2192 URL: ${i}`,`\u2192 Network error: ${p.message}`];p.code==="ENOTFOUND"?f.push("\u2192 DNS lookup failed. Cannot resolve blob storage hostname.","\u2192 Check: Internet connection and DNS settings."):p.code==="ECONNREFUSED"?f.push("\u2192 Connection refused. Blob storage service is unreachable.","\u2192 Check: Network connectivity and firewall settings."):p.code==="ETIMEDOUT"?f.push("\u2192 Connection timed out.","\u2192 Try: Check network connectivity and retry."):p.code&&f.push(`\u2192 Error code: ${p.code}`),l(new Error(f.join(`
63
- `),{cause:g}))})})}};if(qe("heap")){let o=process.memoryUsage();ge("heap",`heap used: ${Math.round(o.heapUsed/1024/1024)}MB`)}export{q as DEFAULT_USER_AGENT,R as ResponseError,Y as SocketSdk,ue as calculateTotalQuotaCost,A as createDeleteRequest,m as createGetRequest,F as createRequestBodyForFilepaths,Ee as createRequestBodyForJson,y as createRequestWithJson,v as createUploadRequest,x as createUserAgentFromPkgJson,Ce as getAllMethodRequirements,L as getErrorResponseBody,P as getHttpModule,$e as getMethodRequirements,Ue as getMethodsByPermissions,Fe as getMethodsByQuotaCost,de as getQuotaCost,ve as getQuotaUsageSummary,xe as getRequiredPermissions,T as getResponse,d as getResponseJson,Le as hasQuotaForMethods,G as httpAgentNames,O as isResponseOk,Q as normalizeBaseUrl,z as promiseWithResolvers,fe as publicPolicy,k as queryToSearchParams,M as reshapeArtifactForPublicPolicy,U as resolveAbsPaths,I as resolveBasePath};
3339
+ \u2192 Try: Run installation command to ensure files are accessible.`
3340
+ );
3341
+ }
3342
+ if (validPaths.length === 0) {
3343
+ const samplePaths = invalidPaths.slice(0, 5).join("\n - ");
3344
+ const remaining = invalidPaths.length > 5 ? `
3345
+ ... and ${invalidPaths.length - 5} more` : "";
3346
+ return {
3347
+ cause: [
3348
+ `All ${invalidPaths.length} files failed validation:`,
3349
+ ` - ${samplePaths}${remaining}`,
3350
+ "",
3351
+ "\u2192 Common causes:",
3352
+ " \u2022 Yarn Berry PnP virtual filesystem (files are not on disk)",
3353
+ " \u2022 pnpm symlinks pointing to inaccessible locations",
3354
+ " \u2022 Incorrect file permissions",
3355
+ " \u2022 Files were deleted after discovery",
3356
+ "",
3357
+ "\u2192 Solutions:",
3358
+ " \u2022 Yarn Berry: Use `nodeLinker: node-modules` in .yarnrc.yml",
3359
+ " \u2022 pnpm: Use `node-linker=hoisted` in .npmrc",
3360
+ " \u2022 Check file permissions with: ls -la <file>",
3361
+ " \u2022 Run package manager install command"
3362
+ ].join("\n"),
3363
+ error: "No readable manifest files found",
3364
+ status: 400,
3365
+ success: false
3366
+ };
3367
+ }
3368
+ try {
3369
+ const data = await this.#executeWithRetry(
3370
+ async () => await getResponseJson(
3371
+ await createUploadRequest(
3372
+ this.#baseUrl,
3373
+ `orgs/${encodeURIComponent(orgSlug)}/upload-manifest-files`,
3374
+ createRequestBodyForFilepaths(validPaths, basePath),
3375
+ this.#reqOptions
3376
+ )
3377
+ )
3378
+ );
3379
+ return this.#handleApiSuccess(
3380
+ data
3381
+ );
3382
+ } catch (e) {
3383
+ return await this.#handleApiError(
3384
+ e
3385
+ );
3386
+ }
3387
+ }
3388
+ /**
3389
+ * View detailed information about a specific patch by its UUID.
3390
+ *
3391
+ * This method retrieves comprehensive patch details including files,
3392
+ * vulnerabilities, description, license, and tier information.
3393
+ */
3394
+ async viewPatch(orgSlug, uuid) {
3395
+ const data = await getResponseJson(
3396
+ await createGetRequest(
3397
+ this.#baseUrl,
3398
+ `orgs/${encodeURIComponent(orgSlug)}/patches/view/${encodeURIComponent(uuid)}`,
3399
+ this.#reqOptions
3400
+ )
3401
+ );
3402
+ return data;
3403
+ }
3404
+ /**
3405
+ * Download patch file content by hash.
3406
+ *
3407
+ * Downloads the actual patched file content from the public Socket blob store.
3408
+ * This is used after calling viewPatch() to get the patch metadata.
3409
+ * No authentication is required as patch blobs are publicly accessible.
3410
+ *
3411
+ * @param hash - The blob hash in SSRI (sha256-base64) or hex format
3412
+ * @param options - Optional configuration
3413
+ * @param options.baseUrl - Override blob store URL (for testing)
3414
+ * @returns Promise<string> - The patch file content as UTF-8 string
3415
+ * @throws Error if blob not found (404) or download fails
3416
+ *
3417
+ * @example
3418
+ * ```typescript
3419
+ * const sdk = new SocketSdk('your-api-token')
3420
+ * // First get patch metadata
3421
+ * const patch = await sdk.viewPatch('my-org', 'patch-uuid')
3422
+ * // Then download the actual patched file
3423
+ * const fileContent = await sdk.downloadPatch(patch.files['index.js'].socketBlob)
3424
+ * ```
3425
+ */
3426
+ async downloadPatch(hash, options) {
3427
+ const https2 = await import("node:https");
3428
+ const http2 = await import("node:http");
3429
+ const blobPath = `/blob/${encodeURIComponent(hash)}`;
3430
+ const blobBaseUrl = options?.baseUrl || SOCKET_PUBLIC_BLOB_STORE_URL;
3431
+ const url = `${blobBaseUrl}${blobPath}`;
3432
+ const isHttps = url.startsWith("https:");
3433
+ return await new Promise((resolve, reject) => {
3434
+ const client = isHttps ? https2 : http2;
3435
+ client.get(url, (res) => {
3436
+ if (res.statusCode === 404) {
3437
+ const message = [
3438
+ `Blob not found: ${hash}`,
3439
+ `\u2192 URL: ${url}`,
3440
+ "\u2192 The patch file may have expired or the hash is incorrect.",
3441
+ "\u2192 Verify: The blob hash is correct.",
3442
+ "\u2192 Note: Blob URLs may expire after a certain time period."
3443
+ ].join("\n");
3444
+ reject(new Error(message));
3445
+ return;
3446
+ }
3447
+ if (res.statusCode !== 200) {
3448
+ const message = [
3449
+ `Failed to download blob: ${res.statusCode} ${res.statusMessage}`,
3450
+ `\u2192 Hash: ${hash}`,
3451
+ `\u2192 URL: ${url}`,
3452
+ "\u2192 The blob storage service may be temporarily unavailable.",
3453
+ res.statusCode && res.statusCode >= 500 ? "\u2192 Try: Retry the download after a short delay." : "\u2192 Verify: The blob hash and URL are correct."
3454
+ ].join("\n");
3455
+ reject(new Error(message));
3456
+ return;
3457
+ }
3458
+ let data = "";
3459
+ res.on("data", (chunk) => {
3460
+ data += chunk;
3461
+ });
3462
+ res.on("end", () => {
3463
+ resolve(data);
3464
+ });
3465
+ res.on("error", (err) => {
3466
+ reject(err);
3467
+ });
3468
+ }).on("error", (err) => {
3469
+ const nodeErr = err;
3470
+ const message = [
3471
+ `Error downloading blob: ${hash}`,
3472
+ `\u2192 URL: ${url}`,
3473
+ `\u2192 Network error: ${nodeErr.message}`
3474
+ ];
3475
+ if (nodeErr.code === "ENOTFOUND") {
3476
+ message.push(
3477
+ "\u2192 DNS lookup failed. Cannot resolve blob storage hostname.",
3478
+ "\u2192 Check: Internet connection and DNS settings."
3479
+ );
3480
+ } else if (nodeErr.code === "ECONNREFUSED") {
3481
+ message.push(
3482
+ "\u2192 Connection refused. Blob storage service is unreachable.",
3483
+ "\u2192 Check: Network connectivity and firewall settings."
3484
+ );
3485
+ } else if (nodeErr.code === "ETIMEDOUT") {
3486
+ message.push(
3487
+ "\u2192 Connection timed out.",
3488
+ "\u2192 Try: Check network connectivity and retry."
3489
+ );
3490
+ } else if (nodeErr.code) {
3491
+ message.push(`\u2192 Error code: ${nodeErr.code}`);
3492
+ }
3493
+ reject(new Error(message.join("\n"), { cause: err }));
3494
+ });
3495
+ });
3496
+ }
3497
+ };
3498
+ if (isDebugNs("heap")) {
3499
+ const used = process.memoryUsage();
3500
+ debugLog2("heap", `heap used: ${Math.round(used.heapUsed / 1024 / 1024)}MB`);
3501
+ }
3502
+ export {
3503
+ DEFAULT_USER_AGENT,
3504
+ ResponseError,
3505
+ SocketSdk,
3506
+ calculateTotalQuotaCost,
3507
+ createDeleteRequest,
3508
+ createGetRequest,
3509
+ createRequestBodyForFilepaths,
3510
+ createRequestBodyForJson,
3511
+ createRequestWithJson,
3512
+ createUploadRequest,
3513
+ createUserAgentFromPkgJson,
3514
+ getAllMethodRequirements,
3515
+ getErrorResponseBody,
3516
+ getHttpModule,
3517
+ getMethodRequirements,
3518
+ getMethodsByPermissions,
3519
+ getMethodsByQuotaCost,
3520
+ getQuotaCost,
3521
+ getQuotaUsageSummary,
3522
+ getRequiredPermissions,
3523
+ getResponse,
3524
+ getResponseJson,
3525
+ hasQuotaForMethods,
3526
+ httpAgentNames,
3527
+ isResponseOk,
3528
+ normalizeBaseUrl,
3529
+ promiseWithResolvers,
3530
+ publicPolicy,
3531
+ queryToSearchParams,
3532
+ reshapeArtifactForPublicPolicy,
3533
+ resolveAbsPaths,
3534
+ resolveBasePath
3535
+ };