@socketsecurity/sdk 1.11.2 → 2.0.2

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.
@@ -1,1511 +0,0 @@
1
- 'use strict';
2
-
3
- var events = require('node:events');
4
- var node_fs = require('node:fs');
5
- var readline = require('node:readline');
6
- var cacheWithTtl = require('@socketsecurity/registry/lib/cache-with-ttl');
7
- var SOCKET_PUBLIC_API_TOKEN = require('@socketsecurity/registry/lib/constants/SOCKET_PUBLIC_API_TOKEN');
8
- var UNKNOWN_ERROR = require('@socketsecurity/registry/lib/constants/UNKNOWN_ERROR');
9
- var abortSignal = require('@socketsecurity/registry/lib/constants/abort-signal');
10
- var debug = require('@socketsecurity/registry/lib/debug');
11
- var json = require('@socketsecurity/registry/lib/json');
12
- var objects = require('@socketsecurity/registry/lib/objects');
13
- var promises = require('@socketsecurity/registry/lib/promises');
14
- var url = require('@socketsecurity/registry/lib/url');
15
- var constants = require('./constants.js');
16
- var fileUpload = require('./file-upload.js');
17
- var httpClient = require('./http-client.js');
18
- var utils = require('./utils.js');
19
-
20
- /**
21
- * @fileoverview SocketSdk class implementation for Socket security API client.
22
- * Provides complete API functionality for vulnerability scanning, analysis, and reporting.
23
- */
24
- /**
25
- * Socket SDK for programmatic access to Socket.dev security analysis APIs.
26
- * Provides methods for package scanning, organization management, and security analysis.
27
- */
28
- class SocketSdk {
29
- #apiToken;
30
- #baseUrl;
31
- #cache;
32
- #reqOptions;
33
- #retries;
34
- #retryDelay;
35
-
36
- /**
37
- * Initialize Socket SDK with API token and configuration options.
38
- * Sets up authentication, base URL, HTTP client options, retry behavior, and caching.
39
- */
40
- constructor(apiToken, options) {
41
- const {
42
- agent: agentOrObj,
43
- baseUrl = 'https://api.socket.dev/v0/',
44
- cache = false,
45
- cacheTtl = 5 * 60 * 1000,
46
- retries = 0,
47
- retryDelay = 100,
48
- timeout,
49
- userAgent
50
- } = {
51
- __proto__: null,
52
- ...options
53
- };
54
- const agentKeys = agentOrObj ? Object.keys(agentOrObj) : [];
55
- const agentAsGotOptions = agentOrObj;
56
- const agent = agentKeys.length && agentKeys.every(k => constants.httpAgentNames.has(k)) ? /* c8 ignore next 3 - Got-style agent options compatibility layer */
57
- agentAsGotOptions.https || agentAsGotOptions.http || agentAsGotOptions.http2 : agentOrObj;
58
- this.#apiToken = apiToken;
59
- this.#baseUrl = utils.normalizeBaseUrl(baseUrl);
60
- this.#cache = cache ? cacheWithTtl.createTtlCache({
61
- memoize: true,
62
- prefix: 'socket-sdk',
63
- ttl: cacheTtl
64
- }) : undefined;
65
- this.#retries = retries;
66
- this.#retryDelay = retryDelay;
67
- this.#reqOptions = {
68
- ...(agent ? {
69
- agent
70
- } : {}),
71
- headers: {
72
- Authorization: `Basic ${btoa(`${apiToken}:`)}`,
73
- 'User-Agent': userAgent ?? constants.DEFAULT_USER_AGENT
74
- },
75
- signal: abortSignal,
76
- ...(timeout ? {
77
- timeout
78
- } : {})
79
- };
80
- }
81
-
82
- /**
83
- * Execute an HTTP request with retry logic.
84
- * Internal method for wrapping HTTP operations with exponential backoff.
85
- */
86
- async #executeWithRetry(operation) {
87
- const result = await promises.pRetry(operation, {
88
- baseDelayMs: this.#retryDelay,
89
- onRetry(_attempt, error) {
90
- /* c8 ignore next 3 - Early return for non-ResponseError types in retry logic */
91
- if (!(error instanceof httpClient.ResponseError)) {
92
- return;
93
- }
94
- const {
95
- statusCode
96
- } = error.response;
97
- // Don't retry authentication/authorization errors - they won't succeed.
98
- if (statusCode === 401 || statusCode === 403) {
99
- throw error;
100
- }
101
- },
102
- onRetryRethrow: true,
103
- retries: this.#retries
104
- });
105
- /* c8 ignore next 3 - Defensive check for undefined result from pRetry abort */
106
- if (result === undefined) {
107
- throw new Error('Request aborted');
108
- }
109
- return result;
110
- }
111
-
112
- /**
113
- * Execute a GET request with optional caching.
114
- * Internal method for handling cached GET requests with retry logic.
115
- */
116
- async #getCached(cacheKey, fetcher) {
117
- // If caching is disabled, just execute the request.
118
- if (!this.#cache) {
119
- return await this.#executeWithRetry(fetcher);
120
- }
121
-
122
- // Use cache with retry logic.
123
- return await this.#cache.getOrFetch(cacheKey, async () => {
124
- return await this.#executeWithRetry(fetcher);
125
- });
126
- }
127
-
128
- /**
129
- * Create async generator for streaming batch package URL processing.
130
- * Internal method for handling chunked PURL responses with error handling.
131
- */
132
- async *#createBatchPurlGenerator(componentsObj, queryParams) {
133
- let res;
134
- try {
135
- res = await this.#executeWithRetry(() => this.#createBatchPurlRequest(componentsObj, queryParams));
136
- } catch (e) {
137
- yield await this.#handleApiError(e);
138
- return;
139
- }
140
- // Validate response before processing.
141
- /* c8 ignore next 3 - Defensive check, response should always be defined after successful request */
142
- if (!res) {
143
- throw new Error('Failed to get response from batch PURL request');
144
- }
145
- // Parse the newline delimited JSON response.
146
- const rli = readline.createInterface({
147
- input: res,
148
- crlfDelay: Number.POSITIVE_INFINITY,
149
- signal: abortSignal
150
- });
151
- const isPublicToken = this.#apiToken === SOCKET_PUBLIC_API_TOKEN;
152
- for await (const line of rli) {
153
- const trimmed = line.trim();
154
- const artifact = trimmed ? json.jsonParse(line, {
155
- throws: false
156
- }) : /* c8 ignore next - Empty line handling in batch streaming response parsing. */null;
157
- if (objects.isObjectObject(artifact)) {
158
- yield this.#handleApiSuccess(isPublicToken ? /* c8 ignore start - Public token artifact reshaping branch for policy compliance. */httpClient.reshapeArtifactForPublicPolicy(artifact, false, queryParams?.['actions']) : /* c8 ignore stop */
159
- artifact);
160
- }
161
- }
162
- }
163
-
164
- /**
165
- * Create HTTP request for batch package URL processing.
166
- * Internal method for handling PURL batch API calls with retry logic.
167
- */
168
- async #createBatchPurlRequest(componentsObj, queryParams) {
169
- // Adds the first 'abort' listener to abortSignal.
170
- const req = httpClient.getHttpModule(this.#baseUrl).request(`${this.#baseUrl}purl?${utils.queryToSearchParams(queryParams)}`, {
171
- method: 'POST',
172
- ...this.#reqOptions
173
- }).end(JSON.stringify(componentsObj));
174
- const response = await httpClient.getResponse(req);
175
-
176
- // Throw ResponseError for non-2xx status codes so retry logic works properly.
177
- if (!httpClient.isResponseOk(response)) {
178
- throw new httpClient.ResponseError(response);
179
- }
180
- return response;
181
- }
182
-
183
- /**
184
- * Create standardized error result from query operation exceptions.
185
- * Internal error handling for non-throwing query API methods.
186
- */
187
- #createQueryErrorResult(e) {
188
- if (e instanceof SyntaxError) {
189
- // Try to get response text from enhanced error, fall back to regex pattern for compatibility.
190
- const enhancedError = e;
191
- /* c8 ignore next - Defensive empty string fallback for originalResponse. */
192
- let responseText = enhancedError.originalResponse || '';
193
-
194
- /* c8 ignore next 5 - Empty response text fallback check for JSON parsing errors without originalResponse. */
195
- if (!responseText) {
196
- const match = e.message.match(/Invalid JSON response:\n([\s\S]*?)\n→/);
197
- responseText = match?.[1] || '';
198
- }
199
-
200
- /* c8 ignore next - Defensive empty string fallback when slice returns empty. */
201
- const preview = responseText.slice(0, 100) || '';
202
- return {
203
- cause: `Please report this. JSON.parse threw an error over the following response: \`${preview.trim()}${responseText.length > 100 ? '...' : ''}\``,
204
- data: undefined,
205
- error: 'Server returned invalid JSON',
206
- status: 0,
207
- success: false
208
- };
209
- }
210
-
211
- /* c8 ignore start - Defensive error stringification fallback branches for edge cases. */
212
- const errStr = e ? String(e).trim() : '';
213
- return {
214
- cause: errStr || UNKNOWN_ERROR,
215
- data: undefined,
216
- error: 'API request failed',
217
- status: 0,
218
- success: false
219
- };
220
- /* c8 ignore stop */
221
- }
222
-
223
- /**
224
- * Extract text content from HTTP response stream.
225
- * Internal method with size limits to prevent memory exhaustion.
226
- */
227
- async #getResponseText(response) {
228
- const chunks = [];
229
- let size = 0;
230
- // 50MB limit to prevent out-of-memory errors from large responses.
231
- const MAX = 50 * 1024 * 1024;
232
- for await (const chunk of response) {
233
- size += chunk.length;
234
- /* c8 ignore next 3 - MAX size limit protection for edge cases */
235
- if (size > MAX) {
236
- throw new Error('Response body exceeds maximum size limit');
237
- }
238
- chunks.push(chunk);
239
- }
240
- return Buffer.concat(chunks).toString('utf8');
241
- }
242
-
243
- /**
244
- * Handle API error responses and convert to standardized error result.
245
- * Internal error handling with status code analysis and message formatting.
246
- */
247
- async #handleApiError(error) {
248
- if (!(error instanceof httpClient.ResponseError)) {
249
- throw new Error('Unexpected Socket API error', {
250
- cause: error
251
- });
252
- }
253
- const {
254
- statusCode
255
- } = error.response;
256
- // Throw server errors (5xx) immediately - these are not recoverable client-side.
257
- if (statusCode && statusCode >= 500) {
258
- throw new Error(`Socket API server error (${statusCode})`, {
259
- cause: error
260
- });
261
- }
262
- // The error payload may give a meaningful hint as to what went wrong.
263
- const bodyStr = await httpClient.getErrorResponseBody(error.response);
264
- // Try to parse the body as JSON, fallback to treating as plain text.
265
- let body;
266
- try {
267
- const parsed = JSON.parse(bodyStr);
268
- // Client errors (4xx) should return actionable error messages.
269
- // Extract both message and details from error response for better context.
270
- if (typeof parsed?.error?.message === 'string') {
271
- body = parsed.error.message;
272
-
273
- // Include details if present for additional error context.
274
- if (parsed.error.details) {
275
- const detailsStr = typeof parsed.error.details === 'string' ? parsed.error.details : JSON.stringify(parsed.error.details);
276
- body = `${body} - Details: ${detailsStr}`;
277
- }
278
- }
279
- } catch {
280
- body = bodyStr;
281
- }
282
- // Build error message that includes the body content if available.
283
- let errorMessage = error.message ?? UNKNOWN_ERROR;
284
- const trimmedBody = body?.trim();
285
- if (trimmedBody && !errorMessage.includes(trimmedBody)) {
286
- // Replace generic status message with actual error body if present,
287
- // otherwise append the body to the error message.
288
- const statusMessage = error.response?.statusMessage;
289
- if (statusMessage && errorMessage.includes(statusMessage)) {
290
- errorMessage = errorMessage.replace(statusMessage, trimmedBody);
291
- } else {
292
- /* c8 ignore next 2 - edge case where statusMessage is undefined or not in error message. */
293
- errorMessage = `${errorMessage}: ${trimmedBody}`;
294
- }
295
- }
296
- return {
297
- cause: body,
298
- data: undefined,
299
- error: errorMessage,
300
- /* c8 ignore next - fallback for missing status code in edge cases. */
301
- status: statusCode ?? 0,
302
- success: false
303
- };
304
- }
305
-
306
- /**
307
- * Handle successful API responses and convert to standardized success result.
308
- * Internal success handling with consistent response formatting.
309
- */
310
- #handleApiSuccess(data) {
311
- return {
312
- cause: undefined,
313
- data: data,
314
- error: undefined,
315
- // Use generic 200 OK status for all successful API responses.
316
- status: 200,
317
- success: true
318
- };
319
- }
320
-
321
- /**
322
- * Handle query API response data based on requested response type.
323
- * Internal method for processing different response formats (json, text, response).
324
- */
325
- async #handleQueryResponseData(response, responseType) {
326
- if (responseType === 'response') {
327
- return response;
328
- }
329
- if (responseType === 'text') {
330
- return await this.#getResponseText(response);
331
- }
332
- if (responseType === 'json') {
333
- return await httpClient.getResponseJson(response);
334
- }
335
- return response;
336
- }
337
-
338
- /**
339
- * Fetch package analysis data for multiple packages in a single batch request.
340
- * Returns all results at once after processing is complete.
341
- *
342
- * @throws {Error} When server returns 5xx status codes
343
- */
344
- async batchPackageFetch(componentsObj, queryParams) {
345
- let res;
346
- try {
347
- res = await this.#createBatchPurlRequest(componentsObj, queryParams);
348
- } catch (e) {
349
- return await this.#handleApiError(e);
350
- }
351
- // Validate response before processing.
352
- /* c8 ignore next 3 - Defensive check, response should always be defined after successful request */
353
- if (!res) {
354
- throw new Error('Failed to get response from batch PURL request');
355
- }
356
- // Parse the newline delimited JSON response.
357
- const rli = readline.createInterface({
358
- input: res,
359
- crlfDelay: Number.POSITIVE_INFINITY,
360
- signal: abortSignal
361
- });
362
- const isPublicToken = this.#apiToken === SOCKET_PUBLIC_API_TOKEN;
363
- const results = [];
364
- for await (const line of rli) {
365
- const trimmed = line.trim();
366
- const artifact = trimmed ? json.jsonParse(line, {
367
- throws: false
368
- }) : /* c8 ignore next - Empty line handling in batch parsing. */null;
369
- if (objects.isObjectObject(artifact)) {
370
- results.push(isPublicToken ? /* c8 ignore start - Public token artifact reshaping for policy compliance. */
371
- httpClient.reshapeArtifactForPublicPolicy(artifact, false, queryParams?.['actions']) : /* c8 ignore stop */
372
- artifact);
373
- }
374
- }
375
- const compact = url.urlSearchParamAsBoolean(objects.getOwn(queryParams, 'compact'));
376
- return this.#handleApiSuccess(compact ? results : results);
377
- }
378
-
379
- /**
380
- * Stream package analysis data for multiple packages with chunked processing and concurrency control.
381
- * Returns results as they become available via async generator.
382
- *
383
- * @throws {Error} When server returns 5xx status codes
384
- */
385
- async *batchPackageStream(componentsObj, options) {
386
- const {
387
- chunkSize = 100,
388
- concurrencyLimit = 10,
389
- queryParams
390
- } = {
391
- __proto__: null,
392
- ...options
393
- };
394
- // The createBatchPurlGenerator method will add 2 'abort' event listeners to
395
- // abortSignal so we multiply the concurrencyLimit by 2.
396
- const neededMaxListeners = concurrencyLimit * 2;
397
- // Increase abortSignal max listeners count to avoid Node's MaxListenersExceededWarning.
398
- const oldAbortSignalMaxListeners = events.getMaxListeners(abortSignal);
399
- let abortSignalMaxListeners = oldAbortSignalMaxListeners;
400
- /* c8 ignore start - EventTarget max listeners adjustment for high concurrency batch operations, difficult to test reliably. */
401
- if (oldAbortSignalMaxListeners < neededMaxListeners) {
402
- abortSignalMaxListeners = oldAbortSignalMaxListeners + neededMaxListeners;
403
- events.setMaxListeners(abortSignalMaxListeners, abortSignal);
404
- }
405
- /* c8 ignore stop */
406
- const {
407
- components
408
- } = componentsObj;
409
- const {
410
- length: componentsCount
411
- } = components;
412
- const running = [];
413
- let index = 0;
414
- const enqueueGen = () => {
415
- if (index >= componentsCount) {
416
- // No more work to do.
417
- return;
418
- }
419
- const generator = this.#createBatchPurlGenerator({
420
- // Chunk components.
421
- components: components.slice(index, index + chunkSize)
422
- }, queryParams);
423
- continueGen(generator);
424
- index += chunkSize;
425
- };
426
- const continueGen = generator => {
427
- const {
428
- promise,
429
- reject: rejectFn,
430
- resolve: resolveFn
431
- } = utils.promiseWithResolvers();
432
- running.push({
433
- generator,
434
- promise
435
- });
436
- void generator.next().then(iteratorResult => resolveFn({
437
- generator,
438
- iteratorResult
439
- }), rejectFn);
440
- };
441
- // Start initial batch of generators.
442
- while (running.length < concurrencyLimit && index < componentsCount) {
443
- enqueueGen();
444
- }
445
- while (running.length > 0) {
446
- // eslint-disable-next-line no-await-in-loop
447
- const {
448
- generator,
449
- iteratorResult
450
- } = await Promise.race(running.map(entry => entry.promise));
451
- // Remove generator with safe index lookup.
452
- const index = running.findIndex(entry => entry.generator === generator);
453
- /* c8 ignore next 3 - Defensive check for concurrent generator cleanup edge case. */
454
- if (index === -1) {
455
- continue;
456
- }
457
- running.splice(index, 1);
458
- // Yield the value if one is given, even when done:true.
459
- if (iteratorResult.value) {
460
- yield iteratorResult.value;
461
- }
462
- if (iteratorResult.done) {
463
- // Start a new generator if available.
464
- enqueueGen();
465
- } else {
466
- // Keep fetching values from this generator.
467
- continueGen(generator);
468
- }
469
- }
470
- // Reset abortSignal max listeners count.
471
- /* c8 ignore start - Reset EventTarget max listeners to original value after batch operations. */
472
- if (abortSignalMaxListeners > oldAbortSignalMaxListeners) {
473
- events.setMaxListeners(oldAbortSignalMaxListeners, abortSignal);
474
- }
475
- /* c8 ignore stop */
476
- }
477
-
478
- /**
479
- * Create a snapshot of project dependencies by uploading manifest files.
480
- * Analyzes dependency files to generate a comprehensive security report.
481
- *
482
- * @throws {Error} When server returns 5xx status codes
483
- */
484
- async createDependenciesSnapshot(filepaths, options) {
485
- const {
486
- pathsRelativeTo = '.',
487
- queryParams
488
- } = {
489
- __proto__: null,
490
- ...options
491
- };
492
- const basePath = utils.resolveBasePath(pathsRelativeTo);
493
- const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
494
- try {
495
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, `dependencies/upload?${utils.queryToSearchParams(queryParams)}`, fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), this.#reqOptions)));
496
- return this.#handleApiSuccess(data);
497
- } catch (e) {
498
- return await this.#handleApiError(e);
499
- }
500
- }
501
-
502
- /**
503
- * Create a diff scan from two full scan IDs.
504
- * Compares two existing full scans to identify changes.
505
- *
506
- * @throws {Error} When server returns 5xx status codes
507
- */
508
- async createOrgDiffScanFromIds(orgSlug, queryParams) {
509
- try {
510
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans?${utils.queryToSearchParams(queryParams)}`, {}, this.#reqOptions)));
511
- return this.#handleApiSuccess(data);
512
- } catch (e) {
513
- return await this.#handleApiError(e);
514
- }
515
- }
516
-
517
- /**
518
- * Create a comprehensive security scan for an organization.
519
- * Uploads project files and initiates full security analysis.
520
- *
521
- * @throws {Error} When server returns 5xx status codes
522
- */
523
- async createOrgFullScan(orgSlug, filepaths, options) {
524
- const {
525
- pathsRelativeTo = '.',
526
- queryParams
527
- } = {
528
- __proto__: null,
529
- ...options
530
- };
531
- const basePath = utils.resolveBasePath(pathsRelativeTo);
532
- const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
533
- try {
534
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans?${utils.queryToSearchParams(queryParams)}`, fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), this.#reqOptions)));
535
- return this.#handleApiSuccess(data);
536
- } catch (e) {
537
- return await this.#handleApiError(e);
538
- }
539
- }
540
-
541
- /**
542
- * Create a new repository in an organization.
543
- * Registers a repository for monitoring and security scanning.
544
- *
545
- * @throws {Error} When server returns 5xx status codes
546
- */
547
- async createOrgRepo(orgSlug, queryParams) {
548
- try {
549
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos`, queryParams, this.#reqOptions)));
550
- return this.#handleApiSuccess(data);
551
- } catch (e) {
552
- return await this.#handleApiError(e);
553
- }
554
- }
555
-
556
- /**
557
- * Create a new repository label for an organization.
558
- * Adds label for repository categorization and management.
559
- *
560
- * @throws {Error} When server returns 5xx status codes
561
- */
562
- async createOrgRepoLabel(orgSlug, repoSlug, labelData) {
563
- try {
564
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels`, labelData, this.#reqOptions)));
565
- return this.#handleApiSuccess(data);
566
- } catch (e) {
567
- return await this.#handleApiError(e);
568
- }
569
- }
570
-
571
- /**
572
- * Create a security scan by uploading project files.
573
- * Analyzes uploaded files for security vulnerabilities and policy violations.
574
- *
575
- * @throws {Error} When server returns 5xx status codes
576
- */
577
- async createScanFromFilepaths(filepaths, options) {
578
- const {
579
- issueRules,
580
- pathsRelativeTo = '.'
581
- } = {
582
- __proto__: null,
583
- ...options
584
- };
585
- const basePath = utils.resolveBasePath(pathsRelativeTo);
586
- const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
587
- try {
588
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, 'report/upload', [...fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), /* c8 ignore next 3 - Optional issueRules parameter edge case. */
589
- ...(issueRules ? fileUpload.createRequestBodyForJson(issueRules, 'issueRules') : [])], {
590
- ...this.#reqOptions,
591
- method: 'PUT'
592
- })
593
- /* c8 ignore next 3 - Success path return statement requires complex file upload mocking with authentication. */));
594
- return this.#handleApiSuccess(data);
595
- } catch (e) {
596
- return await this.#handleApiError(e);
597
- }
598
- }
599
-
600
- /**
601
- * Delete a diff scan from an organization.
602
- * Permanently removes diff scan data and results.
603
- *
604
- * @throws {Error} When server returns 5xx status codes
605
- */
606
- async deleteOrgDiffScan(orgSlug, diffScanId) {
607
- try {
608
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`, this.#reqOptions)));
609
- return this.#handleApiSuccess(data);
610
- } catch (e) {
611
- return await this.#handleApiError(e);
612
- }
613
- }
614
-
615
- /**
616
- * Delete a full scan from an organization.
617
- * Permanently removes scan data and results.
618
- *
619
- * @throws {Error} When server returns 5xx status codes
620
- */
621
- async deleteOrgFullScan(orgSlug, fullScanId) {
622
- try {
623
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, this.#reqOptions)));
624
- return this.#handleApiSuccess(data);
625
- } catch (e) {
626
- return await this.#handleApiError(e);
627
- }
628
- }
629
-
630
- /**
631
- * Delete a repository from an organization.
632
- * Removes repository monitoring and associated scan data.
633
- *
634
- * @throws {Error} When server returns 5xx status codes
635
- */
636
- async deleteOrgRepo(orgSlug, repoSlug) {
637
- try {
638
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}`, this.#reqOptions)));
639
- return this.#handleApiSuccess(data);
640
- } catch (e) {
641
- return await this.#handleApiError(e);
642
- }
643
- }
644
-
645
- /**
646
- * Delete a repository label from an organization.
647
- * Removes label and associated configuration.
648
- *
649
- * @throws {Error} When server returns 5xx status codes
650
- */
651
- async deleteOrgRepoLabel(orgSlug, repoSlug, labelSlug) {
652
- try {
653
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, this.#reqOptions)));
654
- return this.#handleApiSuccess(data);
655
- } catch (e) {
656
- return await this.#handleApiError(e);
657
- }
658
- }
659
-
660
- /**
661
- * Delete a scan report permanently.
662
- * Removes scan data and analysis results from the system.
663
- *
664
- * @throws {Error} When server returns 5xx status codes
665
- */
666
- async deleteReport(reportId) {
667
- try {
668
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `report/delete/${encodeURIComponent(reportId)}`, this.#reqOptions)));
669
- return this.#handleApiSuccess(data);
670
- } catch (e) {
671
- return await this.#handleApiError(e);
672
- }
673
- }
674
-
675
- /**
676
- * Export scan results in CycloneDX SBOM format.
677
- * Returns Software Bill of Materials compliant with CycloneDX standard.
678
- *
679
- * @throws {Error} When server returns 5xx status codes
680
- */
681
- async exportCDX(orgSlug, fullScanId) {
682
- try {
683
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/cdx`, this.#reqOptions)));
684
- return this.#handleApiSuccess(data);
685
- } catch (e) {
686
- return await this.#handleApiError(e);
687
- }
688
- }
689
-
690
- /**
691
- * Export scan results in SPDX SBOM format.
692
- * Returns Software Bill of Materials compliant with SPDX standard.
693
- *
694
- * @throws {Error} When server returns 5xx status codes
695
- */
696
- async exportSPDX(orgSlug, fullScanId) {
697
- try {
698
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/spdx`, this.#reqOptions)));
699
- return this.#handleApiSuccess(data);
700
- } catch (e) {
701
- return await this.#handleApiError(e);
702
- }
703
- }
704
-
705
- /**
706
- * Execute a raw GET request to any API endpoint with configurable response type.
707
- * Supports both throwing (default) and non-throwing modes.
708
- * @param urlPath - API endpoint path (e.g., 'organizations')
709
- * @param options - Request options including responseType and throws behavior
710
- * @returns Raw response, parsed data, or SocketSdkGenericResult based on options
711
- */
712
- async getApi(urlPath, options) {
713
- const {
714
- responseType = 'response',
715
- throws = true
716
- } = {
717
- __proto__: null,
718
- ...options
719
- };
720
- try {
721
- const response = await httpClient.createGetRequest(this.#baseUrl, urlPath, this.#reqOptions);
722
- // Check for HTTP error status codes first.
723
- if (!httpClient.isResponseOk(response)) {
724
- if (throws) {
725
- throw new httpClient.ResponseError(response);
726
- }
727
- const errorResult = await this.#handleApiError(new httpClient.ResponseError(response));
728
- return {
729
- cause: errorResult.cause,
730
- data: undefined,
731
- error: errorResult.error,
732
- status: errorResult.status,
733
- success: false
734
- };
735
- }
736
- const data = await this.#handleQueryResponseData(response, responseType);
737
- if (throws) {
738
- return data;
739
- }
740
- return {
741
- cause: undefined,
742
- data,
743
- error: undefined,
744
- /* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
745
- status: response.statusCode ?? 200,
746
- success: true
747
- };
748
- } catch (e) {
749
- if (throws) {
750
- throw e;
751
- }
752
-
753
- /* c8 ignore start - Defensive fallback: ResponseError in catch block handled in try block (lines 897-910) */
754
- if (e instanceof httpClient.ResponseError) {
755
- // Re-use existing error handling logic from the SDK
756
- const errorResult = await this.#handleApiError(e);
757
- return {
758
- cause: errorResult.cause,
759
- data: undefined,
760
- error: errorResult.error,
761
- status: errorResult.status,
762
- success: false
763
- };
764
- }
765
- /* c8 ignore stop */
766
-
767
- /* c8 ignore next - Fallback error handling for non-ResponseError cases in getApi. */
768
- return this.#createQueryErrorResult(e);
769
- }
770
- }
771
-
772
- /**
773
- * Get list of API tokens for an organization.
774
- * Returns organization API tokens with metadata and permissions.
775
- *
776
- * @throws {Error} When server returns 5xx status codes
777
- */
778
- async getAPITokens(orgSlug) {
779
- try {
780
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens`, this.#reqOptions)));
781
- return this.#handleApiSuccess(data);
782
- } catch (e) {
783
- return await this.#handleApiError(e);
784
- }
785
- }
786
-
787
- /**
788
- * Retrieve audit log events for an organization.
789
- * Returns chronological log of security and administrative actions.
790
- *
791
- * @throws {Error} When server returns 5xx status codes
792
- */
793
- async getAuditLogEvents(orgSlug, queryParams) {
794
- try {
795
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/audit-log?${utils.queryToSearchParams(queryParams)}`, this.#reqOptions)));
796
- return this.#handleApiSuccess(data);
797
- } catch (e) {
798
- return await this.#handleApiError(e);
799
- }
800
- }
801
-
802
- /**
803
- * Get details for a specific diff scan.
804
- * Returns comparison between two full scans with artifact changes.
805
- *
806
- * @throws {Error} When server returns 5xx status codes
807
- */
808
- async getDiffScanById(orgSlug, diffScanId) {
809
- try {
810
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`, this.#reqOptions)));
811
- return this.#handleApiSuccess(data);
812
- } catch (e) {
813
- return await this.#handleApiError(e);
814
- }
815
- }
816
-
817
- /**
818
- * Retrieve the enabled entitlements for an organization.
819
- *
820
- * This method fetches the organization's entitlements and filters for only* the enabled ones, returning their keys. Entitlements represent Socket
821
- * Products that the organization has access to use.
822
- */
823
- async getEnabledEntitlements(orgSlug) {
824
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/entitlements`, this.#reqOptions)));
825
-
826
- // Extract enabled products from the response.
827
- const items = data?.items || [];
828
- return items.filter(item => item && item.enabled === true && item.key).map(item => item.key);
829
- }
830
-
831
- /**
832
- * Retrieve all entitlements for an organization.
833
- *
834
- * This method fetches all entitlements (both enabled and disabled) for
835
- * an organization, returning the complete list with their status.
836
- */
837
- async getEntitlements(orgSlug) {
838
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/entitlements`, this.#reqOptions)));
839
- return data?.items || [];
840
- }
841
-
842
- /**
843
- * Get security issues for a specific npm package and version.
844
- * Returns detailed vulnerability and security alert information.
845
- *
846
- * @throws {Error} When server returns 5xx status codes
847
- */
848
- async getIssuesByNpmPackage(pkgName, version) {
849
- try {
850
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/issues`, this.#reqOptions)));
851
- return this.#handleApiSuccess(data);
852
- } catch (e) {
853
- return await this.#handleApiError(e);
854
- }
855
- }
856
-
857
- /**
858
- * Get analytics data for organization usage patterns and security metrics.
859
- * Returns statistical analysis for specified time period.
860
- *
861
- * @throws {Error} When server returns 5xx status codes
862
- */
863
- async getOrgAnalytics(time) {
864
- try {
865
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `analytics/org/${encodeURIComponent(time)}`, this.#reqOptions)));
866
- return this.#handleApiSuccess(data);
867
- } catch (e) {
868
- return await this.#handleApiError(e);
869
- }
870
- }
871
-
872
- /**
873
- * List all organizations accessible to the current user.
874
- * Returns organization details and access permissions.
875
- *
876
- * @throws {Error} When server returns 5xx status codes
877
- */
878
- async getOrganizations() {
879
- try {
880
- const data = await this.#getCached('organizations', async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'organizations', this.#reqOptions)));
881
- return this.#handleApiSuccess(data);
882
- } catch (e) {
883
- return await this.#handleApiError(e);
884
- }
885
- }
886
-
887
- /**
888
- * Get complete full scan results in memory.
889
- * Returns entire scan data as JSON for programmatic processing.
890
- *
891
- * @throws {Error} When server returns 5xx status codes
892
- */
893
- async getOrgFullScanBuffered(orgSlug, fullScanId) {
894
- try {
895
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, this.#reqOptions)));
896
- return this.#handleApiSuccess(data);
897
- } catch (e) {
898
- return await this.#handleApiError(e);
899
- }
900
- }
901
-
902
- /**
903
- * List all full scans for an organization.
904
- * Returns paginated list of scan metadata and status.
905
- *
906
- * @throws {Error} When server returns 5xx status codes
907
- */
908
- async getOrgFullScanList(orgSlug, queryParams) {
909
- try {
910
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans?${utils.queryToSearchParams(queryParams)}`, this.#reqOptions)));
911
- return this.#handleApiSuccess(data);
912
- } catch (e) {
913
- return await this.#handleApiError(e);
914
- }
915
- }
916
-
917
- /**
918
- * Get metadata for a specific full scan.
919
- * Returns scan configuration, status, and summary information.
920
- *
921
- * @throws {Error} When server returns 5xx status codes
922
- */
923
- async getOrgFullScanMetadata(orgSlug, fullScanId) {
924
- try {
925
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/metadata`, this.#reqOptions)));
926
- return this.#handleApiSuccess(data);
927
- } catch (e) {
928
- return await this.#handleApiError(e);
929
- }
930
- }
931
-
932
- /**
933
- * Get organization's license policy configuration.* Returns allowed, restricted, and monitored license types.
934
- *
935
- * @throws {Error} When server returns 5xx status codes
936
- */
937
- async getOrgLicensePolicy(orgSlug) {
938
- try {
939
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/license-policy`, this.#reqOptions)));
940
- return this.#handleApiSuccess(data);
941
- } catch (e) {
942
- return await this.#handleApiError(e);
943
- }
944
- }
945
-
946
- /**
947
- * Get details for a specific organization repository.
948
- * Returns repository configuration, monitoring status, and metadata.
949
- *
950
- * @throws {Error} When server returns 5xx status codes
951
- */
952
- async getOrgRepo(orgSlug, repoSlug) {
953
- const orgSlugParam = encodeURIComponent(orgSlug);
954
- const repoSlugParam = encodeURIComponent(repoSlug);
955
- try {
956
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${orgSlugParam}/repos/${repoSlugParam}`, this.#reqOptions)));
957
- return this.#handleApiSuccess(data);
958
- } catch (e) {
959
- return await this.#handleApiError(e);
960
- }
961
- }
962
-
963
- /**
964
- * Get details for a specific repository label.
965
- * Returns label configuration and metadata.
966
- *
967
- * @throws {Error} When server returns 5xx status codes
968
- */
969
- async getOrgRepoLabel(orgSlug, repoSlug, labelSlug) {
970
- try {
971
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, this.#reqOptions)));
972
- return this.#handleApiSuccess(data);
973
- } catch (e) {
974
- return await this.#handleApiError(e);
975
- }
976
- }
977
-
978
- /**
979
- * Get list of repository labels for an organization.
980
- * Returns all labels configured for repository management.
981
- *
982
- * @throws {Error} When server returns 5xx status codes
983
- */
984
- async getOrgRepoLabelList(orgSlug, repoSlug) {
985
- try {
986
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels`, this.#reqOptions)));
987
- return this.#handleApiSuccess(data);
988
- } catch (e) {
989
- return await this.#handleApiError(e);
990
- }
991
- }
992
-
993
- /**
994
- * List all repositories in an organization.
995
- * Returns paginated list of repository metadata and status.
996
- *
997
- * @throws {Error} When server returns 5xx status codes
998
- */
999
- async getOrgRepoList(orgSlug, queryParams) {
1000
- try {
1001
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos?${utils.queryToSearchParams(queryParams)}`, this.#reqOptions)));
1002
- return this.#handleApiSuccess(data);
1003
- } catch (e) {
1004
- return await this.#handleApiError(e);
1005
- }
1006
- }
1007
-
1008
- /**
1009
- * Get organization's security policy configuration.* Returns alert rules, severity thresholds, and enforcement settings.
1010
- *
1011
- * @throws {Error} When server returns 5xx status codes
1012
- */
1013
- async getOrgSecurityPolicy(orgSlug) {
1014
- try {
1015
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/security-policy`, this.#reqOptions)));
1016
- return this.#handleApiSuccess(data);
1017
- } catch (e) {
1018
- return await this.#handleApiError(e);
1019
- }
1020
- }
1021
-
1022
- /**
1023
- * Get organization triage settings and status.
1024
- * Returns alert triage configuration and current state.
1025
- *
1026
- * @throws {Error} When server returns 5xx status codes
1027
- */
1028
- async getOrgTriage(orgSlug) {
1029
- try {
1030
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/triage`, this.#reqOptions)));
1031
- return this.#handleApiSuccess(data);
1032
- } catch (e) {
1033
- return await this.#handleApiError(e);
1034
- }
1035
- }
1036
-
1037
- /**
1038
- * Get current API quota usage and limits.
1039
- * Returns remaining requests, rate limits, and quota reset times.
1040
- *
1041
- * @throws {Error} When server returns 5xx status codes
1042
- */
1043
- async getQuota() {
1044
- try {
1045
- const data = await this.#getCached('quota', async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'quota', this.#reqOptions)));
1046
- return this.#handleApiSuccess(data);
1047
- } catch (e) {
1048
- return await this.#handleApiError(e);
1049
- }
1050
- }
1051
-
1052
- /**
1053
- * Get analytics data for a specific repository.
1054
- * Returns security metrics, dependency trends, and vulnerability statistics.
1055
- *
1056
- * @throws {Error} When server returns 5xx status codes
1057
- */
1058
- async getRepoAnalytics(repo, time) {
1059
- try {
1060
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `analytics/repo/${encodeURIComponent(repo)}/${encodeURIComponent(time)}`, this.#reqOptions)));
1061
- return this.#handleApiSuccess(data);
1062
- } catch (e) {
1063
- return await this.#handleApiError(e);
1064
- }
1065
- }
1066
-
1067
- /**
1068
- * Get detailed results for a specific scan.
1069
- * Returns complete scan analysis including vulnerabilities and alerts.
1070
- *
1071
- * @throws {Error} When server returns 5xx status codes
1072
- */
1073
- async getScan(id) {
1074
- try {
1075
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `report/view/${encodeURIComponent(id)}`, this.#reqOptions)));
1076
- return this.#handleApiSuccess(data);
1077
- } catch (e) {
1078
- return await this.#handleApiError(e);
1079
- }
1080
- }
1081
-
1082
- /**
1083
- * List all scans accessible to the current user.
1084
- * Returns paginated list of scan metadata and status.
1085
- *
1086
- * @throws {Error} When server returns 5xx status codes
1087
- */
1088
- async getScanList() {
1089
- try {
1090
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'report/list', this.#reqOptions), 'GET'));
1091
- return this.#handleApiSuccess(data);
1092
- } catch (e) {
1093
- return await this.#handleApiError(e);
1094
- }
1095
- }
1096
-
1097
- /**
1098
- * Get security score for a specific npm package and version.
1099
- * Returns numerical security rating and scoring breakdown.
1100
- *
1101
- * @throws {Error} When server returns 5xx status codes
1102
- */
1103
- async getScoreByNpmPackage(pkgName, version) {
1104
- try {
1105
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/score`, this.#reqOptions)));
1106
- return this.#handleApiSuccess(data);
1107
- } catch (e) {
1108
- return await this.#handleApiError(e);
1109
- }
1110
- }
1111
-
1112
- /**
1113
- * Get list of file types and formats supported for scanning.
1114
- * Returns supported manifest files, lockfiles, and configuration formats.
1115
- *
1116
- * @throws {Error} When server returns 5xx status codes
1117
- */
1118
- async getSupportedScanFiles() {
1119
- try {
1120
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'report/supported', this.#reqOptions)));
1121
- return this.#handleApiSuccess(data);
1122
- } catch (e) {
1123
- return await this.#handleApiError(e);
1124
- }
1125
- }
1126
-
1127
- /**
1128
- * List all diff scans for an organization.
1129
- * Returns paginated list of diff scan metadata and status.
1130
- *
1131
- * @throws {Error} When server returns 5xx status codes
1132
- */
1133
- async listOrgDiffScans(orgSlug) {
1134
- try {
1135
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans`, this.#reqOptions)));
1136
- return this.#handleApiSuccess(data);
1137
- } catch (e) {
1138
- return await this.#handleApiError(e);
1139
- }
1140
- }
1141
-
1142
- /**
1143
- * Create a new API token for an organization.
1144
- * Generates API token with specified scopes and metadata.
1145
- *
1146
- * @throws {Error} When server returns 5xx status codes
1147
- */
1148
- async postAPIToken(orgSlug, tokenData) {
1149
- try {
1150
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens`, tokenData, this.#reqOptions)));
1151
- return this.#handleApiSuccess(data);
1152
- } catch (e) {
1153
- return await this.#handleApiError(e);
1154
- }
1155
- }
1156
-
1157
- /**
1158
- * Revoke an API token for an organization.
1159
- * Permanently disables the token and removes access.
1160
- *
1161
- * @throws {Error} When server returns 5xx status codes
1162
- */
1163
- async postAPITokensRevoke(orgSlug, tokenId) {
1164
- try {
1165
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/revoke`, {}, this.#reqOptions)));
1166
- return this.#handleApiSuccess(data);
1167
- } catch (e) {
1168
- return await this.#handleApiError(e);
1169
- }
1170
- }
1171
-
1172
- /**
1173
- * Rotate an API token for an organization.
1174
- * Generates new token value while preserving token metadata.
1175
- *
1176
- * @throws {Error} When server returns 5xx status codes
1177
- */
1178
- async postAPITokensRotate(orgSlug, tokenId) {
1179
- try {
1180
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/rotate`, {}, this.#reqOptions)));
1181
- return this.#handleApiSuccess(data);
1182
- } catch (e) {
1183
- return await this.#handleApiError(e);
1184
- }
1185
- }
1186
-
1187
- /**
1188
- * Update an existing API token for an organization.
1189
- * Modifies token metadata, scopes, or other properties.
1190
- *
1191
- * @throws {Error} When server returns 5xx status codes
1192
- */
1193
- async postAPITokenUpdate(orgSlug, tokenId, updateData) {
1194
- try {
1195
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/update`, updateData, this.#reqOptions)));
1196
- return this.#handleApiSuccess(data);
1197
- } catch (e) {
1198
- return await this.#handleApiError(e);
1199
- }
1200
- }
1201
-
1202
- /**
1203
- * Update user or organization settings.
1204
- * Configures preferences, notifications, and security policies.
1205
- *
1206
- * @throws {Error} When server returns 5xx status codes
1207
- */
1208
- async postSettings(selectors) {
1209
- try {
1210
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, 'settings', {
1211
- json: selectors
1212
- }, this.#reqOptions)));
1213
- return this.#handleApiSuccess(data);
1214
- } catch (e) {
1215
- return await this.#handleApiError(e);
1216
- }
1217
- }
1218
-
1219
- /**
1220
- * Search for dependencies across monitored projects.
1221
- * Returns matching packages with security information and usage patterns.
1222
- *
1223
- * @throws {Error} When server returns 5xx status codes
1224
- */
1225
- async searchDependencies(queryParams) {
1226
- try {
1227
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, 'dependencies/search', queryParams, this.#reqOptions)));
1228
- return this.#handleApiSuccess(data);
1229
- } catch (e) {
1230
- return await this.#handleApiError(e);
1231
- }
1232
- }
1233
-
1234
- /**
1235
- * Send POST or PUT request with JSON body and return parsed JSON response.
1236
- * Supports both throwing (default) and non-throwing modes.
1237
- * @param urlPath - API endpoint path (e.g., 'organizations')
1238
- * @param options - Request options including method, body, and throws behavior
1239
- * @returns Parsed JSON response or SocketSdkGenericResult based on options
1240
- */
1241
- async sendApi(urlPath, options) {
1242
- const {
1243
- body,
1244
- // Default to POST method for JSON API requests.
1245
- method = 'POST',
1246
- throws = true
1247
- } = {
1248
- __proto__: null,
1249
- ...options
1250
- };
1251
- try {
1252
- // Route to appropriate HTTP method handler (POST or PUT).
1253
- const response = await httpClient.createRequestWithJson(method, this.#baseUrl, urlPath, body, this.#reqOptions);
1254
- const data = await httpClient.getResponseJson(response);
1255
- if (throws) {
1256
- return data;
1257
- }
1258
- return {
1259
- cause: undefined,
1260
- data,
1261
- error: undefined,
1262
- /* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
1263
- status: response.statusCode ?? 200,
1264
- success: true
1265
- };
1266
- } catch (e) {
1267
- if (throws) {
1268
- throw e;
1269
- }
1270
-
1271
- /* c8 ignore start - Defensive fallback: ResponseError in catch block handled in try block (lines 1686-1695) */
1272
- if (e instanceof httpClient.ResponseError) {
1273
- // Re-use existing error handling logic from the SDK
1274
- const errorResult = await this.#handleApiError(e);
1275
- return {
1276
- cause: errorResult.cause,
1277
- data: undefined,
1278
- error: errorResult.error,
1279
- status: errorResult.status,
1280
- success: false
1281
- };
1282
- }
1283
- /* c8 ignore stop */
1284
-
1285
- /* c8 ignore start - Defensive error stringification fallback branches for sendApi edge cases. */
1286
- const errStr = e ? String(e).trim() : '';
1287
- return {
1288
- cause: errStr || UNKNOWN_ERROR,
1289
- data: undefined,
1290
- error: 'API request failed',
1291
- status: 0,
1292
- success: false
1293
- };
1294
- /* c8 ignore stop */
1295
- }
1296
- }
1297
-
1298
- /**
1299
- * Stream a full scan's results to file or stdout.* Provides efficient streaming for large scan datasets.
1300
- *
1301
- * @throws {Error} When server returns 5xx status codes
1302
- */
1303
- async streamOrgFullScan(orgSlug, fullScanId, options) {
1304
- const {
1305
- output
1306
- } = {
1307
- __proto__: null,
1308
- ...options
1309
- };
1310
- try {
1311
- const req = httpClient.getHttpModule(this.#baseUrl).request(`${this.#baseUrl}orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, {
1312
- method: 'GET',
1313
- ...this.#reqOptions
1314
- }).end();
1315
- const res = await httpClient.getResponse(req);
1316
-
1317
- // Check for HTTP error status codes.
1318
- if (!httpClient.isResponseOk(res)) {
1319
- throw new httpClient.ResponseError(res);
1320
- }
1321
- if (typeof output === 'string') {
1322
- // Stream to file with error handling.
1323
- const writeStream = node_fs.createWriteStream(output);
1324
- res.pipe(writeStream);
1325
- /* c8 ignore next 4 - Write stream error handler, difficult to test reliably */
1326
- writeStream.on('error', error => {
1327
- throw new Error(`Failed to write to file: ${output}`, {
1328
- cause: error
1329
- });
1330
- });
1331
- } else if (output === true) {
1332
- // Stream to stdout with error handling.
1333
- res.pipe(process.stdout);
1334
- /* c8 ignore next 3 - Stdout error handler, difficult to test reliably */
1335
- process.stdout.on('error', error => {
1336
- throw new Error('Failed to write to stdout', {
1337
- cause: error
1338
- });
1339
- });
1340
- }
1341
-
1342
- // If output is false or undefined, just return the response without streaming
1343
- return this.#handleApiSuccess(res);
1344
- } catch (e) {
1345
- return await this.#handleApiError(e);
1346
- }
1347
- }
1348
-
1349
- /**
1350
- * Stream patches for artifacts in a scan report.
1351
- *
1352
- * This method streams all available patches for artifacts in a scan.
1353
- * Free tier users will only receive free patches.
1354
- *
1355
- * Note: This method returns a ReadableStream for processing large datasets.
1356
- */
1357
- async streamPatchesFromScan(orgSlug, scanId) {
1358
- const response = await this.#executeWithRetry(async () => await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/patches/scan/${encodeURIComponent(scanId)}`, this.#reqOptions));
1359
-
1360
- // Check for HTTP error status codes.
1361
- if (!httpClient.isResponseOk(response)) {
1362
- throw new httpClient.ResponseError(response, 'GET Request failed');
1363
- }
1364
-
1365
- // The response itself is the readable stream for NDJSON data
1366
- // Convert the Node.js readable stream to a Web ReadableStream
1367
- return new ReadableStream({
1368
- start(controller) {
1369
- response.on('data', chunk => {
1370
- // Parse NDJSON chunks line by line
1371
- const lines = chunk.toString().split('\n').filter(line => line.trim());
1372
- for (const line of lines) {
1373
- try {
1374
- const data = JSON.parse(line);
1375
- controller.enqueue(data);
1376
- } catch (e) {
1377
- // Log parse errors for debugging invalid NDJSON lines.
1378
- debug.debugLog('streamPatchesFromScan', `Failed to parse line: ${e}`);
1379
- }
1380
- }
1381
- });
1382
- response.on('end', () => {
1383
- controller.close();
1384
- });
1385
- response.on('error', error => {
1386
- /* c8 ignore next - Streaming error handler, difficult to test reliably. */
1387
- controller.error(error);
1388
- });
1389
- }
1390
- });
1391
- }
1392
-
1393
- /**
1394
- * Update alert triage status for an organization.
1395
- * Modifies alert resolution status and triage decisions.
1396
- *
1397
- * @throws {Error} When server returns 5xx status codes
1398
- */
1399
- async updateOrgAlertTriage(orgSlug, alertId, triageData) {
1400
- try {
1401
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('PUT', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/triage/${encodeURIComponent(alertId)}`, triageData, this.#reqOptions)));
1402
- return this.#handleApiSuccess(data);
1403
- } catch (e) {
1404
- return await this.#handleApiError(e);
1405
- }
1406
- }
1407
-
1408
- /**
1409
- * Update organization's license policy configuration.* Modifies allowed, restricted, and monitored license types.
1410
- *
1411
- * @throws {Error} When server returns 5xx status codes
1412
- */
1413
- async updateOrgLicensePolicy(orgSlug, policyData, queryParams) {
1414
- try {
1415
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/license-policy?${utils.queryToSearchParams(queryParams)}`, policyData, this.#reqOptions)));
1416
- return this.#handleApiSuccess(data);
1417
- } catch (e) {
1418
- return await this.#handleApiError(e);
1419
- }
1420
- }
1421
-
1422
- /**
1423
- * Update configuration for an organization repository.
1424
- * Modifies monitoring settings, branch configuration, and scan preferences.
1425
- *
1426
- * @throws {Error} When server returns 5xx status codes
1427
- */
1428
- async updateOrgRepo(orgSlug, repoSlug, queryParams) {
1429
- try {
1430
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}`, queryParams, this.#reqOptions)));
1431
- return this.#handleApiSuccess(data);
1432
- } catch (e) {
1433
- return await this.#handleApiError(e);
1434
- }
1435
- }
1436
-
1437
- /**
1438
- * Update a repository label for an organization.
1439
- * Modifies label properties and configuration.
1440
- *
1441
- * @throws {Error} When server returns 5xx status codes
1442
- */
1443
- async updateOrgRepoLabel(orgSlug, repoSlug, labelSlug, labelData) {
1444
- try {
1445
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('PUT', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, labelData, this.#reqOptions)));
1446
- return this.#handleApiSuccess(data);
1447
- } catch (e) {
1448
- return await this.#handleApiError(e);
1449
- }
1450
- }
1451
-
1452
- /**
1453
- * Update organization's security policy configuration.* Modifies alert rules, severity thresholds, and enforcement settings.
1454
- *
1455
- * @throws {Error} When server returns 5xx status codes
1456
- */
1457
- async updateOrgSecurityPolicy(orgSlug, policyData) {
1458
- try {
1459
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/security-policy`, policyData, this.#reqOptions)));
1460
- return this.#handleApiSuccess(data);
1461
- } catch (e) {
1462
- return await this.#handleApiError(e);
1463
- }
1464
- }
1465
-
1466
- /**
1467
- * Upload manifest files for dependency analysis.
1468
- * Processes package files to create dependency snapshots and security analysis.
1469
- *
1470
- * @throws {Error} When server returns 5xx status codes
1471
- */
1472
- async uploadManifestFiles(orgSlug, filepaths, options) {
1473
- const {
1474
- pathsRelativeTo = '.'
1475
- } = {
1476
- __proto__: null,
1477
- ...options
1478
- };
1479
- const basePath = utils.resolveBasePath(pathsRelativeTo);
1480
- const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
1481
- try {
1482
- const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/upload-manifest-files`, fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), this.#reqOptions)));
1483
- return this.#handleApiSuccess(data);
1484
- } catch (e) {
1485
- /* c8 ignore start - Error handling in uploadManifestFiles method for edge cases. */
1486
- return await this.#handleApiError(e);
1487
- /* c8 ignore stop */
1488
- }
1489
- }
1490
-
1491
- /**
1492
- * View detailed information about a specific patch by its UUID.
1493
- *
1494
- * This method retrieves comprehensive patch details including files,
1495
- * vulnerabilities, description, license, and tier information.
1496
- */
1497
- async viewPatch(orgSlug, uuid) {
1498
- const data = await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/patches/view/${encodeURIComponent(uuid)}`, this.#reqOptions));
1499
- return data;
1500
- }
1501
- }
1502
-
1503
- // Optional live heap trace.
1504
- /* c8 ignore start - optional debug logging for heap monitoring */
1505
- if (debug.isDebugNs('heap')) {
1506
- const used = process.memoryUsage();
1507
- debug.debugLog('heap', `heap used: ${Math.round(used.heapUsed / 1024 / 1024)}MB`);
1508
- }
1509
- /* c8 ignore stop - end debug logging */
1510
-
1511
- exports.SocketSdk = SocketSdk;