• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / storage / 28888819873

07 Jul 2026 06:20PM UTC coverage: 79.219% (+0.1%) from 79.091%
28888819873

Pull #1214

github

web-flow
Merge 40f07c0dd into 9cf361f1f
Pull Request #1214: feat: add heap snapshot into admin

5293 of 7245 branches covered (73.06%)

Branch coverage included in aggregate %.

194 of 215 new or added lines in 5 files covered. (90.23%)

1 existing line in 1 file now uncovered.

10363 of 12518 relevant lines covered (82.78%)

413.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.63
/src/scripts/pprof-client.ts
1
import { fetchPprofStream } from '@internal/monitoring/pprof/client-http'
2
import { writePprofCaptureToFile } from '@internal/monitoring/pprof/download'
3
import { generateFlameArtifacts, resolveFlameMdFormat } from '@internal/monitoring/pprof/flame'
4
import type { PprofRequestTargetType } from '@internal/monitoring/pprof/types'
5
import path from 'path'
6

7
const ADMIN_URL = process.env.ADMIN_URL
1✔
8
const ADMIN_API_KEY = process.env.ADMIN_API_KEY
1✔
9
const PPROF_SECONDS = process.env.PPROF_SECONDS
1✔
10
const PPROF_GENERATE_FLAME = process.env.PPROF_GENERATE_FLAME
1✔
11
const PPROF_FLAME_MD_FORMAT = process.env.PPROF_FLAME_MD_FORMAT
1✔
12
const PPROF_WORKER_ID = process.env.PPROF_WORKER_ID
1✔
13
const PPROF_SOURCE_MAPS = process.env.PPROF_SOURCE_MAPS
1✔
14
const PPROF_NODE_MODULES_SOURCE_MAPS = process.env.PPROF_NODE_MODULES_SOURCE_MAPS
1✔
15
const PPROF_OUTPUT = process.env.PPROF_OUTPUT
1✔
16
const PPROF_USAGE =
17
  'Usage: tsx src/scripts/pprof-client.ts <profile[:seconds]|heap[:seconds]|heap-snapshot> [output-file]'
1✔
18

19
export function parseBooleanEnv(value: string | undefined) {
20
  if (value === undefined) {
5✔
21
    return undefined
1✔
22
  }
23

24
  const normalized = value.trim().toLowerCase()
4✔
25
  if (['1', 'true', 'yes', 'on'].includes(normalized)) {
4✔
26
    return true
1✔
27
  }
28

29
  if (['0', 'false', 'no', 'off'].includes(normalized)) {
3✔
30
    return false
2✔
31
  }
32

33
  throw new Error(`Invalid boolean value: ${value}`)
1✔
34
}
35

36
export function parseBooleanEnvWithDefault(value: string | undefined, defaultValue: boolean) {
37
  if (value === undefined) {
3✔
38
    return defaultValue
2✔
39
  }
40

41
  return parseBooleanEnv(value) === true
1✔
42
}
43

44
function parseUnsignedInteger(value: string, errorMessage: string) {
45
  const normalized = value.trim()
12✔
46

47
  if (!/^\d+$/.test(normalized)) {
12✔
48
    throw new Error(errorMessage)
5✔
49
  }
50

51
  const parsed = Number.parseInt(normalized, 10)
7✔
52
  if (!Number.isSafeInteger(parsed)) {
7!
53
    throw new Error(errorMessage)
×
54
  }
55

56
  return parsed
7✔
57
}
58

59
export function parsePositiveIntegerEnv(
60
  value: string | undefined,
61
  envName: string,
62
  defaultValue: number
63
) {
64
  if (value === undefined) {
4✔
65
    return defaultValue
1✔
66
  }
67

68
  const parsed = parseUnsignedInteger(value, `${envName} must be a positive integer`)
3✔
69
  if (parsed <= 0) {
3✔
70
    throw new Error(`${envName} must be a positive integer`)
1✔
71
  }
72

73
  return parsed
1✔
74
}
75

76
export function parseNonNegativeIntegerEnv(value: string | undefined, envName: string) {
77
  if (value === undefined) {
5✔
78
    return undefined
1✔
79
  }
80

81
  return parseUnsignedInteger(value, `${envName} must be a non-negative integer`)
4✔
82
}
83

84
export function parsePprofTarget(
85
  value: string | undefined,
86
  defaultSeconds: number
87
):
88
  | { seconds: number; type: Exclude<PprofRequestTargetType, 'heap-snapshot'> }
89
  | {
90
      type: 'heap-snapshot'
91
    } {
92
  if (!value) {
12✔
93
    throw new Error(PPROF_USAGE)
1✔
94
  }
95

96
  const [type, secondsValue, ...rest] = value.split(':')
11✔
97

98
  if (rest.length > 0 || (type !== 'profile' && type !== 'heap' && type !== 'heap-snapshot')) {
11✔
99
    throw new Error(PPROF_USAGE)
2✔
100
  }
101

102
  if (type === 'heap-snapshot') {
9✔
103
    if (secondsValue !== undefined) {
2✔
104
      throw new Error(PPROF_USAGE)
1✔
105
    }
106

107
    return {
1✔
108
      type,
109
    }
110
  }
111

112
  if (secondsValue === undefined || secondsValue === '') {
7✔
113
    return {
2✔
114
      seconds: defaultSeconds,
115
      type,
116
    }
117
  }
118

119
  const seconds = parseUnsignedInteger(secondsValue, 'seconds must be a positive integer')
5✔
120
  if (seconds <= 0) {
5✔
121
    throw new Error('seconds must be a positive integer')
1✔
122
  }
123

124
  return {
2✔
125
    seconds,
126
    type,
127
  }
128
}
129

130
export function resolvePprofClientFlameMdFormat(
131
  generateFlame: boolean,
132
  target: ReturnType<typeof parsePprofTarget>,
133
  value: string | undefined
134
) {
135
  if (!generateFlame || target.type === 'heap-snapshot') {
4✔
136
    return undefined
2✔
137
  }
138

139
  return resolveFlameMdFormat(value)
2✔
140
}
141

142
function fail(message: string) {
143
  process.exitCode = 1
×
144
  console.error(message)
×
145
}
146

147
async function main() {
148
  const target = process.argv[2]
×
149
  const outputArg = process.argv[3]
×
150
  let parsedTarget: ReturnType<typeof parsePprofTarget>
151
  let pprofSeconds: number
152
  let sourceMaps: boolean | undefined
153
  let workerId: number | undefined
154
  let generateFlame: boolean
155

156
  if (!ADMIN_URL) {
×
157
    fail('Please provide ADMIN_URL')
×
158
    return
×
159
  }
160

161
  if (!ADMIN_API_KEY) {
×
162
    fail('Please provide ADMIN_API_KEY')
×
163
    return
×
164
  }
165

166
  try {
×
167
    pprofSeconds = parsePositiveIntegerEnv(PPROF_SECONDS, 'PPROF_SECONDS', 60)
×
168
    parsedTarget = parsePprofTarget(target, pprofSeconds)
×
169
    sourceMaps = parseBooleanEnv(PPROF_SOURCE_MAPS)
×
170
    workerId = parseNonNegativeIntegerEnv(PPROF_WORKER_ID, 'PPROF_WORKER_ID')
×
171
    generateFlame = parseBooleanEnvWithDefault(PPROF_GENERATE_FLAME, true)
×
172
  } catch (error) {
173
    process.exitCode = 1
×
174
    console.error(error instanceof Error ? error.message : error)
×
175
    return
×
176
  }
177

NEW
178
  const flameMdFormat = resolvePprofClientFlameMdFormat(
×
179
    generateFlame,
180
    parsedTarget,
181
    PPROF_FLAME_MD_FORMAT
182
  )
183

184
  const response =
NEW
185
    parsedTarget.type === 'heap-snapshot'
×
186
      ? await fetchPprofStream({
187
          adminUrl: ADMIN_URL,
188
          apiKey: ADMIN_API_KEY,
189
          type: 'heap-snapshot',
190
          workerId,
191
        })
192
      : await fetchPprofStream({
193
          adminUrl: ADMIN_URL,
194
          apiKey: ADMIN_API_KEY,
195
          nodeModulesSourceMaps: PPROF_NODE_MODULES_SOURCE_MAPS || undefined,
×
196
          seconds: parsedTarget.seconds,
197
          sourceMaps,
198
          type: parsedTarget.type,
199
          workerId,
200
        })
201

202
  const outputPath = outputArg
×
203
    ? path.resolve(outputArg)
204
    : PPROF_OUTPUT
×
205
      ? path.resolve(PPROF_OUTPUT)
206
      : undefined
207

NEW
208
  const { outputPath: capturedProfilePath } = await writePprofCaptureToFile(
×
209
    response.stream,
210
    {
211
      contentDisposition: response.contentDisposition,
212
      contentType: response.contentType,
213
      type: parsedTarget.type,
214
    },
215
    {
216
      outputPath,
217
    }
218
  )
219

NEW
220
  if (!generateFlame || parsedTarget.type === 'heap-snapshot') {
×
221
    return
×
222
  }
223

224
  await generateFlameArtifacts(capturedProfilePath, {
×
225
    env: {
226
      ...process.env,
227
      FLAME_SOURCEMAPS_DIRS: process.env.FLAME_SOURCEMAPS_DIRS || 'dist',
×
228
    },
229
    mdFormat: flameMdFormat,
230
  })
231
}
232

233
// Keep the CLI side effect behind a CommonJS-friendly main-module gate so tests can import
234
// the helpers without starting a capture.
235
if (require.main === module) {
1!
236
  main().catch((error) => {
×
237
    process.exitCode = 1
×
238
    console.error(error)
×
239
  })
240
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc