@socketsecurity/sdk 3.0.26 → 3.0.28

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