-
Notifications
You must be signed in to change notification settings - Fork 65
Expand file tree
/
Copy pathapi-error-messages.mts
More file actions
169 lines (159 loc) · 6.03 KB
/
Copy pathapi-error-messages.mts
File metadata and controls
169 lines (159 loc) · 6.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// user-facing API error strings; emojis are part of the message-template
// contract.
/* oxlint-disable-next-line socket/no-file-scope-oxlint-disable -- legitimate file-scope: domain-grouped layout or test fixture; per-call would produce many redundant disables. */
/* oxlint-disable socket/no-status-emoji -- emoji is the contract */
/**
* User-facing error messages + permission-requirements logging for Socket API
* failures.
*
* Extracted from api.mts to keep that file under the 1000-line File-size cap.
* These helpers turn opaque HTTP status codes into actionable guidance ("here's
* where to update your token", "here's how to check rate limits") and translate
* command paths into the permission set the API was expecting.
*/
import { getDefaultLogger } from '@socketsecurity/lib-stable/logger/default'
import {
HTTP_STATUS_BAD_REQUEST,
HTTP_STATUS_FORBIDDEN,
HTTP_STATUS_INTERNAL_SERVER_ERROR,
HTTP_STATUS_NOT_FOUND,
HTTP_STATUS_TOO_MANY_REQUESTS,
HTTP_STATUS_UNAUTHORIZED,
} from '../../constants/http.mts'
import {
SOCKET_CLI_ISSUES_URL,
SOCKET_PRICING_URL,
SOCKET_SETTINGS_API_TOKENS_URL,
SOCKET_STATUS_URL,
} from '../../constants/socket.mts'
import {
getRequirements,
getRequirementsKey,
} from '../ecosystem/requirements.mts'
const logger = getDefaultLogger()
export type CommandRequirements = {
permissions?: string[] | undefined
quota?: number | undefined
}
/**
* Get command requirements from requirements.json based on command path.
*/
export function getCommandRequirements(
cmdPath?: string | undefined,
): CommandRequirements | undefined {
if (!cmdPath) {
return undefined
}
const requirements = getRequirements()
const key = getRequirementsKey(cmdPath)
return (
((requirements.api as Record<string, unknown>)[key] as
| { quota?: number | undefined; permissions?: string[] | undefined }
| undefined) || undefined
)
}
/**
* Get user-friendly error message for HTTP status codes with actionable
* guidance.
*/
export async function getErrorMessageForHttpStatusCode(code: number) {
if (code === HTTP_STATUS_BAD_REQUEST) {
return (
'❌ Invalid request: One of the options or parameters may be incorrect.\n' +
'💡 Try: Check your command syntax and parameter values.'
)
}
if (code === HTTP_STATUS_UNAUTHORIZED) {
return (
'❌ Authentication failed: Your Socket API token appears to be invalid, expired, or revoked.\n' +
'💡 Try:\n' +
' • Run `socket whoami` to verify your current token\n' +
' • Run `socket login` to re-authenticate\n' +
` • Manage tokens at ${SOCKET_SETTINGS_API_TOKENS_URL}`
)
}
if (code === HTTP_STATUS_FORBIDDEN) {
return (
'❌ Access denied: Your API token lacks required permissions or organization access.\n' +
'💡 Try:\n' +
' • Run `socket whoami` to verify your account and organization\n' +
` • Check your API token permissions at ${SOCKET_SETTINGS_API_TOKENS_URL}\n` +
" • Ensure you're accessing the correct organization with `--org` flag\n" +
` • Verify your plan includes this feature at ${SOCKET_PRICING_URL}`
)
}
if (code === HTTP_STATUS_NOT_FOUND) {
return (
"❌ Not found: The requested endpoint or resource doesn't exist.\n" +
'💡 Try:\n' +
' • Verify resource names (package, repository, organization)\n' +
' • Check if the resource was deleted or moved\n' +
' • Update to the latest CLI version: `socket self-update` (SEA) or `npm update -g socket`\n' +
` • Report persistent issues at ${SOCKET_CLI_ISSUES_URL}`
)
}
if (code === HTTP_STATUS_TOO_MANY_REQUESTS) {
return (
'❌ Rate limit exceeded: Too many API requests.\n' +
'💡 Try:\n' +
` • Free plan: Wait a few minutes for quota reset or upgrade at ${SOCKET_PRICING_URL}\n` +
' • Paid plan: Contact support if rate limits seem incorrect\n' +
' • Check current quota: `socket organization quota`\n' +
' • Reduce request frequency or batch operations'
)
}
if (code === HTTP_STATUS_INTERNAL_SERVER_ERROR) {
return (
'❌ Server error: Socket API encountered an internal problem (HTTP 500).\n' +
'💡 Try:\n' +
' • Wait a few minutes and retry your command\n' +
` • Check Socket status: ${SOCKET_STATUS_URL}\n` +
` • Report persistent issues: ${SOCKET_CLI_ISSUES_URL}`
)
}
return (
`❌ HTTP ${code}: Server responded with unexpected status code.\n` +
`💡 Try: Check Socket status at ${SOCKET_STATUS_URL} or report the issue.`
)
}
/**
* Log required permissions for a command when encountering 403 errors with
* actionable guidance.
*
* @param cmdPath - Command path to look up requirements for (e.g., "socket
* fix", "socket scan:create")
*/
export function logPermissionsFor403(cmdPath?: string | undefined): void {
const requirements = getCommandRequirements(cmdPath)
logger.error('')
if (requirements?.permissions?.length) {
logger.group('🔐 Required API Permissions:')
for (const permission of requirements.permissions) {
logger.error(permission)
}
logger.groupEnd()
logger.error('')
logger.group('💡 To fix this:')
logger.error(`Visit ${SOCKET_SETTINGS_API_TOKENS_URL}`)
logger.error('Edit your API token to grant the permissions listed above')
logger.error('Re-run your command')
logger.groupEnd()
} else {
// No specific permissions found, provide general guidance.
logger.group('🔐 Permission Requirements:')
logger.error(
'Your API token lacks the required permissions for this operation.',
)
logger.groupEnd()
logger.error('')
logger.group('💡 To fix this:')
logger.error(`Visit ${SOCKET_SETTINGS_API_TOKENS_URL}`)
logger.error('Check your API token has the necessary permissions')
logger.error(
`Run \`socket ${cmdPath?.replace(/^socket[: ]/, '') || 'help'} --help\` to see required permissions`,
)
logger.error('Re-run your command after updating permissions')
logger.groupEnd()
}
logger.error('')
}