(.+?)<\/div>/s', $Section, $UrlMatches ) !== 1 )
35 | {
36 | continue;
37 | }
38 |
39 | $Url = htmlspecialchars_decode( $UrlMatches[ 1 ] );
40 | $Url = explode( ' ', trim( preg_replace( '/[\n\r ]+/', ' ', $Url ) ) );
41 |
42 | if( count( $Url ) < 2 )
43 | {
44 | continue;
45 | }
46 |
47 | $UrlPath = parse_url( $Url[ 1 ], PHP_URL_PATH );
48 |
49 | if( empty( $UrlPath ) )
50 | {
51 | continue;
52 | }
53 |
54 | $Parameters = [];
55 | $HttpMethod = $Url[ 0 ];
56 | $HttpPath = explode( '/', $UrlPath );
57 |
58 | if( count( $HttpPath ) < 4 )
59 | {
60 | continue;
61 | }
62 |
63 | $ApiService = $HttpPath[ 1 ];
64 | $ApiMethod = $HttpPath[ 2 ];
65 | $ApiVersion = (int)str_replace( 'v', '', $HttpPath[ 3 ] );
66 |
67 | $Method =
68 | [
69 | 'name' => $ApiMethod,
70 | 'version' => $ApiVersion,
71 | 'httpmethod' => $HttpMethod,
72 | 'parameters' => [],
73 | ];
74 |
75 | $Section = explode( '', $Section, 2 ); // Can be multiple tables (like response)
76 |
77 | preg_match_all( '/
(.*?)<\/tr>/s', $Section[ 0 ], $Matches );
78 |
79 | foreach( $Matches[ 1 ] as $ParamsHtml )
80 | {
81 | if( preg_match_all( '/(.*?)<\/td>/s', $ParamsHtml, $ParamsMatches ) === 0 )
82 | {
83 | continue;
84 | }
85 |
86 | $Method[ 'parameters' ][] =
87 | [
88 | 'name' => trim( strip_tags( $ParamsMatches[ 1 ][ 0 ] ) ),
89 | 'type' => trim( strip_tags( $ParamsMatches[ 1 ][ 1 ] ) ),
90 | 'optional' => $ParamsMatches[ 1 ][ 2 ] !== '✔',
91 | 'description' => trim( strip_tags( $ParamsMatches[ 1 ][ 3 ] ) ),
92 | ];
93 | }
94 |
95 | if( !isset( $Methods[ $ApiService ] ) )
96 | {
97 | $Methods[ $ApiService ] = [];
98 | }
99 |
100 | $Methods[ $ApiService ][] = $Method;
101 | }
102 | }
103 |
104 | $FoundServices = [];
105 |
106 | foreach( $Methods as $ServiceName => $FoundMethods )
107 | {
108 | $FoundServices[] =
109 | [
110 | 'name' => $ServiceName,
111 | 'methods' => $FoundMethods,
112 | ];
113 | }
114 |
115 | file_put_contents(
116 | __DIR__ . DIRECTORY_SEPARATOR . 'api_from_docs.json',
117 | json_encode( $FoundServices, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) . PHP_EOL
118 | );
119 |
--------------------------------------------------------------------------------
/generate_api_from_protos.php:
--------------------------------------------------------------------------------
1 | isFile() )
45 | {
46 | echo $fileInfo . ' does not exist' . PHP_EOL;
47 | return '';
48 | }
49 |
50 | $proto = file_get_contents( $fileInfo );
51 |
52 | if( $proto === false )
53 | {
54 | throw new Exception( "Failed to read $fileInfo" );
55 | }
56 |
57 | return preg_replace_callback( '/^import "(?.+\.proto)";/m', function( array $matches ) use ( $fileInfo ) : string
58 | {
59 | $path = $fileInfo->getPath() . '/';
60 |
61 | if( str_starts_with( $matches[ 'file' ], 'google/' ) )
62 | {
63 | $path .= '../' . $matches[ 'file' ];
64 | }
65 | else if( str_starts_with( $matches[ 'file' ], 'steammessages' ) && str_contains( $path, 'webui' ) )
66 | {
67 | $path .= '../steam/' . $matches[ 'file' ];
68 | }
69 | else
70 | {
71 | $path .= $matches[ 'file' ];
72 | }
73 |
74 | return ProcessFile( new SplFileInfo( $path ) );
75 | }, $proto ) ?? '';
76 | }
77 |
78 | function ParseTypeToRequestParameters( string $request, string $proto, int $level = 0 )
79 | {
80 | if( !preg_match( "/message " . $request . " {(.+?)^}/ms", $proto, $message ) )
81 | {
82 | echo $request . ' not found' . PHP_EOL;
83 | return [];
84 | }
85 |
86 | $parameters = [];
87 |
88 | if( preg_match_all(
89 | "/^\t(?optional|repeated|required) (?[\w\.]+) (?\w+).+?(?:\(description\) = \"(?.+?)\".+?)?;$/m",
90 | $message[ 1 ] ?? '',
91 | $fields
92 | ) > 0 )
93 | {
94 | for( $y = 0; $y < count( $fields[ 0 ] ); $y++ )
95 | {
96 | $name = $fields[ 'name' ][ $y ];
97 | $extra = null;
98 |
99 | if( strpos( $fields[ 'type' ][ $y ], '.' ) !== false )
100 | {
101 | $type = substr( $fields[ 'type' ][ $y ], 1 );
102 | // TODO: Support inner types with dots in middle
103 |
104 | if( $type !== $request && $level < 5 )
105 | {
106 | $extra = ParseTypeToRequestParameters( $type, $proto, $level + 1 );
107 | }
108 | }
109 | else
110 | {
111 | $type = $fields[ 'type' ][ $y ];
112 | }
113 |
114 | if( $fields[ 'rule' ][ $y ] === 'repeated' )
115 | {
116 | $name .= '[0]';
117 | $type .= '[]';
118 | }
119 |
120 | if( !empty( $parameters[ $name ] ) )
121 | {
122 | if( empty( $parameters[ $name ][ 'description' ] ) )
123 | {
124 | $parameters[ $name ][ 'description' ] = trim( $fields[ 'description' ][ $y ] );
125 | }
126 |
127 | continue;
128 | }
129 |
130 | $parameters[ $name ] =
131 | [
132 | 'name' => $name,
133 | 'type' => $type,
134 | 'optional' => true,
135 | 'description' => trim( $fields[ 'description' ][ $y ] ),
136 | ];
137 |
138 | if( !empty( $extra ) )
139 | {
140 | $parameters[ $name ][ 'extra' ] = array_values( $extra );
141 | }
142 | }
143 | }
144 |
145 | return $parameters;
146 | }
147 |
148 | foreach( $allProtos as $fileInfo )
149 | {
150 | if( strpos( $fileInfo, '.git' ) !== false || $fileInfo->getExtension() !== 'proto' )
151 | {
152 | continue;
153 | }
154 |
155 | $proto = ProcessFile( $fileInfo );
156 |
157 | preg_match_all( "/service (.+?)\s{/", $proto, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE );
158 |
159 | $matches[] =
160 | [
161 | [],
162 | [
163 | '',
164 | strlen( $proto )
165 | ]
166 | ];
167 |
168 | for( $i = count( $matches ) - 1; $i > 0; $i-- )
169 | {
170 | $serviceName = $matches[ $i - 1 ][ 1 ][ 0 ];
171 |
172 | if( $serviceName === 'RemoteClientSteamClient' )
173 | {
174 | $serviceName = 'RemoteClient';
175 | }
176 |
177 | $serviceName = 'I' . $serviceName . 'Service';
178 |
179 | $service = substr( $proto, $matches[ $i - 1 ][ 1 ][ 1 ], $matches[ $i ][ 1 ][ 1 ] - $matches[ $i - 1 ][ 1 ][ 1 ] );
180 |
181 | preg_match_all( "/rpc (.+?) \(\.?(.+?)\) returns \(\.?(?:.+?)\)\s*(?:;|{}|\{\s*option \(method_description\) = \"(.+?)\";)$/m", $service, $rpcs );
182 |
183 | $generatedMethods = [];
184 |
185 | for( $x = 0; $x < count( $rpcs[ 0 ] ); $x++ )
186 | {
187 | $methodName = $rpcs[ 1 ][ $x ];
188 | $request = $rpcs[ 2 ][ $x ];
189 |
190 | $methodPath = $serviceName . '/' . $methodName;
191 |
192 | if( empty( $methodDescriptions[ $methodPath ] ) )
193 | {
194 | $methodDescriptions[ $methodPath ] = trim( $rpcs[ 3 ][ $x ] );
195 | }
196 |
197 | if( empty( $methodParameters[ $methodPath ] ) )
198 | {
199 | $methodParameters[ $methodPath ] =
200 | [
201 | 'key' =>
202 | [
203 | "name" => "key",
204 | "type" => "string",
205 | "optional" => false,
206 | "description" => "Access key",
207 | ]
208 | ];
209 | }
210 |
211 | $methodParameters[ $methodPath ] += ParseTypeToRequestParameters( $request, $proto );
212 |
213 | $generatedMethods[ $methodName ] = true;
214 | }
215 |
216 | if( empty( $generatedServices[ $serviceName ] ) )
217 | {
218 | $generatedServices[ $serviceName ] = [];
219 | }
220 |
221 | $generatedServices[ $serviceName ] += $generatedMethods;
222 | }
223 | }
224 |
225 | $c = curl_init( );
226 |
227 | curl_setopt_array( $c, [
228 | CURLOPT_USERAGENT => '',
229 | CURLOPT_RETURNTRANSFER => true,
230 | CURLOPT_TIMEOUT => 5,
231 | CURLOPT_CONNECTTIMEOUT => 5,
232 | CURLOPT_URL => 'https://api.steampowered.com/ISteamWebAPIUtil/GetSupportedAPIList/v1/?format=json&key=' . $PublisherApiKey,
233 | ] );
234 |
235 | $knownServices = [];
236 |
237 | $response = curl_exec( $c );
238 | $response = json_decode( $response, true, 512, JSON_THROW_ON_ERROR );
239 |
240 | foreach( $response[ 'apilist' ][ 'interfaces' ] as $service )
241 | {
242 | foreach( $service[ 'methods' ] as $method )
243 | {
244 | $knownServices[ $service[ 'name' ] . '/' . $method[ 'name' ] ] = true;
245 | }
246 | }
247 |
248 | $notFound = "\n\n404 Not Found \n\n\nNot Found \n\n";
249 | $notFoundNoInterface = "Not Found Not Found Interface '%s' not found";
250 | $notFoundMethodInInterface = "Not Found Not Found Method '%s' not found in interface '%s'";
251 | $mustBePost = "Method Not Allowed Method Not Allowed This API must be called with a HTTP POST request";
252 |
253 | $foundServices = [];
254 |
255 | ksort( $generatedServices );
256 |
257 | foreach( $generatedServices as $serviceName => $methods )
258 | {
259 | ksort( $methods );
260 |
261 | $foundMethods = [];
262 |
263 | foreach( $methods as $methodName => $trash )
264 | {
265 | $path = $serviceName . '/' . $methodName;
266 |
267 | if( isset( $knownServices[ $path ] ) )
268 | {
269 | continue;
270 | }
271 |
272 | echo 'Checking ' . $path . '...';
273 |
274 | curl_setopt( $c, CURLOPT_URL, "https://api.steampowered.com/{$path}/v1/" );
275 | $response = curl_exec( $c );
276 |
277 | if( $response === $notFound )
278 | {
279 | echo " \033[1;31mnothing\033[0m" . PHP_EOL;
280 | continue;
281 | }
282 |
283 | if( $response === sprintf( $notFoundNoInterface, $serviceName ) )
284 | {
285 | echo " \033[1;33minterface not found\033[0m" . PHP_EOL;
286 | continue;
287 | }
288 |
289 | if( $response === sprintf( $notFoundMethodInInterface, $methodName, $serviceName ) )
290 | {
291 | echo " \033[1;31mmethod not found\033[0m" . PHP_EOL;
292 | continue;
293 | }
294 |
295 | echo " \033[0;32mFOUND!\033[0m" . PHP_EOL;
296 |
297 | $method =
298 | [
299 | 'name' => $methodName,
300 | 'version' => 1,
301 | ];
302 |
303 | if( $response === $mustBePost )
304 | {
305 | $method[ 'httpmethod' ] = 'POST';
306 | }
307 |
308 | if( !empty( $methodDescriptions[ $path ] ) )
309 | {
310 | $method[ 'description' ] = $methodDescriptions[ $path ];
311 | }
312 |
313 | if( !empty( $methodParameters[ $path ] ) )
314 | {
315 | $method[ 'parameters' ] = array_values( $methodParameters[ $path ] );
316 | }
317 |
318 | $foundMethods[] = $method;
319 | }
320 |
321 | if( empty( $foundMethods ) )
322 | {
323 | continue;
324 | }
325 |
326 | $foundServices[] =
327 | [
328 | 'name' => $serviceName,
329 | 'methods' => $foundMethods,
330 | ];
331 | }
332 |
333 | curl_close( $c );
334 |
335 | file_put_contents(
336 | __DIR__ . DIRECTORY_SEPARATOR . 'api_from_protos.json',
337 | json_encode( $foundServices, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) . PHP_EOL
338 | );
339 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SteamWebAPIDocumentation",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "devDependencies": {
8 | "@biomejs/biome": "^2.0.0-beta.1",
9 | "@chialab/esbuild-plugin-html": "^0.18.2",
10 | "@vue/tsconfig": "^0.7.0",
11 | "bootstrap": "^5.2.2",
12 | "esbuild": "^0.25.0",
13 | "esbuild-plugin-vue3": "^0.4.2",
14 | "htmlnano": "^2.1.1",
15 | "typescript": "^5.2.2",
16 | "vue": "^3.2.40"
17 | }
18 | },
19 | "node_modules/@babel/code-frame": {
20 | "version": "7.26.2",
21 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
22 | "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
23 | "dev": true,
24 | "license": "MIT",
25 | "dependencies": {
26 | "@babel/helper-validator-identifier": "^7.25.9",
27 | "js-tokens": "^4.0.0",
28 | "picocolors": "^1.0.0"
29 | },
30 | "engines": {
31 | "node": ">=6.9.0"
32 | }
33 | },
34 | "node_modules/@babel/helper-string-parser": {
35 | "version": "7.25.9",
36 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
37 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
38 | "dev": true,
39 | "license": "MIT",
40 | "engines": {
41 | "node": ">=6.9.0"
42 | }
43 | },
44 | "node_modules/@babel/helper-validator-identifier": {
45 | "version": "7.25.9",
46 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
47 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
48 | "dev": true,
49 | "license": "MIT",
50 | "engines": {
51 | "node": ">=6.9.0"
52 | }
53 | },
54 | "node_modules/@babel/parser": {
55 | "version": "7.26.9",
56 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
57 | "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
58 | "dev": true,
59 | "license": "MIT",
60 | "dependencies": {
61 | "@babel/types": "^7.26.9"
62 | },
63 | "bin": {
64 | "parser": "bin/babel-parser.js"
65 | },
66 | "engines": {
67 | "node": ">=6.0.0"
68 | }
69 | },
70 | "node_modules/@babel/types": {
71 | "version": "7.26.9",
72 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
73 | "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
74 | "dev": true,
75 | "license": "MIT",
76 | "dependencies": {
77 | "@babel/helper-string-parser": "^7.25.9",
78 | "@babel/helper-validator-identifier": "^7.25.9"
79 | },
80 | "engines": {
81 | "node": ">=6.9.0"
82 | }
83 | },
84 | "node_modules/@biomejs/biome": {
85 | "version": "2.0.0-beta.1",
86 | "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.0.0-beta.1.tgz",
87 | "integrity": "sha512-MqRoy9CbTkrS45zW+S4u8p4kQUIFx0mGUWi789W1R3b1kXYIudEqsTKgXKtTGsI0kWOlvnjuKqwTrabjaGchhQ==",
88 | "dev": true,
89 | "license": "MIT OR Apache-2.0",
90 | "bin": {
91 | "biome": "bin/biome"
92 | },
93 | "engines": {
94 | "node": ">=14.21.3"
95 | },
96 | "funding": {
97 | "type": "opencollective",
98 | "url": "https://opencollective.com/biome"
99 | },
100 | "optionalDependencies": {
101 | "@biomejs/cli-darwin-arm64": "2.0.0-beta.1",
102 | "@biomejs/cli-darwin-x64": "2.0.0-beta.1",
103 | "@biomejs/cli-linux-arm64": "2.0.0-beta.1",
104 | "@biomejs/cli-linux-arm64-musl": "2.0.0-beta.1",
105 | "@biomejs/cli-linux-x64": "2.0.0-beta.1",
106 | "@biomejs/cli-linux-x64-musl": "2.0.0-beta.1",
107 | "@biomejs/cli-win32-arm64": "2.0.0-beta.1",
108 | "@biomejs/cli-win32-x64": "2.0.0-beta.1"
109 | }
110 | },
111 | "node_modules/@biomejs/cli-darwin-arm64": {
112 | "version": "2.0.0-beta.1",
113 | "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0-beta.1.tgz",
114 | "integrity": "sha512-RaGmpNLl5NFooXaoCwvgvcuU6Am/rMZ3R48pQeCVxjrCcz1BIlKLTai5UosiedazW7JbXAvgXdSNizYG7ITlAQ==",
115 | "cpu": [
116 | "arm64"
117 | ],
118 | "dev": true,
119 | "license": "MIT OR Apache-2.0",
120 | "optional": true,
121 | "os": [
122 | "darwin"
123 | ],
124 | "engines": {
125 | "node": ">=14.21.3"
126 | }
127 | },
128 | "node_modules/@biomejs/cli-darwin-x64": {
129 | "version": "2.0.0-beta.1",
130 | "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.0.0-beta.1.tgz",
131 | "integrity": "sha512-sTzSshkne7HKZFNfiIhmAji7gjtCBXvkTujZELCZWIZC7oj1Tjw/gvAzbdFj2UyHd5/i90pND4ybFOLQZm9gpg==",
132 | "cpu": [
133 | "x64"
134 | ],
135 | "dev": true,
136 | "license": "MIT OR Apache-2.0",
137 | "optional": true,
138 | "os": [
139 | "darwin"
140 | ],
141 | "engines": {
142 | "node": ">=14.21.3"
143 | }
144 | },
145 | "node_modules/@biomejs/cli-linux-arm64": {
146 | "version": "2.0.0-beta.1",
147 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.0.0-beta.1.tgz",
148 | "integrity": "sha512-bxce2O4nooBmp20Ey0+IFIZyy/b0RVnciIQk9euCfAi9evq7SvFtMBYo3YUZej0KIvrau5H7tJk5OqmRJk2l+g==",
149 | "cpu": [
150 | "arm64"
151 | ],
152 | "dev": true,
153 | "license": "MIT OR Apache-2.0",
154 | "optional": true,
155 | "os": [
156 | "linux"
157 | ],
158 | "engines": {
159 | "node": ">=14.21.3"
160 | }
161 | },
162 | "node_modules/@biomejs/cli-linux-arm64-musl": {
163 | "version": "2.0.0-beta.1",
164 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0-beta.1.tgz",
165 | "integrity": "sha512-0MPUKzz9uBBxAYSJ+OlFi4+yGwiRcZeFqq39H0MxXCQ9MMpKJFH2Ek72fw8sXwG7Prn7EsW/3u1b7najyn1XGQ==",
166 | "cpu": [
167 | "arm64"
168 | ],
169 | "dev": true,
170 | "license": "MIT OR Apache-2.0",
171 | "optional": true,
172 | "os": [
173 | "linux"
174 | ],
175 | "engines": {
176 | "node": ">=14.21.3"
177 | }
178 | },
179 | "node_modules/@biomejs/cli-linux-x64": {
180 | "version": "2.0.0-beta.1",
181 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.0.0-beta.1.tgz",
182 | "integrity": "sha512-6P/AtJv4hOH8mu8ez0c4UInUpiet9NEoF25+O7OPyb4w6ZHJMp2qzvayJS7TKrTQzE5KUvSiNsACGRz34DzUkg==",
183 | "cpu": [
184 | "x64"
185 | ],
186 | "dev": true,
187 | "license": "MIT OR Apache-2.0",
188 | "optional": true,
189 | "os": [
190 | "linux"
191 | ],
192 | "engines": {
193 | "node": ">=14.21.3"
194 | }
195 | },
196 | "node_modules/@biomejs/cli-linux-x64-musl": {
197 | "version": "2.0.0-beta.1",
198 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0-beta.1.tgz",
199 | "integrity": "sha512-dFvisnP1hFpVILNw0PZfs8piBwe8+aykO04Tb/4AJDVVzKkGgJfwSefwo4jqzO/Wk/Zruvhcp1nKbjgRXM+vDg==",
200 | "cpu": [
201 | "x64"
202 | ],
203 | "dev": true,
204 | "license": "MIT OR Apache-2.0",
205 | "optional": true,
206 | "os": [
207 | "linux"
208 | ],
209 | "engines": {
210 | "node": ">=14.21.3"
211 | }
212 | },
213 | "node_modules/@biomejs/cli-win32-arm64": {
214 | "version": "2.0.0-beta.1",
215 | "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.0.0-beta.1.tgz",
216 | "integrity": "sha512-0C9YSqWHf2cJGnjKDbLi49xv6H9IfqbDsFav7X557PqwY64O6IKWqcmZzi/PkDFHjQM9opU6uhKapeGKGDxziQ==",
217 | "cpu": [
218 | "arm64"
219 | ],
220 | "dev": true,
221 | "license": "MIT OR Apache-2.0",
222 | "optional": true,
223 | "os": [
224 | "win32"
225 | ],
226 | "engines": {
227 | "node": ">=14.21.3"
228 | }
229 | },
230 | "node_modules/@biomejs/cli-win32-x64": {
231 | "version": "2.0.0-beta.1",
232 | "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.0.0-beta.1.tgz",
233 | "integrity": "sha512-o8W6+DX0YRjt1kS8Y3ismq6EkjwiVDv7X0TEpfnFywoVG8HoJ7G7/m9r8LM1yE46WI3maPH2A0MoVpQ1ZNG++A==",
234 | "cpu": [
235 | "x64"
236 | ],
237 | "dev": true,
238 | "license": "MIT OR Apache-2.0",
239 | "optional": true,
240 | "os": [
241 | "win32"
242 | ],
243 | "engines": {
244 | "node": ">=14.21.3"
245 | }
246 | },
247 | "node_modules/@chialab/esbuild-plugin-html": {
248 | "version": "0.18.2",
249 | "resolved": "https://registry.npmjs.org/@chialab/esbuild-plugin-html/-/esbuild-plugin-html-0.18.2.tgz",
250 | "integrity": "sha512-8dBqIZIL1tkLYyMko+HY8b80QoDOIGlydbIQO8ALLv4e59UO0MGQjFG3RCD0V5sMbpjeNrJ3MCKz29wGL16Wrg==",
251 | "dev": true,
252 | "license": "MIT",
253 | "dependencies": {
254 | "@chialab/esbuild-rna": "^0.18.1"
255 | },
256 | "engines": {
257 | "node": ">=18"
258 | },
259 | "peerDependencies": {
260 | "htmlnano": "^2.0.0"
261 | },
262 | "peerDependenciesMeta": {
263 | "htmlnano": {
264 | "optional": true
265 | }
266 | }
267 | },
268 | "node_modules/@chialab/esbuild-rna": {
269 | "version": "0.18.2",
270 | "resolved": "https://registry.npmjs.org/@chialab/esbuild-rna/-/esbuild-rna-0.18.2.tgz",
271 | "integrity": "sha512-ckzskez7bxstVQ4c5cxbx0DRP2teldzrcSGQl2KPh1VJGdO2ZmRrb6vNkBBD5K3dx9tgTyvskWp4dV+Fbg07Ag==",
272 | "dev": true,
273 | "license": "MIT",
274 | "dependencies": {
275 | "@chialab/estransform": "^0.18.0",
276 | "@chialab/node-resolve": "^0.18.0"
277 | },
278 | "engines": {
279 | "node": ">=18"
280 | }
281 | },
282 | "node_modules/@chialab/estransform": {
283 | "version": "0.18.1",
284 | "resolved": "https://registry.npmjs.org/@chialab/estransform/-/estransform-0.18.1.tgz",
285 | "integrity": "sha512-W/WmjpQL2hndD0/XfR0FcPBAUj+aLNeoAVehOjV/Q9bSnioz0GVSAXXhzp59S33ZynxJBBfn8DNiMTVNJmk4Aw==",
286 | "dev": true,
287 | "license": "MIT",
288 | "dependencies": {
289 | "@parcel/source-map": "^2.0.0"
290 | },
291 | "engines": {
292 | "node": ">=18"
293 | }
294 | },
295 | "node_modules/@chialab/node-resolve": {
296 | "version": "0.18.0",
297 | "resolved": "https://registry.npmjs.org/@chialab/node-resolve/-/node-resolve-0.18.0.tgz",
298 | "integrity": "sha512-eV1m70Qn9pLY9xwFmZ2FlcOzwiaUywsJ7NB/ud8VB7DouvCQtIHkQ3Om7uPX0ojXGEG1LCyO96kZkvbNTxNu0Q==",
299 | "dev": true,
300 | "license": "MIT",
301 | "engines": {
302 | "node": ">=18"
303 | }
304 | },
305 | "node_modules/@esbuild/aix-ppc64": {
306 | "version": "0.25.1",
307 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
308 | "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
309 | "cpu": [
310 | "ppc64"
311 | ],
312 | "dev": true,
313 | "license": "MIT",
314 | "optional": true,
315 | "os": [
316 | "aix"
317 | ],
318 | "engines": {
319 | "node": ">=18"
320 | }
321 | },
322 | "node_modules/@esbuild/android-arm": {
323 | "version": "0.25.1",
324 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
325 | "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
326 | "cpu": [
327 | "arm"
328 | ],
329 | "dev": true,
330 | "license": "MIT",
331 | "optional": true,
332 | "os": [
333 | "android"
334 | ],
335 | "engines": {
336 | "node": ">=18"
337 | }
338 | },
339 | "node_modules/@esbuild/android-arm64": {
340 | "version": "0.25.1",
341 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
342 | "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
343 | "cpu": [
344 | "arm64"
345 | ],
346 | "dev": true,
347 | "license": "MIT",
348 | "optional": true,
349 | "os": [
350 | "android"
351 | ],
352 | "engines": {
353 | "node": ">=18"
354 | }
355 | },
356 | "node_modules/@esbuild/android-x64": {
357 | "version": "0.25.1",
358 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
359 | "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
360 | "cpu": [
361 | "x64"
362 | ],
363 | "dev": true,
364 | "license": "MIT",
365 | "optional": true,
366 | "os": [
367 | "android"
368 | ],
369 | "engines": {
370 | "node": ">=18"
371 | }
372 | },
373 | "node_modules/@esbuild/darwin-arm64": {
374 | "version": "0.25.1",
375 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
376 | "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
377 | "cpu": [
378 | "arm64"
379 | ],
380 | "dev": true,
381 | "license": "MIT",
382 | "optional": true,
383 | "os": [
384 | "darwin"
385 | ],
386 | "engines": {
387 | "node": ">=18"
388 | }
389 | },
390 | "node_modules/@esbuild/darwin-x64": {
391 | "version": "0.25.1",
392 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
393 | "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
394 | "cpu": [
395 | "x64"
396 | ],
397 | "dev": true,
398 | "license": "MIT",
399 | "optional": true,
400 | "os": [
401 | "darwin"
402 | ],
403 | "engines": {
404 | "node": ">=18"
405 | }
406 | },
407 | "node_modules/@esbuild/freebsd-arm64": {
408 | "version": "0.25.1",
409 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
410 | "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
411 | "cpu": [
412 | "arm64"
413 | ],
414 | "dev": true,
415 | "license": "MIT",
416 | "optional": true,
417 | "os": [
418 | "freebsd"
419 | ],
420 | "engines": {
421 | "node": ">=18"
422 | }
423 | },
424 | "node_modules/@esbuild/freebsd-x64": {
425 | "version": "0.25.1",
426 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
427 | "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
428 | "cpu": [
429 | "x64"
430 | ],
431 | "dev": true,
432 | "license": "MIT",
433 | "optional": true,
434 | "os": [
435 | "freebsd"
436 | ],
437 | "engines": {
438 | "node": ">=18"
439 | }
440 | },
441 | "node_modules/@esbuild/linux-arm": {
442 | "version": "0.25.1",
443 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
444 | "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
445 | "cpu": [
446 | "arm"
447 | ],
448 | "dev": true,
449 | "license": "MIT",
450 | "optional": true,
451 | "os": [
452 | "linux"
453 | ],
454 | "engines": {
455 | "node": ">=18"
456 | }
457 | },
458 | "node_modules/@esbuild/linux-arm64": {
459 | "version": "0.25.1",
460 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
461 | "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
462 | "cpu": [
463 | "arm64"
464 | ],
465 | "dev": true,
466 | "license": "MIT",
467 | "optional": true,
468 | "os": [
469 | "linux"
470 | ],
471 | "engines": {
472 | "node": ">=18"
473 | }
474 | },
475 | "node_modules/@esbuild/linux-ia32": {
476 | "version": "0.25.1",
477 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
478 | "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
479 | "cpu": [
480 | "ia32"
481 | ],
482 | "dev": true,
483 | "license": "MIT",
484 | "optional": true,
485 | "os": [
486 | "linux"
487 | ],
488 | "engines": {
489 | "node": ">=18"
490 | }
491 | },
492 | "node_modules/@esbuild/linux-loong64": {
493 | "version": "0.25.1",
494 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
495 | "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
496 | "cpu": [
497 | "loong64"
498 | ],
499 | "dev": true,
500 | "license": "MIT",
501 | "optional": true,
502 | "os": [
503 | "linux"
504 | ],
505 | "engines": {
506 | "node": ">=18"
507 | }
508 | },
509 | "node_modules/@esbuild/linux-mips64el": {
510 | "version": "0.25.1",
511 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
512 | "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
513 | "cpu": [
514 | "mips64el"
515 | ],
516 | "dev": true,
517 | "license": "MIT",
518 | "optional": true,
519 | "os": [
520 | "linux"
521 | ],
522 | "engines": {
523 | "node": ">=18"
524 | }
525 | },
526 | "node_modules/@esbuild/linux-ppc64": {
527 | "version": "0.25.1",
528 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
529 | "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
530 | "cpu": [
531 | "ppc64"
532 | ],
533 | "dev": true,
534 | "license": "MIT",
535 | "optional": true,
536 | "os": [
537 | "linux"
538 | ],
539 | "engines": {
540 | "node": ">=18"
541 | }
542 | },
543 | "node_modules/@esbuild/linux-riscv64": {
544 | "version": "0.25.1",
545 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
546 | "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
547 | "cpu": [
548 | "riscv64"
549 | ],
550 | "dev": true,
551 | "license": "MIT",
552 | "optional": true,
553 | "os": [
554 | "linux"
555 | ],
556 | "engines": {
557 | "node": ">=18"
558 | }
559 | },
560 | "node_modules/@esbuild/linux-s390x": {
561 | "version": "0.25.1",
562 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
563 | "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
564 | "cpu": [
565 | "s390x"
566 | ],
567 | "dev": true,
568 | "license": "MIT",
569 | "optional": true,
570 | "os": [
571 | "linux"
572 | ],
573 | "engines": {
574 | "node": ">=18"
575 | }
576 | },
577 | "node_modules/@esbuild/linux-x64": {
578 | "version": "0.25.1",
579 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
580 | "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
581 | "cpu": [
582 | "x64"
583 | ],
584 | "dev": true,
585 | "license": "MIT",
586 | "optional": true,
587 | "os": [
588 | "linux"
589 | ],
590 | "engines": {
591 | "node": ">=18"
592 | }
593 | },
594 | "node_modules/@esbuild/netbsd-arm64": {
595 | "version": "0.25.1",
596 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
597 | "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
598 | "cpu": [
599 | "arm64"
600 | ],
601 | "dev": true,
602 | "license": "MIT",
603 | "optional": true,
604 | "os": [
605 | "netbsd"
606 | ],
607 | "engines": {
608 | "node": ">=18"
609 | }
610 | },
611 | "node_modules/@esbuild/netbsd-x64": {
612 | "version": "0.25.1",
613 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
614 | "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
615 | "cpu": [
616 | "x64"
617 | ],
618 | "dev": true,
619 | "license": "MIT",
620 | "optional": true,
621 | "os": [
622 | "netbsd"
623 | ],
624 | "engines": {
625 | "node": ">=18"
626 | }
627 | },
628 | "node_modules/@esbuild/openbsd-arm64": {
629 | "version": "0.25.1",
630 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
631 | "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
632 | "cpu": [
633 | "arm64"
634 | ],
635 | "dev": true,
636 | "license": "MIT",
637 | "optional": true,
638 | "os": [
639 | "openbsd"
640 | ],
641 | "engines": {
642 | "node": ">=18"
643 | }
644 | },
645 | "node_modules/@esbuild/openbsd-x64": {
646 | "version": "0.25.1",
647 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
648 | "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
649 | "cpu": [
650 | "x64"
651 | ],
652 | "dev": true,
653 | "license": "MIT",
654 | "optional": true,
655 | "os": [
656 | "openbsd"
657 | ],
658 | "engines": {
659 | "node": ">=18"
660 | }
661 | },
662 | "node_modules/@esbuild/sunos-x64": {
663 | "version": "0.25.1",
664 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
665 | "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
666 | "cpu": [
667 | "x64"
668 | ],
669 | "dev": true,
670 | "license": "MIT",
671 | "optional": true,
672 | "os": [
673 | "sunos"
674 | ],
675 | "engines": {
676 | "node": ">=18"
677 | }
678 | },
679 | "node_modules/@esbuild/win32-arm64": {
680 | "version": "0.25.1",
681 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
682 | "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
683 | "cpu": [
684 | "arm64"
685 | ],
686 | "dev": true,
687 | "license": "MIT",
688 | "optional": true,
689 | "os": [
690 | "win32"
691 | ],
692 | "engines": {
693 | "node": ">=18"
694 | }
695 | },
696 | "node_modules/@esbuild/win32-ia32": {
697 | "version": "0.25.1",
698 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
699 | "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
700 | "cpu": [
701 | "ia32"
702 | ],
703 | "dev": true,
704 | "license": "MIT",
705 | "optional": true,
706 | "os": [
707 | "win32"
708 | ],
709 | "engines": {
710 | "node": ">=18"
711 | }
712 | },
713 | "node_modules/@esbuild/win32-x64": {
714 | "version": "0.25.1",
715 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
716 | "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
717 | "cpu": [
718 | "x64"
719 | ],
720 | "dev": true,
721 | "license": "MIT",
722 | "optional": true,
723 | "os": [
724 | "win32"
725 | ],
726 | "engines": {
727 | "node": ">=18"
728 | }
729 | },
730 | "node_modules/@jridgewell/sourcemap-codec": {
731 | "version": "1.5.0",
732 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
733 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
734 | "dev": true,
735 | "license": "MIT"
736 | },
737 | "node_modules/@parcel/source-map": {
738 | "version": "2.1.1",
739 | "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz",
740 | "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==",
741 | "dev": true,
742 | "license": "MIT",
743 | "dependencies": {
744 | "detect-libc": "^1.0.3"
745 | },
746 | "engines": {
747 | "node": "^12.18.3 || >=14"
748 | }
749 | },
750 | "node_modules/@popperjs/core": {
751 | "version": "2.11.8",
752 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
753 | "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
754 | "dev": true,
755 | "license": "MIT",
756 | "peer": true,
757 | "funding": {
758 | "type": "opencollective",
759 | "url": "https://opencollective.com/popperjs"
760 | }
761 | },
762 | "node_modules/@vue/compiler-core": {
763 | "version": "3.5.13",
764 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz",
765 | "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==",
766 | "dev": true,
767 | "license": "MIT",
768 | "dependencies": {
769 | "@babel/parser": "^7.25.3",
770 | "@vue/shared": "3.5.13",
771 | "entities": "^4.5.0",
772 | "estree-walker": "^2.0.2",
773 | "source-map-js": "^1.2.0"
774 | }
775 | },
776 | "node_modules/@vue/compiler-dom": {
777 | "version": "3.5.13",
778 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz",
779 | "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==",
780 | "dev": true,
781 | "license": "MIT",
782 | "dependencies": {
783 | "@vue/compiler-core": "3.5.13",
784 | "@vue/shared": "3.5.13"
785 | }
786 | },
787 | "node_modules/@vue/compiler-sfc": {
788 | "version": "3.5.13",
789 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz",
790 | "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==",
791 | "dev": true,
792 | "license": "MIT",
793 | "dependencies": {
794 | "@babel/parser": "^7.25.3",
795 | "@vue/compiler-core": "3.5.13",
796 | "@vue/compiler-dom": "3.5.13",
797 | "@vue/compiler-ssr": "3.5.13",
798 | "@vue/shared": "3.5.13",
799 | "estree-walker": "^2.0.2",
800 | "magic-string": "^0.30.11",
801 | "postcss": "^8.4.48",
802 | "source-map-js": "^1.2.0"
803 | }
804 | },
805 | "node_modules/@vue/compiler-ssr": {
806 | "version": "3.5.13",
807 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz",
808 | "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==",
809 | "dev": true,
810 | "license": "MIT",
811 | "dependencies": {
812 | "@vue/compiler-dom": "3.5.13",
813 | "@vue/shared": "3.5.13"
814 | }
815 | },
816 | "node_modules/@vue/reactivity": {
817 | "version": "3.5.13",
818 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz",
819 | "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==",
820 | "dev": true,
821 | "license": "MIT",
822 | "dependencies": {
823 | "@vue/shared": "3.5.13"
824 | }
825 | },
826 | "node_modules/@vue/runtime-core": {
827 | "version": "3.5.13",
828 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz",
829 | "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==",
830 | "dev": true,
831 | "license": "MIT",
832 | "dependencies": {
833 | "@vue/reactivity": "3.5.13",
834 | "@vue/shared": "3.5.13"
835 | }
836 | },
837 | "node_modules/@vue/runtime-dom": {
838 | "version": "3.5.13",
839 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz",
840 | "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==",
841 | "dev": true,
842 | "license": "MIT",
843 | "dependencies": {
844 | "@vue/reactivity": "3.5.13",
845 | "@vue/runtime-core": "3.5.13",
846 | "@vue/shared": "3.5.13",
847 | "csstype": "^3.1.3"
848 | }
849 | },
850 | "node_modules/@vue/server-renderer": {
851 | "version": "3.5.13",
852 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz",
853 | "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==",
854 | "dev": true,
855 | "license": "MIT",
856 | "dependencies": {
857 | "@vue/compiler-ssr": "3.5.13",
858 | "@vue/shared": "3.5.13"
859 | },
860 | "peerDependencies": {
861 | "vue": "3.5.13"
862 | }
863 | },
864 | "node_modules/@vue/shared": {
865 | "version": "3.5.13",
866 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz",
867 | "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
868 | "dev": true,
869 | "license": "MIT"
870 | },
871 | "node_modules/@vue/tsconfig": {
872 | "version": "0.7.0",
873 | "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.7.0.tgz",
874 | "integrity": "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==",
875 | "dev": true,
876 | "license": "MIT",
877 | "peerDependencies": {
878 | "typescript": "5.x",
879 | "vue": "^3.4.0"
880 | },
881 | "peerDependenciesMeta": {
882 | "typescript": {
883 | "optional": true
884 | },
885 | "vue": {
886 | "optional": true
887 | }
888 | }
889 | },
890 | "node_modules/argparse": {
891 | "version": "2.0.1",
892 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
893 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
894 | "dev": true,
895 | "license": "Python-2.0"
896 | },
897 | "node_modules/bootstrap": {
898 | "version": "5.3.3",
899 | "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
900 | "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
901 | "dev": true,
902 | "funding": [
903 | {
904 | "type": "github",
905 | "url": "https://github.com/sponsors/twbs"
906 | },
907 | {
908 | "type": "opencollective",
909 | "url": "https://opencollective.com/bootstrap"
910 | }
911 | ],
912 | "license": "MIT",
913 | "peerDependencies": {
914 | "@popperjs/core": "^2.11.8"
915 | }
916 | },
917 | "node_modules/callsites": {
918 | "version": "3.1.0",
919 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
920 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
921 | "dev": true,
922 | "license": "MIT",
923 | "engines": {
924 | "node": ">=6"
925 | }
926 | },
927 | "node_modules/cosmiconfig": {
928 | "version": "9.0.0",
929 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
930 | "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
931 | "dev": true,
932 | "license": "MIT",
933 | "dependencies": {
934 | "env-paths": "^2.2.1",
935 | "import-fresh": "^3.3.0",
936 | "js-yaml": "^4.1.0",
937 | "parse-json": "^5.2.0"
938 | },
939 | "engines": {
940 | "node": ">=14"
941 | },
942 | "funding": {
943 | "url": "https://github.com/sponsors/d-fischer"
944 | },
945 | "peerDependencies": {
946 | "typescript": ">=4.9.5"
947 | },
948 | "peerDependenciesMeta": {
949 | "typescript": {
950 | "optional": true
951 | }
952 | }
953 | },
954 | "node_modules/csstype": {
955 | "version": "3.1.3",
956 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
957 | "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
958 | "dev": true,
959 | "license": "MIT"
960 | },
961 | "node_modules/detect-libc": {
962 | "version": "1.0.3",
963 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
964 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
965 | "dev": true,
966 | "license": "Apache-2.0",
967 | "bin": {
968 | "detect-libc": "bin/detect-libc.js"
969 | },
970 | "engines": {
971 | "node": ">=0.10"
972 | }
973 | },
974 | "node_modules/dom-serializer": {
975 | "version": "1.4.1",
976 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
977 | "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
978 | "dev": true,
979 | "license": "MIT",
980 | "dependencies": {
981 | "domelementtype": "^2.0.1",
982 | "domhandler": "^4.2.0",
983 | "entities": "^2.0.0"
984 | },
985 | "funding": {
986 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
987 | }
988 | },
989 | "node_modules/dom-serializer/node_modules/entities": {
990 | "version": "2.2.0",
991 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
992 | "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
993 | "dev": true,
994 | "license": "BSD-2-Clause",
995 | "funding": {
996 | "url": "https://github.com/fb55/entities?sponsor=1"
997 | }
998 | },
999 | "node_modules/domelementtype": {
1000 | "version": "2.3.0",
1001 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
1002 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
1003 | "dev": true,
1004 | "funding": [
1005 | {
1006 | "type": "github",
1007 | "url": "https://github.com/sponsors/fb55"
1008 | }
1009 | ],
1010 | "license": "BSD-2-Clause"
1011 | },
1012 | "node_modules/domhandler": {
1013 | "version": "4.3.1",
1014 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
1015 | "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
1016 | "dev": true,
1017 | "license": "BSD-2-Clause",
1018 | "dependencies": {
1019 | "domelementtype": "^2.2.0"
1020 | },
1021 | "engines": {
1022 | "node": ">= 4"
1023 | },
1024 | "funding": {
1025 | "url": "https://github.com/fb55/domhandler?sponsor=1"
1026 | }
1027 | },
1028 | "node_modules/domutils": {
1029 | "version": "2.8.0",
1030 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
1031 | "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
1032 | "dev": true,
1033 | "license": "BSD-2-Clause",
1034 | "dependencies": {
1035 | "dom-serializer": "^1.0.1",
1036 | "domelementtype": "^2.2.0",
1037 | "domhandler": "^4.2.0"
1038 | },
1039 | "funding": {
1040 | "url": "https://github.com/fb55/domutils?sponsor=1"
1041 | }
1042 | },
1043 | "node_modules/entities": {
1044 | "version": "4.5.0",
1045 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
1046 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
1047 | "dev": true,
1048 | "license": "BSD-2-Clause",
1049 | "engines": {
1050 | "node": ">=0.12"
1051 | },
1052 | "funding": {
1053 | "url": "https://github.com/fb55/entities?sponsor=1"
1054 | }
1055 | },
1056 | "node_modules/env-paths": {
1057 | "version": "2.2.1",
1058 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
1059 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
1060 | "dev": true,
1061 | "license": "MIT",
1062 | "engines": {
1063 | "node": ">=6"
1064 | }
1065 | },
1066 | "node_modules/error-ex": {
1067 | "version": "1.3.2",
1068 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
1069 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
1070 | "dev": true,
1071 | "license": "MIT",
1072 | "dependencies": {
1073 | "is-arrayish": "^0.2.1"
1074 | }
1075 | },
1076 | "node_modules/esbuild": {
1077 | "version": "0.25.1",
1078 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
1079 | "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
1080 | "dev": true,
1081 | "hasInstallScript": true,
1082 | "license": "MIT",
1083 | "bin": {
1084 | "esbuild": "bin/esbuild"
1085 | },
1086 | "engines": {
1087 | "node": ">=18"
1088 | },
1089 | "optionalDependencies": {
1090 | "@esbuild/aix-ppc64": "0.25.1",
1091 | "@esbuild/android-arm": "0.25.1",
1092 | "@esbuild/android-arm64": "0.25.1",
1093 | "@esbuild/android-x64": "0.25.1",
1094 | "@esbuild/darwin-arm64": "0.25.1",
1095 | "@esbuild/darwin-x64": "0.25.1",
1096 | "@esbuild/freebsd-arm64": "0.25.1",
1097 | "@esbuild/freebsd-x64": "0.25.1",
1098 | "@esbuild/linux-arm": "0.25.1",
1099 | "@esbuild/linux-arm64": "0.25.1",
1100 | "@esbuild/linux-ia32": "0.25.1",
1101 | "@esbuild/linux-loong64": "0.25.1",
1102 | "@esbuild/linux-mips64el": "0.25.1",
1103 | "@esbuild/linux-ppc64": "0.25.1",
1104 | "@esbuild/linux-riscv64": "0.25.1",
1105 | "@esbuild/linux-s390x": "0.25.1",
1106 | "@esbuild/linux-x64": "0.25.1",
1107 | "@esbuild/netbsd-arm64": "0.25.1",
1108 | "@esbuild/netbsd-x64": "0.25.1",
1109 | "@esbuild/openbsd-arm64": "0.25.1",
1110 | "@esbuild/openbsd-x64": "0.25.1",
1111 | "@esbuild/sunos-x64": "0.25.1",
1112 | "@esbuild/win32-arm64": "0.25.1",
1113 | "@esbuild/win32-ia32": "0.25.1",
1114 | "@esbuild/win32-x64": "0.25.1"
1115 | }
1116 | },
1117 | "node_modules/esbuild-android-64": {
1118 | "version": "0.14.54",
1119 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz",
1120 | "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==",
1121 | "cpu": [
1122 | "x64"
1123 | ],
1124 | "dev": true,
1125 | "license": "MIT",
1126 | "optional": true,
1127 | "os": [
1128 | "android"
1129 | ],
1130 | "engines": {
1131 | "node": ">=12"
1132 | }
1133 | },
1134 | "node_modules/esbuild-android-arm64": {
1135 | "version": "0.14.54",
1136 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz",
1137 | "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==",
1138 | "cpu": [
1139 | "arm64"
1140 | ],
1141 | "dev": true,
1142 | "license": "MIT",
1143 | "optional": true,
1144 | "os": [
1145 | "android"
1146 | ],
1147 | "engines": {
1148 | "node": ">=12"
1149 | }
1150 | },
1151 | "node_modules/esbuild-darwin-64": {
1152 | "version": "0.14.54",
1153 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz",
1154 | "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==",
1155 | "cpu": [
1156 | "x64"
1157 | ],
1158 | "dev": true,
1159 | "license": "MIT",
1160 | "optional": true,
1161 | "os": [
1162 | "darwin"
1163 | ],
1164 | "engines": {
1165 | "node": ">=12"
1166 | }
1167 | },
1168 | "node_modules/esbuild-darwin-arm64": {
1169 | "version": "0.14.54",
1170 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz",
1171 | "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==",
1172 | "cpu": [
1173 | "arm64"
1174 | ],
1175 | "dev": true,
1176 | "license": "MIT",
1177 | "optional": true,
1178 | "os": [
1179 | "darwin"
1180 | ],
1181 | "engines": {
1182 | "node": ">=12"
1183 | }
1184 | },
1185 | "node_modules/esbuild-freebsd-64": {
1186 | "version": "0.14.54",
1187 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz",
1188 | "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==",
1189 | "cpu": [
1190 | "x64"
1191 | ],
1192 | "dev": true,
1193 | "license": "MIT",
1194 | "optional": true,
1195 | "os": [
1196 | "freebsd"
1197 | ],
1198 | "engines": {
1199 | "node": ">=12"
1200 | }
1201 | },
1202 | "node_modules/esbuild-freebsd-arm64": {
1203 | "version": "0.14.54",
1204 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz",
1205 | "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==",
1206 | "cpu": [
1207 | "arm64"
1208 | ],
1209 | "dev": true,
1210 | "license": "MIT",
1211 | "optional": true,
1212 | "os": [
1213 | "freebsd"
1214 | ],
1215 | "engines": {
1216 | "node": ">=12"
1217 | }
1218 | },
1219 | "node_modules/esbuild-linux-32": {
1220 | "version": "0.14.54",
1221 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz",
1222 | "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==",
1223 | "cpu": [
1224 | "ia32"
1225 | ],
1226 | "dev": true,
1227 | "license": "MIT",
1228 | "optional": true,
1229 | "os": [
1230 | "linux"
1231 | ],
1232 | "engines": {
1233 | "node": ">=12"
1234 | }
1235 | },
1236 | "node_modules/esbuild-linux-64": {
1237 | "version": "0.14.54",
1238 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz",
1239 | "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==",
1240 | "cpu": [
1241 | "x64"
1242 | ],
1243 | "dev": true,
1244 | "license": "MIT",
1245 | "optional": true,
1246 | "os": [
1247 | "linux"
1248 | ],
1249 | "engines": {
1250 | "node": ">=12"
1251 | }
1252 | },
1253 | "node_modules/esbuild-linux-arm": {
1254 | "version": "0.14.54",
1255 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz",
1256 | "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==",
1257 | "cpu": [
1258 | "arm"
1259 | ],
1260 | "dev": true,
1261 | "license": "MIT",
1262 | "optional": true,
1263 | "os": [
1264 | "linux"
1265 | ],
1266 | "engines": {
1267 | "node": ">=12"
1268 | }
1269 | },
1270 | "node_modules/esbuild-linux-arm64": {
1271 | "version": "0.14.54",
1272 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz",
1273 | "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==",
1274 | "cpu": [
1275 | "arm64"
1276 | ],
1277 | "dev": true,
1278 | "license": "MIT",
1279 | "optional": true,
1280 | "os": [
1281 | "linux"
1282 | ],
1283 | "engines": {
1284 | "node": ">=12"
1285 | }
1286 | },
1287 | "node_modules/esbuild-linux-mips64le": {
1288 | "version": "0.14.54",
1289 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz",
1290 | "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==",
1291 | "cpu": [
1292 | "mips64el"
1293 | ],
1294 | "dev": true,
1295 | "license": "MIT",
1296 | "optional": true,
1297 | "os": [
1298 | "linux"
1299 | ],
1300 | "engines": {
1301 | "node": ">=12"
1302 | }
1303 | },
1304 | "node_modules/esbuild-linux-ppc64le": {
1305 | "version": "0.14.54",
1306 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz",
1307 | "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==",
1308 | "cpu": [
1309 | "ppc64"
1310 | ],
1311 | "dev": true,
1312 | "license": "MIT",
1313 | "optional": true,
1314 | "os": [
1315 | "linux"
1316 | ],
1317 | "engines": {
1318 | "node": ">=12"
1319 | }
1320 | },
1321 | "node_modules/esbuild-linux-riscv64": {
1322 | "version": "0.14.54",
1323 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz",
1324 | "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==",
1325 | "cpu": [
1326 | "riscv64"
1327 | ],
1328 | "dev": true,
1329 | "license": "MIT",
1330 | "optional": true,
1331 | "os": [
1332 | "linux"
1333 | ],
1334 | "engines": {
1335 | "node": ">=12"
1336 | }
1337 | },
1338 | "node_modules/esbuild-linux-s390x": {
1339 | "version": "0.14.54",
1340 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz",
1341 | "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==",
1342 | "cpu": [
1343 | "s390x"
1344 | ],
1345 | "dev": true,
1346 | "license": "MIT",
1347 | "optional": true,
1348 | "os": [
1349 | "linux"
1350 | ],
1351 | "engines": {
1352 | "node": ">=12"
1353 | }
1354 | },
1355 | "node_modules/esbuild-netbsd-64": {
1356 | "version": "0.14.54",
1357 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz",
1358 | "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==",
1359 | "cpu": [
1360 | "x64"
1361 | ],
1362 | "dev": true,
1363 | "license": "MIT",
1364 | "optional": true,
1365 | "os": [
1366 | "netbsd"
1367 | ],
1368 | "engines": {
1369 | "node": ">=12"
1370 | }
1371 | },
1372 | "node_modules/esbuild-openbsd-64": {
1373 | "version": "0.14.54",
1374 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz",
1375 | "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==",
1376 | "cpu": [
1377 | "x64"
1378 | ],
1379 | "dev": true,
1380 | "license": "MIT",
1381 | "optional": true,
1382 | "os": [
1383 | "openbsd"
1384 | ],
1385 | "engines": {
1386 | "node": ">=12"
1387 | }
1388 | },
1389 | "node_modules/esbuild-plugin-vue3": {
1390 | "version": "0.4.2",
1391 | "resolved": "https://registry.npmjs.org/esbuild-plugin-vue3/-/esbuild-plugin-vue3-0.4.2.tgz",
1392 | "integrity": "sha512-edaghOAJY+26uIJVywkT0cyUxWu/oi2+dGe2KePyHAJ9y6hAB4fqNnY5SFpZY9G6knERZo4Nykp/YOcKML06rA==",
1393 | "dev": true,
1394 | "license": "MIT",
1395 | "dependencies": {
1396 | "esbuild": "^0.14.8",
1397 | "typescript": "^4.7.4"
1398 | },
1399 | "peerDependencies": {
1400 | "cheerio": "^1.0.0-rc.10",
1401 | "html-minifier": "^4.0.0",
1402 | "pug": "^3.0.2",
1403 | "sass": "^1.35.2",
1404 | "vue": "^3.4.15"
1405 | },
1406 | "peerDependenciesMeta": {
1407 | "cheerio": {
1408 | "optional": true
1409 | },
1410 | "html-minifier": {
1411 | "optional": true
1412 | },
1413 | "pug": {
1414 | "optional": true
1415 | },
1416 | "sass": {
1417 | "optional": true
1418 | }
1419 | }
1420 | },
1421 | "node_modules/esbuild-plugin-vue3/node_modules/@esbuild/linux-loong64": {
1422 | "version": "0.14.54",
1423 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz",
1424 | "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==",
1425 | "cpu": [
1426 | "loong64"
1427 | ],
1428 | "dev": true,
1429 | "license": "MIT",
1430 | "optional": true,
1431 | "os": [
1432 | "linux"
1433 | ],
1434 | "engines": {
1435 | "node": ">=12"
1436 | }
1437 | },
1438 | "node_modules/esbuild-plugin-vue3/node_modules/esbuild": {
1439 | "version": "0.14.54",
1440 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz",
1441 | "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==",
1442 | "dev": true,
1443 | "hasInstallScript": true,
1444 | "license": "MIT",
1445 | "bin": {
1446 | "esbuild": "bin/esbuild"
1447 | },
1448 | "engines": {
1449 | "node": ">=12"
1450 | },
1451 | "optionalDependencies": {
1452 | "@esbuild/linux-loong64": "0.14.54",
1453 | "esbuild-android-64": "0.14.54",
1454 | "esbuild-android-arm64": "0.14.54",
1455 | "esbuild-darwin-64": "0.14.54",
1456 | "esbuild-darwin-arm64": "0.14.54",
1457 | "esbuild-freebsd-64": "0.14.54",
1458 | "esbuild-freebsd-arm64": "0.14.54",
1459 | "esbuild-linux-32": "0.14.54",
1460 | "esbuild-linux-64": "0.14.54",
1461 | "esbuild-linux-arm": "0.14.54",
1462 | "esbuild-linux-arm64": "0.14.54",
1463 | "esbuild-linux-mips64le": "0.14.54",
1464 | "esbuild-linux-ppc64le": "0.14.54",
1465 | "esbuild-linux-riscv64": "0.14.54",
1466 | "esbuild-linux-s390x": "0.14.54",
1467 | "esbuild-netbsd-64": "0.14.54",
1468 | "esbuild-openbsd-64": "0.14.54",
1469 | "esbuild-sunos-64": "0.14.54",
1470 | "esbuild-windows-32": "0.14.54",
1471 | "esbuild-windows-64": "0.14.54",
1472 | "esbuild-windows-arm64": "0.14.54"
1473 | }
1474 | },
1475 | "node_modules/esbuild-plugin-vue3/node_modules/typescript": {
1476 | "version": "4.9.5",
1477 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
1478 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
1479 | "dev": true,
1480 | "license": "Apache-2.0",
1481 | "bin": {
1482 | "tsc": "bin/tsc",
1483 | "tsserver": "bin/tsserver"
1484 | },
1485 | "engines": {
1486 | "node": ">=4.2.0"
1487 | }
1488 | },
1489 | "node_modules/esbuild-sunos-64": {
1490 | "version": "0.14.54",
1491 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz",
1492 | "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==",
1493 | "cpu": [
1494 | "x64"
1495 | ],
1496 | "dev": true,
1497 | "license": "MIT",
1498 | "optional": true,
1499 | "os": [
1500 | "sunos"
1501 | ],
1502 | "engines": {
1503 | "node": ">=12"
1504 | }
1505 | },
1506 | "node_modules/esbuild-windows-32": {
1507 | "version": "0.14.54",
1508 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz",
1509 | "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==",
1510 | "cpu": [
1511 | "ia32"
1512 | ],
1513 | "dev": true,
1514 | "license": "MIT",
1515 | "optional": true,
1516 | "os": [
1517 | "win32"
1518 | ],
1519 | "engines": {
1520 | "node": ">=12"
1521 | }
1522 | },
1523 | "node_modules/esbuild-windows-64": {
1524 | "version": "0.14.54",
1525 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz",
1526 | "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==",
1527 | "cpu": [
1528 | "x64"
1529 | ],
1530 | "dev": true,
1531 | "license": "MIT",
1532 | "optional": true,
1533 | "os": [
1534 | "win32"
1535 | ],
1536 | "engines": {
1537 | "node": ">=12"
1538 | }
1539 | },
1540 | "node_modules/esbuild-windows-arm64": {
1541 | "version": "0.14.54",
1542 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz",
1543 | "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==",
1544 | "cpu": [
1545 | "arm64"
1546 | ],
1547 | "dev": true,
1548 | "license": "MIT",
1549 | "optional": true,
1550 | "os": [
1551 | "win32"
1552 | ],
1553 | "engines": {
1554 | "node": ">=12"
1555 | }
1556 | },
1557 | "node_modules/estree-walker": {
1558 | "version": "2.0.2",
1559 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
1560 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
1561 | "dev": true,
1562 | "license": "MIT"
1563 | },
1564 | "node_modules/htmlnano": {
1565 | "version": "2.1.1",
1566 | "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.1.tgz",
1567 | "integrity": "sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==",
1568 | "dev": true,
1569 | "license": "MIT",
1570 | "dependencies": {
1571 | "cosmiconfig": "^9.0.0",
1572 | "posthtml": "^0.16.5",
1573 | "timsort": "^0.3.0"
1574 | },
1575 | "peerDependencies": {
1576 | "cssnano": "^7.0.0",
1577 | "postcss": "^8.3.11",
1578 | "purgecss": "^6.0.0",
1579 | "relateurl": "^0.2.7",
1580 | "srcset": "5.0.1",
1581 | "svgo": "^3.0.2",
1582 | "terser": "^5.10.0",
1583 | "uncss": "^0.17.3"
1584 | },
1585 | "peerDependenciesMeta": {
1586 | "cssnano": {
1587 | "optional": true
1588 | },
1589 | "postcss": {
1590 | "optional": true
1591 | },
1592 | "purgecss": {
1593 | "optional": true
1594 | },
1595 | "relateurl": {
1596 | "optional": true
1597 | },
1598 | "srcset": {
1599 | "optional": true
1600 | },
1601 | "svgo": {
1602 | "optional": true
1603 | },
1604 | "terser": {
1605 | "optional": true
1606 | },
1607 | "uncss": {
1608 | "optional": true
1609 | }
1610 | }
1611 | },
1612 | "node_modules/htmlparser2": {
1613 | "version": "7.2.0",
1614 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
1615 | "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
1616 | "dev": true,
1617 | "funding": [
1618 | "https://github.com/fb55/htmlparser2?sponsor=1",
1619 | {
1620 | "type": "github",
1621 | "url": "https://github.com/sponsors/fb55"
1622 | }
1623 | ],
1624 | "license": "MIT",
1625 | "dependencies": {
1626 | "domelementtype": "^2.0.1",
1627 | "domhandler": "^4.2.2",
1628 | "domutils": "^2.8.0",
1629 | "entities": "^3.0.1"
1630 | }
1631 | },
1632 | "node_modules/htmlparser2/node_modules/entities": {
1633 | "version": "3.0.1",
1634 | "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
1635 | "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
1636 | "dev": true,
1637 | "license": "BSD-2-Clause",
1638 | "engines": {
1639 | "node": ">=0.12"
1640 | },
1641 | "funding": {
1642 | "url": "https://github.com/fb55/entities?sponsor=1"
1643 | }
1644 | },
1645 | "node_modules/import-fresh": {
1646 | "version": "3.3.1",
1647 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
1648 | "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
1649 | "dev": true,
1650 | "license": "MIT",
1651 | "dependencies": {
1652 | "parent-module": "^1.0.0",
1653 | "resolve-from": "^4.0.0"
1654 | },
1655 | "engines": {
1656 | "node": ">=6"
1657 | },
1658 | "funding": {
1659 | "url": "https://github.com/sponsors/sindresorhus"
1660 | }
1661 | },
1662 | "node_modules/is-arrayish": {
1663 | "version": "0.2.1",
1664 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
1665 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
1666 | "dev": true,
1667 | "license": "MIT"
1668 | },
1669 | "node_modules/is-json": {
1670 | "version": "2.0.1",
1671 | "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
1672 | "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
1673 | "dev": true,
1674 | "license": "ISC"
1675 | },
1676 | "node_modules/js-tokens": {
1677 | "version": "4.0.0",
1678 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1679 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1680 | "dev": true,
1681 | "license": "MIT"
1682 | },
1683 | "node_modules/js-yaml": {
1684 | "version": "4.1.0",
1685 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
1686 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
1687 | "dev": true,
1688 | "license": "MIT",
1689 | "dependencies": {
1690 | "argparse": "^2.0.1"
1691 | },
1692 | "bin": {
1693 | "js-yaml": "bin/js-yaml.js"
1694 | }
1695 | },
1696 | "node_modules/json-parse-even-better-errors": {
1697 | "version": "2.3.1",
1698 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
1699 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
1700 | "dev": true,
1701 | "license": "MIT"
1702 | },
1703 | "node_modules/lines-and-columns": {
1704 | "version": "1.2.4",
1705 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
1706 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
1707 | "dev": true,
1708 | "license": "MIT"
1709 | },
1710 | "node_modules/magic-string": {
1711 | "version": "0.30.17",
1712 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
1713 | "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
1714 | "dev": true,
1715 | "license": "MIT",
1716 | "dependencies": {
1717 | "@jridgewell/sourcemap-codec": "^1.5.0"
1718 | }
1719 | },
1720 | "node_modules/nanoid": {
1721 | "version": "3.3.9",
1722 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz",
1723 | "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==",
1724 | "dev": true,
1725 | "funding": [
1726 | {
1727 | "type": "github",
1728 | "url": "https://github.com/sponsors/ai"
1729 | }
1730 | ],
1731 | "license": "MIT",
1732 | "bin": {
1733 | "nanoid": "bin/nanoid.cjs"
1734 | },
1735 | "engines": {
1736 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1737 | }
1738 | },
1739 | "node_modules/parent-module": {
1740 | "version": "1.0.1",
1741 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
1742 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
1743 | "dev": true,
1744 | "license": "MIT",
1745 | "dependencies": {
1746 | "callsites": "^3.0.0"
1747 | },
1748 | "engines": {
1749 | "node": ">=6"
1750 | }
1751 | },
1752 | "node_modules/parse-json": {
1753 | "version": "5.2.0",
1754 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
1755 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
1756 | "dev": true,
1757 | "license": "MIT",
1758 | "dependencies": {
1759 | "@babel/code-frame": "^7.0.0",
1760 | "error-ex": "^1.3.1",
1761 | "json-parse-even-better-errors": "^2.3.0",
1762 | "lines-and-columns": "^1.1.6"
1763 | },
1764 | "engines": {
1765 | "node": ">=8"
1766 | },
1767 | "funding": {
1768 | "url": "https://github.com/sponsors/sindresorhus"
1769 | }
1770 | },
1771 | "node_modules/picocolors": {
1772 | "version": "1.1.1",
1773 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1774 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1775 | "dev": true,
1776 | "license": "ISC"
1777 | },
1778 | "node_modules/postcss": {
1779 | "version": "8.5.3",
1780 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
1781 | "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
1782 | "dev": true,
1783 | "funding": [
1784 | {
1785 | "type": "opencollective",
1786 | "url": "https://opencollective.com/postcss/"
1787 | },
1788 | {
1789 | "type": "tidelift",
1790 | "url": "https://tidelift.com/funding/github/npm/postcss"
1791 | },
1792 | {
1793 | "type": "github",
1794 | "url": "https://github.com/sponsors/ai"
1795 | }
1796 | ],
1797 | "license": "MIT",
1798 | "dependencies": {
1799 | "nanoid": "^3.3.8",
1800 | "picocolors": "^1.1.1",
1801 | "source-map-js": "^1.2.1"
1802 | },
1803 | "engines": {
1804 | "node": "^10 || ^12 || >=14"
1805 | }
1806 | },
1807 | "node_modules/posthtml": {
1808 | "version": "0.16.6",
1809 | "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
1810 | "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
1811 | "dev": true,
1812 | "license": "MIT",
1813 | "dependencies": {
1814 | "posthtml-parser": "^0.11.0",
1815 | "posthtml-render": "^3.0.0"
1816 | },
1817 | "engines": {
1818 | "node": ">=12.0.0"
1819 | }
1820 | },
1821 | "node_modules/posthtml-parser": {
1822 | "version": "0.11.0",
1823 | "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
1824 | "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
1825 | "dev": true,
1826 | "license": "MIT",
1827 | "dependencies": {
1828 | "htmlparser2": "^7.1.1"
1829 | },
1830 | "engines": {
1831 | "node": ">=12"
1832 | }
1833 | },
1834 | "node_modules/posthtml-render": {
1835 | "version": "3.0.0",
1836 | "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
1837 | "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
1838 | "dev": true,
1839 | "license": "MIT",
1840 | "dependencies": {
1841 | "is-json": "^2.0.1"
1842 | },
1843 | "engines": {
1844 | "node": ">=12"
1845 | }
1846 | },
1847 | "node_modules/resolve-from": {
1848 | "version": "4.0.0",
1849 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
1850 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
1851 | "dev": true,
1852 | "license": "MIT",
1853 | "engines": {
1854 | "node": ">=4"
1855 | }
1856 | },
1857 | "node_modules/source-map-js": {
1858 | "version": "1.2.1",
1859 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
1860 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1861 | "dev": true,
1862 | "license": "BSD-3-Clause",
1863 | "engines": {
1864 | "node": ">=0.10.0"
1865 | }
1866 | },
1867 | "node_modules/timsort": {
1868 | "version": "0.3.0",
1869 | "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
1870 | "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==",
1871 | "dev": true,
1872 | "license": "MIT"
1873 | },
1874 | "node_modules/typescript": {
1875 | "version": "5.8.2",
1876 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
1877 | "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
1878 | "dev": true,
1879 | "license": "Apache-2.0",
1880 | "bin": {
1881 | "tsc": "bin/tsc",
1882 | "tsserver": "bin/tsserver"
1883 | },
1884 | "engines": {
1885 | "node": ">=14.17"
1886 | }
1887 | },
1888 | "node_modules/vue": {
1889 | "version": "3.5.13",
1890 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz",
1891 | "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
1892 | "dev": true,
1893 | "license": "MIT",
1894 | "dependencies": {
1895 | "@vue/compiler-dom": "3.5.13",
1896 | "@vue/compiler-sfc": "3.5.13",
1897 | "@vue/runtime-dom": "3.5.13",
1898 | "@vue/server-renderer": "3.5.13",
1899 | "@vue/shared": "3.5.13"
1900 | },
1901 | "peerDependencies": {
1902 | "typescript": "*"
1903 | },
1904 | "peerDependenciesMeta": {
1905 | "typescript": {
1906 | "optional": true
1907 | }
1908 | }
1909 | }
1910 | }
1911 | }
1912 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "build": "node build.mjs",
4 | "dev": "node build.mjs --dev",
5 | "test": "tsc && biome check",
6 | "fix": "biome check --write"
7 | },
8 | "devDependencies": {
9 | "@biomejs/biome": "^2.0.0-beta.1",
10 | "@chialab/esbuild-plugin-html": "^0.18.2",
11 | "@vue/tsconfig": "^0.7.0",
12 | "bootstrap": "^5.2.2",
13 | "esbuild": "^0.25.0",
14 | "esbuild-plugin-vue3": "^0.4.2",
15 | "htmlnano": "^2.1.1",
16 | "typescript": "^5.2.2",
17 | "vue": "^3.2.40"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/public/192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/192.png
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 404 · Page not found
10 |
11 |
12 | 404 Not Found
13 |
14 |
15 |
--------------------------------------------------------------------------------
/public/512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/512.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/favicon.ico
--------------------------------------------------------------------------------
/public/icons/artifact.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/artifact.jpg
--------------------------------------------------------------------------------
/public/icons/cs2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/cs2.jpg
--------------------------------------------------------------------------------
/public/icons/deadlock.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/deadlock.jpg
--------------------------------------------------------------------------------
/public/icons/dota.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/dota.jpg
--------------------------------------------------------------------------------
/public/icons/portal2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/portal2.jpg
--------------------------------------------------------------------------------
/public/icons/steam.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/steam.jpg
--------------------------------------------------------------------------------
/public/icons/tf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/tf.jpg
--------------------------------------------------------------------------------
/public/icons/underlords.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xPaw/SteamWebAPIDocumentation/7d148892ef314367ab66965687f8d3576e964d0a/public/icons/underlords.jpg
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Steam Web API Documentation",
3 | "short_name": "Steam Web API",
4 | "description": "An automatically generated list of Steam Web API interfaces, methods and parameters. Allows you to craft requests in the browser.",
5 | "start_url": "/",
6 | "display": "standalone",
7 | "theme_color": "#0d0d0d",
8 | "background_color": "#0d0d0d",
9 | "icons": [
10 | {
11 | "src": "favicon.ico",
12 | "sizes": "16x16 32x32 64x64"
13 | },
14 | {
15 | "src": "192.png",
16 | "sizes": "192x192"
17 | },
18 | {
19 | "src": "512.png",
20 | "sizes": "512x512"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 |
--------------------------------------------------------------------------------
/public/serviceworker.js:
--------------------------------------------------------------------------------
1 | self.addEventListener('install', () => self.skipWaiting());
2 | self.addEventListener('activate', (event) => event.waitUntil(self.clients.claim()));
3 |
4 | self.addEventListener('fetch', (event) => {
5 | if (event.request.method !== 'GET') {
6 | return;
7 | }
8 |
9 | event.respondWith(networkOrCache(event));
10 | });
11 |
12 | async function putInCache(event, response) {
13 | const cache = await caches.open('steamwebapi-cache');
14 | await cache.put(event.request, response);
15 | }
16 |
17 | async function networkOrCache(event) {
18 | try {
19 | const response = await fetch(event.request, { cache: 'no-cache' });
20 |
21 | if (response.ok) {
22 | event.waitUntil(putInCache(event, response));
23 |
24 | return response.clone();
25 | }
26 |
27 | return response;
28 | } catch (e) {
29 | const cache = await caches.open('steamwebapi-cache');
30 | const matching = await cache.match(event.request);
31 |
32 | return matching || Promise.reject(e);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/ApiParameter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ↳
5 | {{ parameter.name }}
6 | +
7 |
8 |
9 |
10 | click to change
11 | click to set
12 |
13 |
14 |
20 |
28 | ×
29 |
30 |
38 |
39 | {{ parameter.type }}
40 | No
41 |
42 |
43 | Yes
44 |
45 | {{ parameter.description }}
46 |
47 |
48 |
58 |
59 |
60 |
76 |
--------------------------------------------------------------------------------
/src/App.ts:
--------------------------------------------------------------------------------
1 | import { defineComponent, markRaw, ref } from 'vue';
2 | import interfacesJson from '../api.json';
3 | import ApiParameter from './ApiParameter.vue';
4 | import HighlightedSearchMethod from './HighlightedSearchMethod';
5 | import type { ApiInterface, ApiMethod, ApiMethodParameter, ApiServices, SidebarGroupData } from './interfaces';
6 | import { ApiSearcher } from './search';
7 |
8 | const sidebar = ref(null);
9 | const inputSearch = ref(null);
10 | const inputApiKey = ref(null);
11 | const inputAccessToken = ref(null);
12 |
13 | export default defineComponent({
14 | components: {
15 | ApiParameter,
16 | HighlightedSearchMethod,
17 | },
18 | data() {
19 | // @ts-ignore
20 | const interfaces = interfacesJson as ApiServices;
21 |
22 | const groupsMap = new Map();
23 | const groupsData = new Map(
24 | // biome-ignore format: too verbose
25 | [
26 | // Order of apps here defines the order in the sidebar
27 | [0, { name: 'Steam', icon: 'steam.jpg', open: true, methods: {} }],
28 | [730, { name: 'Counter-Strike 2', icon: 'cs2.jpg', open: true, methods: {} }],
29 | [570, { name: 'Dota 2', icon: 'dota.jpg', open: true, methods: {} }],
30 | [440, { name: 'Team Fortress 2', icon: 'tf.jpg', open: true, methods: {} }],
31 | [1422450, { name: 'Deadlock', icon: 'deadlock.jpg', open: true, methods: {} }],
32 | [620, { name: 'Portal 2', icon: 'portal2.jpg', open: false, methods: {} }],
33 | [1046930, { name: 'Dota Underlords', icon: 'underlords.jpg', open: false, methods: {} }],
34 | [583950, { name: 'Artifact Classic', icon: 'artifact.jpg', open: false, methods: {} }],
35 | [1269260, { name: 'Artifact Foundry', icon: 'artifact.jpg', open: false, methods: {} }],
36 |
37 | // Beta apps
38 | [247040, { name: 'Dota 2 Experimental', icon: 'dota.jpg', open: false, methods: {} }],
39 | [2305270, { name: 'Dota 2 Staging', icon: 'dota.jpg', open: false, methods: {} }],
40 | ],
41 | );
42 |
43 | const steamGroup = groupsData.get(0)!;
44 |
45 | for (const interfaceName in interfaces) {
46 | const interfaceAppid = interfaceName.match(/_(?[0-9]+)$/);
47 |
48 | if (interfaceAppid) {
49 | const appid = parseInt(interfaceAppid.groups!.appid, 10);
50 |
51 | groupsMap.set(interfaceName, appid);
52 |
53 | let group = groupsData.get(appid);
54 |
55 | if (!group) {
56 | group = {
57 | name: `App ${appid}`,
58 | icon: 'steam.jpg',
59 | open: false,
60 | methods: {},
61 | };
62 |
63 | groupsData.set(appid, group);
64 | }
65 |
66 | group.methods[interfaceName] = interfaces[interfaceName];
67 | } else {
68 | steamGroup.methods[interfaceName] = interfaces[interfaceName];
69 | }
70 |
71 | for (const methodName in interfaces[interfaceName]) {
72 | const method = interfaces[interfaceName][methodName];
73 |
74 | for (const parameter of method.parameters) {
75 | parameter._value = '';
76 |
77 | if (parameter.type === 'bool') {
78 | parameter.manuallyToggled = false;
79 | }
80 | }
81 | }
82 | }
83 |
84 | return {
85 | userData: {
86 | webapi_key: '',
87 | access_token: '',
88 | steamid: '',
89 | format: 'json',
90 | favorites: new Set(),
91 | },
92 | skipNextHashChange: false,
93 | keyInputType: 'password',
94 | hasValidWebApiKey: false,
95 | hasValidAccessToken: false,
96 | accessTokenExpiration: 0,
97 | accessTokenSteamId: null,
98 | accessTokenAudience: [],
99 | accessTokenVisible: false,
100 | currentFilter: '',
101 | currentInterface: '',
102 | search: markRaw(new ApiSearcher(interfaces)),
103 | interfaces,
104 | groupsMap,
105 | groupsData,
106 | };
107 | },
108 | setup() {
109 | return {
110 | sidebar,
111 | inputSearch,
112 | inputApiKey,
113 | inputAccessToken,
114 | };
115 | },
116 | watch: {
117 | 'userData.format'(value: string): void {
118 | localStorage.setItem('format', value);
119 | },
120 | 'userData.webapi_key'(value: string): void {
121 | if (this.isFieldValid('webapi_key')) {
122 | localStorage.setItem('webapi_key', value);
123 | } else {
124 | localStorage.removeItem('webapi_key');
125 | }
126 | },
127 | 'userData.access_token'(value: string): void {
128 | try {
129 | if (value.length > 2 && value[0] === '{' && value[value.length - 1] === '}') {
130 | const obj = JSON.parse(value);
131 |
132 | if (obj.data?.webapi_token) {
133 | this.userData.access_token = obj.data.webapi_token;
134 | return;
135 | }
136 | }
137 | if (/^[\w-]+\.[\w-]+\.[\w-]+$/.test(value)) {
138 | const jwt = value.split('.');
139 | const token = JSON.parse(atob(jwt[1]));
140 |
141 | this.accessTokenExpiration = token.exp * 1000;
142 | this.accessTokenAudience = token.aud;
143 | this.accessTokenSteamId = token.sub;
144 |
145 | if (token.sub && !this.userData.steamid) {
146 | this.userData.steamid = token.sub;
147 | }
148 | } else {
149 | throw new Error('Invalid token format (or empty)');
150 | }
151 | } catch (e) {
152 | console.log((e as Error).message);
153 | this.accessTokenExpiration = 0;
154 | this.accessTokenSteamId = null;
155 | this.accessTokenAudience = [];
156 | }
157 |
158 | if (this.isFieldValid('access_token')) {
159 | localStorage.setItem('access_token', value);
160 | } else {
161 | localStorage.removeItem('access_token');
162 | }
163 | },
164 | 'userData.steamid'(value: string): void {
165 | if (this.isFieldValid('steamid')) {
166 | localStorage.setItem('steamid', value);
167 |
168 | this.fillSteamidParameter();
169 | } else {
170 | localStorage.removeItem('steamid');
171 | }
172 | },
173 | currentFilter(newFilter: string, oldFilter: string): void {
174 | if (!newFilter) {
175 | this.$nextTick(this.scrollInterfaceIntoView);
176 |
177 | if (oldFilter) {
178 | this.sidebar!.scrollTop = 0;
179 | }
180 | } else {
181 | this.setInterface('');
182 |
183 | if (!oldFilter) {
184 | this.sidebar!.scrollTop = 0;
185 | }
186 | }
187 | },
188 | },
189 | mounted(): void {
190 | try {
191 | this.userData.format = localStorage.getItem('format') || 'json';
192 | this.userData.steamid = localStorage.getItem('steamid') || '';
193 | this.userData.webapi_key = localStorage.getItem('webapi_key') || '';
194 | this.userData.access_token = localStorage.getItem('access_token') || '';
195 |
196 | const favoriteStrings = JSON.parse(localStorage.getItem('favorites') || '[]');
197 |
198 | for (const favorite of favoriteStrings) {
199 | const [favoriteInterface, favoriteMethod] = favorite.split('/', 2);
200 |
201 | if (
202 | Object.hasOwn(this.interfaces, favoriteInterface) &&
203 | Object.hasOwn(this.interfaces[favoriteInterface], favoriteMethod)
204 | ) {
205 | this.interfaces[favoriteInterface][favoriteMethod].isFavorite = true;
206 |
207 | this.userData.favorites.add(favorite);
208 | }
209 | }
210 | } catch (e) {
211 | console.error(e);
212 | }
213 |
214 | if (location.hash.startsWith('#')) {
215 | this.setInterface(location.hash.substring(1), true);
216 | }
217 |
218 | window.addEventListener(
219 | 'hashchange',
220 | () => {
221 | if (this.skipNextHashChange) {
222 | this.skipNextHashChange = false;
223 | return;
224 | }
225 |
226 | this.setInterface(location.hash.substring(1));
227 | },
228 | false,
229 | );
230 |
231 | this.bindGlobalKeybind();
232 | },
233 | computed: {
234 | sidebarInterfaces(): Map {
235 | const interfaces = this.filteredInterfaces;
236 |
237 | if (this.currentFilter) {
238 | return new Map([
239 | [
240 | -1,
241 | {
242 | name: 'Search results',
243 | icon: '',
244 | open: true,
245 | methods: interfaces,
246 | },
247 | ],
248 | ]);
249 | }
250 |
251 | return this.groupsData;
252 | },
253 | filteredInterfaces(): ApiServices {
254 | if (!this.currentFilter) {
255 | return this.interfaces;
256 | }
257 |
258 | const matchedInterfaces: ApiServices = {};
259 | const hits = this.search.search(this.currentFilter);
260 |
261 | for (const match of hits) {
262 | if (!matchedInterfaces[match.interface]) {
263 | matchedInterfaces[match.interface] = {};
264 | }
265 |
266 | const method = this.interfaces[match.interface][match.method];
267 | method.highlight = match.indices;
268 | matchedInterfaces[match.interface][match.method] = method;
269 | }
270 |
271 | return matchedInterfaces;
272 | },
273 | currentInterfaceMethods(): ApiInterface {
274 | return this.interfaces[this.currentInterface];
275 | },
276 | uriDelimeterBeforeKey() {
277 | return this.hasValidAccessToken || this.hasValidWebApiKey ? '?' : '';
278 | },
279 | formatAccessTokenExpirationDate(): string {
280 | const formatter = new Intl.DateTimeFormat('en-US', {
281 | hourCycle: 'h23',
282 | dateStyle: 'medium',
283 | timeStyle: 'short',
284 | });
285 |
286 | return formatter.format(this.accessTokenExpiration);
287 | },
288 | },
289 | methods: {
290 | setInterface(interfaceAndMethod: string, setFromUrl = false): void {
291 | const split = interfaceAndMethod.split('/', 2);
292 | let currentInterface: string | null = split[0];
293 | let currentMethod: string | null = split.length > 1 ? split[1] : null;
294 |
295 | if (!Object.hasOwn(this.interfaces, currentInterface)) {
296 | currentInterface = null;
297 | currentMethod = null;
298 | } else if (currentMethod !== null && !Object.hasOwn(this.interfaces[currentInterface], currentMethod)) {
299 | currentMethod = null;
300 | }
301 |
302 | this.currentInterface = currentInterface || '';
303 |
304 | if (currentInterface) {
305 | document.title = `${currentInterface} – Steam Web API Documentation`;
306 | } else {
307 | document.title = `Steam Web API Documentation`;
308 | }
309 |
310 | // Since we won't scroll to a method, scroll to top (as there is no element with just interface id)
311 | if (document.scrollingElement && !currentMethod) {
312 | document.scrollingElement.scrollTop = 0;
313 | }
314 |
315 | if (setFromUrl) {
316 | return;
317 | }
318 |
319 | this.$nextTick(() => {
320 | this.skipNextHashChange = true;
321 |
322 | if (currentMethod) {
323 | location.hash = `#${currentInterface}/${currentMethod}`;
324 | } else if (currentInterface) {
325 | location.hash = `#${currentInterface}`;
326 | } else {
327 | location.hash = '';
328 | }
329 | });
330 | },
331 | fillSteamidParameter(): void {
332 | if (!this.userData.steamid) {
333 | return;
334 | }
335 |
336 | for (const interfaceName in this.interfaces) {
337 | for (const methodName in this.interfaces[interfaceName]) {
338 | for (const parameter of this.interfaces[interfaceName][methodName].parameters) {
339 | if (!parameter._value && parameter.name.includes('steamid')) {
340 | parameter._value = this.userData.steamid;
341 | }
342 | }
343 | }
344 | }
345 | },
346 | isFieldValid(field: string): boolean {
347 | switch (field) {
348 | case 'access_token':
349 | this.hasValidAccessToken = this.accessTokenExpiration > Date.now();
350 | return this.hasValidAccessToken;
351 |
352 | case 'webapi_key':
353 | this.hasValidWebApiKey = /^[0-9a-f]{32}$/i.test(this.userData[field]);
354 | return this.hasValidWebApiKey;
355 |
356 | case 'steamid':
357 | return /^[0-9]{17}$/.test(this.userData[field]);
358 | }
359 |
360 | return false;
361 | },
362 | renderUri(methodName: string, method: ApiMethod): string {
363 | let host = 'https://api.steampowered.com/';
364 |
365 | if (method._type === 'publisher_only') {
366 | host = 'https://partner.steam-api.com/';
367 | }
368 |
369 | return `${host}${this.currentInterface}/${methodName}/v${method.version}/`;
370 | },
371 | renderApiKey(): string {
372 | const parameters = new URLSearchParams();
373 |
374 | if (this.hasValidAccessToken) {
375 | parameters.set('access_token', this.userData.access_token);
376 | } else if (this.hasValidWebApiKey) {
377 | parameters.set('key', this.userData.webapi_key);
378 | }
379 |
380 | return parameters.toString();
381 | },
382 | renderParameters(method: ApiMethod): string {
383 | const parameters = new URLSearchParams();
384 |
385 | if (this.userData.format !== 'json') {
386 | parameters.set('format', this.userData.format);
387 | }
388 |
389 | let hasArrays = false;
390 | const inputJson = {} as any;
391 |
392 | for (const parameter of method.parameters) {
393 | if (parameter.extra) {
394 | const arr = this.getInnerParameters(parameter);
395 |
396 | if (Object.keys(arr).length > 0) {
397 | hasArrays = true;
398 |
399 | if (parameter.type?.endsWith('[]')) {
400 | const paramName = parameter.name.substring(0, parameter.name.length - 3);
401 |
402 | if (!Object.hasOwn(inputJson, paramName)) {
403 | inputJson[paramName] = [];
404 | }
405 |
406 | inputJson[paramName].push(arr);
407 | } else {
408 | inputJson[parameter.name] = arr;
409 | }
410 | } else if (parameter._value) {
411 | parameters.set(parameter.name, parameter._value);
412 | }
413 |
414 | continue;
415 | }
416 |
417 | if (!parameter._value && !parameter.manuallyToggled) {
418 | continue;
419 | }
420 |
421 | parameters.set(parameter.name, parameter._value ?? '');
422 | }
423 |
424 | if (hasArrays) {
425 | method.hasArrays = true;
426 | parameters.set('input_json', JSON.stringify(inputJson));
427 | }
428 |
429 | const str = parameters.toString();
430 |
431 | if (str.length === 0) {
432 | return '';
433 | }
434 |
435 | if (this.uriDelimeterBeforeKey) {
436 | return `&${str}`;
437 | }
438 |
439 | return `?${str}`;
440 | },
441 | getInnerParameters(parameterParent: ApiMethodParameter) {
442 | const arr = {} as any;
443 |
444 | for (const parameter of parameterParent.extra!) {
445 | if (parameter.extra) {
446 | const result = this.getInnerParameters(parameter);
447 |
448 | if (Object.keys(result).length > 0) {
449 | if (parameter.type?.endsWith('[]')) {
450 | const paramName = parameter.name.substring(0, parameter.name.length - 3);
451 |
452 | if (!Object.hasOwn(arr, paramName)) {
453 | arr[paramName] = [];
454 | }
455 |
456 | arr[paramName].push(result);
457 | } else {
458 | arr[parameter.name] = result;
459 | }
460 | }
461 |
462 | continue;
463 | }
464 |
465 | if (!parameter._value && !parameter.manuallyToggled) {
466 | continue;
467 | }
468 |
469 | if (parameter.type?.endsWith('[]')) {
470 | const paramName = parameter.name.substring(0, parameter.name.length - 3);
471 |
472 | if (!Object.hasOwn(arr, paramName)) {
473 | arr[paramName] = [];
474 | }
475 |
476 | arr[paramName].push(parameter._value || '');
477 | } else {
478 | arr[parameter.name] = parameter._value || '';
479 | }
480 | }
481 |
482 | return arr;
483 | },
484 | useThisMethod(event: SubmitEvent, method: ApiMethod): void {
485 | const form = event.target as HTMLFormElement;
486 |
487 | if (method.hasArrays) {
488 | event.preventDefault();
489 |
490 | if (method.httpmethod === 'POST') {
491 | alert('Executing POST requests with input_json is not yet supported.');
492 | return;
493 | }
494 |
495 | const url = [
496 | form.action,
497 | this.uriDelimeterBeforeKey,
498 | this.renderApiKey(),
499 | this.renderParameters(method),
500 | ].join('');
501 |
502 | try {
503 | window.open(url, '_blank');
504 | } catch {
505 | alert('Failed to open window');
506 | }
507 |
508 | return;
509 | }
510 |
511 | if (
512 | method.httpmethod === 'POST' &&
513 | !confirm(
514 | 'Executing POST requests could be potentially disastrous.\n\n' +
515 | 'Author is not responsible for any damage done.\n\n' +
516 | 'Are you sure you want to continue?',
517 | )
518 | ) {
519 | event.preventDefault();
520 | }
521 |
522 | for (const field of form.elements) {
523 | if (!(field instanceof HTMLInputElement)) {
524 | continue;
525 | }
526 |
527 | if (!field.value && !field.disabled && field.tagName === 'INPUT') {
528 | field.disabled = true;
529 |
530 | setTimeout(() => {
531 | field.disabled = false;
532 | }, 0);
533 | }
534 | }
535 | },
536 | addParamArray(method: ApiMethod, parameter: ApiMethodParameter): void {
537 | if (!parameter._counter) {
538 | parameter._counter = 1;
539 | } else {
540 | parameter._counter++;
541 | }
542 |
543 | const newParameter: ApiMethodParameter = {
544 | name: `${parameter.name.substring(0, parameter.name.length - 3)}[${parameter._counter}]`,
545 | type: parameter.type,
546 | optional: true,
547 | };
548 |
549 | if (parameter.extra) {
550 | newParameter.extra = [];
551 |
552 | for (const parameter2 of parameter.extra!) {
553 | newParameter.extra.push({
554 | name: parameter2.name,
555 | type: parameter2.type,
556 | optional: true,
557 | });
558 | }
559 | }
560 |
561 | const parameterIndex = method.parameters.findIndex((param) => param.name === parameter.name);
562 | method.parameters.splice(parameterIndex + parameter._counter, 0, newParameter);
563 | },
564 | scrollInterfaceIntoView(): void {
565 | const element = document.querySelector(`.interface-list a[href="#${this.currentInterface}"]`);
566 |
567 | if (element instanceof HTMLElement) {
568 | element.scrollIntoView();
569 | }
570 | },
571 | copyUrl(event: MouseEvent): void {
572 | const button = event.target as Element;
573 | const element = button.closest('.input-group')!.querySelector('.form-control')!;
574 |
575 | navigator.clipboard.writeText(element.textContent || '').then(
576 | () => {
577 | button.classList.add('bg-success');
578 |
579 | setTimeout(() => button.classList.remove('bg-success'), 500);
580 | },
581 | () => {
582 | // write fail
583 | },
584 | );
585 | },
586 | favoriteMethod(method: ApiMethod, methodName: string): void {
587 | const name = `${this.currentInterface}/${methodName}`;
588 |
589 | method.isFavorite = !method.isFavorite;
590 |
591 | if (method.isFavorite) {
592 | this.userData.favorites.add(name);
593 | } else {
594 | this.userData.favorites.delete(name);
595 | }
596 |
597 | localStorage.setItem('favorites', JSON.stringify([...this.userData.favorites]));
598 | },
599 | navigateSidebar(direction: number): void {
600 | const entries = Object.entries(this.filteredInterfaces);
601 | const index = entries.findIndex((x) => x[0] === this.currentInterface) + direction;
602 | const size = entries.length;
603 | const [interfaceName, methods] = entries[((index % size) + size) % size];
604 | const firstMethodName = Object.keys(methods)[0];
605 |
606 | this.setInterface(`${interfaceName}/${firstMethodName}`);
607 | this.scrollInterfaceIntoView();
608 |
609 | // This is trash, but the focus gets lost because of location.hash change
610 | this.$nextTick(() => {
611 | this.inputSearch?.focus();
612 | });
613 | },
614 | focusApiKey(): void {
615 | this.currentFilter = '';
616 | this.setInterface('');
617 |
618 | this.$nextTick(() => {
619 | const element = this.hasValidAccessToken ? this.inputAccessToken : this.inputApiKey;
620 |
621 | if (element) {
622 | element.focus();
623 | }
624 | });
625 | },
626 | onSearchInput(e: Event) {
627 | requestAnimationFrame(() => {
628 | this.currentFilter = (e.target as HTMLInputElement).value;
629 | });
630 | },
631 | bindGlobalKeybind() {
632 | document.addEventListener('keydown', (e: KeyboardEvent) => {
633 | if (e.ctrlKey || e.metaKey) {
634 | return;
635 | }
636 |
637 | const target = e.target as HTMLElement;
638 |
639 | if (['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].includes(target.tagName)) {
640 | return;
641 | }
642 |
643 | if (e.key === '/' || e.key === 's') {
644 | e.preventDefault();
645 | this.inputSearch?.focus();
646 | }
647 | });
648 | },
649 | },
650 | });
651 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 |
30 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
112 |
113 |
How to get it
114 |
115 | Access token
116 | expires on {{formatAccessTokenExpirationDate}}
117 |
118 |
131 |
132 |
133 | Preferred output format
134 |
135 | JSON
136 | VDF
137 | XML (not recommended)
138 |
139 |
140 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
Some APIs work with access tokens, if you have one you can provide it here and it will be preferred over the webapi key.
155 |
Currently entered token is for {{ aud }} with steamid {{ accessTokenSteamId }} and expires on {{ formatAccessTokenExpirationDate }}.
156 |
Here's how to get a store token:
157 |
161 |
162 |
Here's how to get a community token:
163 |
164 | Open https://steamcommunity.com/my/edit/info
165 | Run the following script: JSON.parse(application_config.dataset.loyalty_webapi_token)
(or manually copy data-loyalty_webapi_token from application_config element)
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
This is a static page that is automatically generated from GetSupportedAPIList using public and publisher keys. Additionally service methods are parsed from Steam client's protobuf files.
174 |
If you specify the web api key above, it will be stored in your browser, and will only be sent to Valve's API servers if you chose to do so.
175 |
Type a value in the value field and click the execute button to perform an API request in your browser.
176 |
177 |
This website is created and maintained by xPaw . Use any APIs listed here at your own risk. I do not know how all of them work, this page is simply a reference.
178 |
If you know of an API that is not listed here, make a pull request to the file of undocumented APIs .
179 |
Source code for this page is also available on GitHub .
180 |
181 |
182 |
183 |
184 |
185 |
186 |
The public Steamworks Web API is hosted on https://api.steampowered.com
or https://community.steam-api.com
.
187 |
188 | The public Web API host is accessible via HTTP (port 80) and HTTPS (port 443). Note that any requests using your publisher Web API key should be made over HTTPS.
189 | This service is behind Akamai's edge cache, so the actual IP addresses you will see for the name will vary based on your location and on ongoing service changes.
190 | The IPs can change rapidly and fluidly, so if your Web API calls are made through a firewall on outbound requests, read on.
191 |
192 |
193 | Steam also provides a partner-only Web API server hosted on https://partner.steam-api.com
. The intent of this service is to have higher availability than
194 | the public host; you should use this service for all requests made from your secure servers. This host has some different properties than the public host:
195 |
196 |
197 | This host is only accessible via HTTPS.
198 | This host is not behind Akamai's edge cache.
199 | Every request to this host must be made with your publisher Web API key, even requests which would ordinarily not need a key.
200 | Requests made without a valid publisher key will return a 403 error code.
201 | Requests generating 403 status codes will incur strict rate limits for the connecting IP. This is in an effort to ensure
202 | high availability. If you generate a sufficient number of requests within a certain time interval that return 403 status codes —
203 | either during testing, or by using a regular Web API key instead of your publisher key — the host will put your IP on a deny
204 | list for a while.
205 |
206 |
You should not connect to the Web API servers by IP; use the DNS name.
207 |
208 |
209 |
210 |
211 |
212 |
213 |
Similiar to the Steamworks C++ API, the Web API has been divided into multiple interfaces that contain related methods. The URI format of each API request is: https://api.steampowered.com/<interface>/<method>/<method_version>/
214 |
215 |
Steam supports returning Web API responses in multiple formats. By default, all responses are returned JSON encoded. However, each request can optionally contain a format
parameter to specify the desired response format. The following values can be passed for this parameter: xml
, json
, and vdf
.
216 |
A flexible solution should be used to parse Web API results as each method may return results in an arbitrary order.
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
225 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
226 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
227 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
228 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
229 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
230 | SOFTWARE.
231 |
232 |
233 |
234 |
235 |
253 |
254 |
255 |
256 | This page is just a reference of all the known Steam APIs, I do not know how they work. Please do not email me with questions.
257 |
258 |
262 |
263 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
--------------------------------------------------------------------------------
/src/HighlightedSearchMethod.ts:
--------------------------------------------------------------------------------
1 | import { defineComponent, h, ref, type VNode } from 'vue';
2 |
3 | export default defineComponent({
4 | props: {
5 | method: {
6 | type: String,
7 | default: '',
8 | },
9 | indices: {
10 | type: Array as () => number[],
11 | default: () => [],
12 | },
13 | },
14 | setup(props) {
15 | return () => highlightMethod(props.method, props.indices);
16 | },
17 | });
18 |
19 | function highlightMethod(text: string, indices: number[]) {
20 | // Group consecutive indices for proper highlighting spans
21 | const spans: { start: number; end: number }[] = [];
22 | let currentSpan: { start: number; end: number } | null = null;
23 |
24 | for (let i = 0; i < indices.length; i++) {
25 | const index = indices[i];
26 |
27 | if (currentSpan === null) {
28 | currentSpan = { start: index, end: index };
29 | } else if (index === currentSpan.end + 1) {
30 | currentSpan.end = index;
31 | } else {
32 | spans.push(currentSpan);
33 | currentSpan = { start: index, end: index };
34 | }
35 | }
36 |
37 | if (currentSpan !== null) {
38 | spans.push(currentSpan);
39 | }
40 |
41 | // Build the highlighted text with VNodes
42 | const nodes: (VNode | string)[] = [];
43 | let lastIndex = 0;
44 |
45 | for (const span of spans) {
46 | // Add text before the span
47 | if (span.start > lastIndex) {
48 | nodes.push(text.substring(lastIndex, span.start));
49 | }
50 |
51 | // Add highlighted span
52 | nodes.push(h('b', {}, text.substring(span.start, span.end + 1)));
53 |
54 | lastIndex = span.end + 1;
55 | }
56 |
57 | // Add remaining text
58 | if (lastIndex < text.length) {
59 | nodes.push(text.substring(lastIndex));
60 | }
61 |
62 | return nodes;
63 | }
64 |
--------------------------------------------------------------------------------
/src/documentation.ts:
--------------------------------------------------------------------------------
1 | import './index.ts';
2 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Steam Web API Documentation and Tester
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { createSSRApp } from 'vue';
2 | import App from './App.vue';
3 |
4 | if ('serviceWorker' in navigator && !('DEV_MODE' in window)) {
5 | navigator.serviceWorker.register('serviceworker.js', { scope: './' });
6 | }
7 |
8 | createSSRApp(App).mount('#app');
9 |
--------------------------------------------------------------------------------
/src/interfaces.ts:
--------------------------------------------------------------------------------
1 | export interface SidebarGroupData {
2 | name: string;
3 | icon: string;
4 | open: boolean;
5 | methods: ApiServices;
6 | }
7 |
8 | export interface ApiServices {
9 | [x: string]: ApiInterface;
10 | }
11 |
12 | export interface ApiInterface {
13 | [x: string]: ApiMethod;
14 | }
15 |
16 | export interface ApiMethod {
17 | _type: 'protobufs' | 'publisher_only' | 'undocumented' | null;
18 | httpmethod: 'GET' | 'POST' | null;
19 | version: number;
20 | description?: string;
21 | highlight?: number[];
22 | parameters: ApiMethodParameter[];
23 | isFavorite: boolean;
24 | hasArrays: boolean;
25 | }
26 |
27 | export interface ApiMethodParameter {
28 | _value?: string;
29 | _counter?: number;
30 | manuallyToggled?: boolean;
31 |
32 | name: string;
33 | type?: string;
34 | description?: string;
35 | optional: boolean;
36 | extra?: ApiMethodParameter[];
37 | }
38 |
--------------------------------------------------------------------------------
/src/search.ts:
--------------------------------------------------------------------------------
1 | import type { ApiServices } from './interfaces';
2 |
3 | export interface SearchResult {
4 | interface: string;
5 | method: string;
6 | indices: number[];
7 | score: number;
8 | }
9 |
10 | interface ScoreResult {
11 | score: number;
12 | indices: number[];
13 | }
14 |
15 | /**
16 | * A high-performance fuzzy search implementation for API methods
17 | *
18 | * Design Goals:
19 | * 1. Performance: Optimized for handling thousands of methods with minimal latency
20 | * 2. Relevance:
21 | * - Method names weighted higher than interface names
22 | * - Results sorted by calculated relevance score
23 | * - Exact substring matches prioritized over subsequence matches
24 | * - Start-of-word matches given higher scores
25 | * 3. Match Types:
26 | * - Substring matching (e.g. "tag" finds "GetTagList")
27 | * - Subsequence matching (e.g. "getcurrent" finds "GetNumberOfCurrentPlayers")
28 | * 4. Usability Features:
29 | * - Matched portions highlighted with tags
30 | * - Interface names with numeric IDs receive lower scores
31 | * - Adaptive thresholds based on query length
32 | * 5. Implementation:
33 | * - Prefix and trigram indexes for efficient candidate selection
34 | * - Pre-cached lowercase versions of strings for performance
35 | * - No regex usage for critical path operations
36 | * - Clean, maintainable code structure
37 | * - Limited to top 100 most relevant results
38 | */
39 | export class ApiSearcher {
40 | private methodsList: {
41 | interface: string;
42 | method: string;
43 | interfaceLower: string;
44 | methodLower: string;
45 | hasAppIdSuffix: boolean;
46 | }[] = [];
47 | private prefixMap: Map = new Map();
48 | private trigrams: Map = new Map();
49 | private interfacePrefixMap: Map = new Map();
50 | private interfaceTrigrams: Map = new Map();
51 |
52 | constructor(apiServices: ApiServices) {
53 | // Build flat list of methods with pre-cached lowercase versions
54 | for (const interfaceName in apiServices) {
55 | const apiInterface = apiServices[interfaceName];
56 | const interfaceLower = interfaceName.toLowerCase();
57 |
58 | // Pre-check if interface matches the app ID pattern
59 | const hasAppIdSuffix = /_(?[0-9]+)$/.test(interfaceName);
60 |
61 | for (const methodName in apiInterface) {
62 | const methodLower = methodName.toLowerCase();
63 | this.methodsList.push({
64 | interface: interfaceName,
65 | method: methodName,
66 | interfaceLower,
67 | methodLower,
68 | hasAppIdSuffix,
69 | });
70 | }
71 | }
72 |
73 | // Build indexes for both methods and interfaces
74 | this.methodsList.forEach((item, index) => {
75 | // Method indexes
76 | this.indexString(item.methodLower, index, this.prefixMap, this.trigrams);
77 |
78 | // Interface indexes
79 | this.indexString(item.interfaceLower, index, this.interfacePrefixMap, this.interfaceTrigrams);
80 | });
81 | }
82 |
83 | private indexString(
84 | str: string,
85 | index: number,
86 | prefixMap: Map,
87 | trigramMap: Map,
88 | ): void {
89 | // Add each prefix of the string to the map
90 | for (let i = 1; i <= Math.min(str.length, 4); i++) {
91 | const prefix = str.substring(0, i);
92 | let arr = prefixMap.get(prefix);
93 | if (!arr) {
94 | arr = [];
95 | prefixMap.set(prefix, arr);
96 | }
97 | arr.push(index);
98 | }
99 |
100 | // Add trigrams for substring matching acceleration
101 | if (str.length >= 3) {
102 | for (let i = 0; i <= str.length - 3; i++) {
103 | const trigram = str.substring(i, i + 3);
104 | let arr = trigramMap.get(trigram);
105 | if (!arr) {
106 | arr = [];
107 | trigramMap.set(trigram, arr);
108 | }
109 | arr.push(index);
110 | }
111 | }
112 | }
113 |
114 | public search(query: string): SearchResult[] {
115 | if (!query || query.length === 0) {
116 | return [];
117 | }
118 |
119 | const normalizedQuery = query.toLowerCase().replace(/\s/g, '');
120 |
121 | // Get method candidates
122 | const methodCandidates = this.getMethodCandidates(normalizedQuery);
123 |
124 | // Find matching interfaces
125 | const matchingInterfaces = this.getMatchingInterfaces(normalizedQuery);
126 |
127 | // Process candidates and build results
128 | const results: SearchResult[] = [];
129 | const processedItems = new Set();
130 |
131 | // First process direct method matches
132 | for (const index of methodCandidates) {
133 | const item = this.methodsList[index];
134 |
135 | // Only process if it's an actual match
136 | if (!this.hasSubstringOrSubsequence(item.methodLower, normalizedQuery)) {
137 | continue;
138 | }
139 |
140 | processedItems.add(index);
141 |
142 | const methodResult = this.getScore(item.methodLower, normalizedQuery, 3);
143 | let totalScore = methodResult.score;
144 |
145 | // Apply penalty for interfaces with app ID suffix
146 | if (item.hasAppIdSuffix) {
147 | totalScore *= 0.5;
148 | }
149 |
150 | // For very short queries, apply a stricter threshold
151 | const minScoreThreshold = normalizedQuery.length < 3 ? 0.7 : 0.3;
152 |
153 | // Apply stricter scoring for common terms
154 | if (totalScore > minScoreThreshold) {
155 | results.push({
156 | interface: item.interface,
157 | method: item.method,
158 | indices: methodResult.indices,
159 | score: totalScore,
160 | });
161 | }
162 | }
163 |
164 | // Then add methods from matching interfaces (if not already added)
165 | for (const interfaceName of matchingInterfaces) {
166 | // Find all methods belonging to this interface
167 | for (let i = 0; i < this.methodsList.length; i++) {
168 | if (this.methodsList[i].interfaceLower === interfaceName) {
169 | // Skip if already processed
170 | if (processedItems.has(i)) continue;
171 |
172 | const item = this.methodsList[i];
173 | processedItems.add(i);
174 |
175 | // Check if method itself also matches (for highlighting)
176 | const methodResult = this.hasSubstringOrSubsequence(item.methodLower, normalizedQuery)
177 | ? this.getScore(item.methodLower, normalizedQuery, 3)
178 | : { score: 0, indices: [] };
179 |
180 | // Interface matches get a modest base score
181 | let interfaceScore = 0.5;
182 |
183 | // Apply penalty for interfaces with app ID suffix
184 | if (item.hasAppIdSuffix) {
185 | interfaceScore *= 0.9;
186 | }
187 |
188 | const totalScore = interfaceScore + methodResult.score;
189 |
190 | // For very short queries, we need a higher threshold for interface matches
191 | const minScoreThreshold = normalizedQuery.length < 3 ? 0.5 : 0.25;
192 |
193 | if (totalScore > minScoreThreshold) {
194 | results.push({
195 | interface: item.interface,
196 | method: item.method,
197 | indices: methodResult.indices,
198 | score: totalScore,
199 | });
200 | }
201 | }
202 | }
203 | }
204 |
205 | // Sort by score in descending order
206 | results.sort((a, b) => b.score - a.score);
207 |
208 | return results.slice(0, 100);
209 | }
210 |
211 | private getMethodCandidates(query: string): Set {
212 | const candidateSet = new Set();
213 |
214 | // Try prefix matching for methods (fastest)
215 | this.addCandidatesByPrefix(query, this.prefixMap, candidateSet);
216 |
217 | // Return early if we have enough candidates
218 | if (candidateSet.size >= 100) {
219 | return candidateSet;
220 | }
221 |
222 | // If query is long enough, try trigram matching
223 | if (query.length >= 3) {
224 | this.addCandidatesByTrigram(query, this.trigrams, candidateSet);
225 |
226 | // Return early if we have enough candidates
227 | if (candidateSet.size >= 100) {
228 | return candidateSet;
229 | }
230 | }
231 |
232 | // If still no candidates, include methods with first letter match
233 | if (candidateSet.size === 0 && query.length > 0) {
234 | const firstChar = query[0];
235 | for (let i = 0; i < this.methodsList.length; i++) {
236 | if (this.methodsList[i].methodLower.includes(firstChar)) {
237 | candidateSet.add(i);
238 | }
239 | }
240 | }
241 |
242 | return candidateSet;
243 | }
244 |
245 | private getMatchingInterfaces(query: string): Set {
246 | const matchingInterfaces = new Set();
247 |
248 | // Find matching interfaces using the candidate approach
249 | const candidateSet = new Set();
250 |
251 | // Try prefix matching for interfaces
252 | this.addCandidatesByPrefix(query, this.interfacePrefixMap, candidateSet);
253 |
254 | // If needed, try trigram matching
255 | if (candidateSet.size < 50 && query.length >= 3) {
256 | this.addCandidatesByTrigram(query, this.interfaceTrigrams, candidateSet);
257 | }
258 |
259 | // Check candidates
260 | for (const index of candidateSet) {
261 | const interfaceName = this.methodsList[index].interfaceLower;
262 | if (this.hasSubstringOrSubsequence(interfaceName, query)) {
263 | matchingInterfaces.add(interfaceName);
264 | }
265 | }
266 |
267 | return matchingInterfaces;
268 | }
269 |
270 | private addCandidatesByPrefix(query: string, prefixMap: Map, candidateSet: Set): void {
271 | const prefix = query.substring(0, Math.min(query.length, 4));
272 | const indices = prefixMap.get(prefix);
273 |
274 | if (indices) {
275 | indices.forEach((index) => candidateSet.add(index));
276 | }
277 | }
278 |
279 | private addCandidatesByTrigram(query: string, trigramMap: Map, candidateSet: Set): void {
280 | for (let i = 0; i <= query.length - 3; i++) {
281 | const trigram = query.substring(i, i + 3);
282 | const indices = trigramMap.get(trigram);
283 |
284 | if (indices) {
285 | indices.forEach((index) => candidateSet.add(index));
286 | }
287 | }
288 | }
289 |
290 | private hasSubstringOrSubsequence(text: string, query: string): boolean {
291 | // Quick substring check
292 | if (text.includes(query)) {
293 | return true;
294 | }
295 |
296 | // Quick subsequence check
297 | let j = 0;
298 | for (let i = 0; i < text.length && j < query.length; i++) {
299 | if (text[i] === query[j]) {
300 | j++;
301 | }
302 | }
303 | return j === query.length;
304 | }
305 |
306 | private getScore(text: string, query: string, weight: number): ScoreResult {
307 | // Substring match (highest score)
308 | const substringIndex = text.indexOf(query);
309 | if (substringIndex !== -1) {
310 | // Score based on position (earlier matches get higher scores)
311 | let positionScore = 1 - substringIndex / text.length;
312 |
313 | // Bonus for matches at start of words (camelCase detection)
314 | if (
315 | substringIndex === 0 ||
316 | (text[substringIndex - 1] >= 'a' &&
317 | text[substringIndex - 1] <= 'z' &&
318 | text[substringIndex] >= 'A' &&
319 | text[substringIndex] <= 'Z')
320 | ) {
321 | positionScore += 0.5;
322 | }
323 |
324 | // Apply length-based adjustment for short queries
325 | const lengthFactor = Math.min(1, query.length / 5);
326 |
327 | const indices = Array.from({ length: query.length }, (_, i) => substringIndex + i);
328 | return {
329 | score: weight * (1.0 + positionScore * 0.5) * lengthFactor,
330 | indices,
331 | };
332 | }
333 |
334 | // Subsequence match - only compute if length is manageable and query isn't too short
335 | if (query.length >= 2 && query.length <= text.length) {
336 | return this.getSubsequenceScore(text, query, weight);
337 | }
338 |
339 | return { score: 0, indices: [] };
340 | }
341 |
342 | private getSubsequenceScore(text: string, query: string, weight: number): ScoreResult {
343 | let matchIndices: number[] = [];
344 | let i = 0;
345 | let j = 0;
346 |
347 | // Try to find a subsequence match
348 | while (i < text.length && j < query.length) {
349 | if (text[i] === query[j]) {
350 | matchIndices.push(i);
351 | j++;
352 | }
353 | i++;
354 | }
355 |
356 | // If we didn't match all query characters
357 | if (j < query.length) {
358 | return { score: 0, indices: [] };
359 | }
360 |
361 | // Calculate score based on matches and gaps
362 | const textLength = text.length;
363 |
364 | // Calculate gap penalties
365 | let gapPenalty = 0;
366 | for (let k = 1; k < matchIndices.length; k++) {
367 | const gap = matchIndices[k] - matchIndices[k - 1] - 1;
368 | gapPenalty += gap / textLength;
369 | }
370 |
371 | // Normalize gap penalty
372 | gapPenalty = matchIndices.length > 1 ? gapPenalty / (matchIndices.length - 1) : 0;
373 |
374 | // Position bonus (earlier matches are better)
375 | const positionBonus = 1 - matchIndices[0] / textLength;
376 |
377 | // Calculate density bonus (denser matches are better)
378 | const densityRange = matchIndices[matchIndices.length - 1] - matchIndices[0] + 1;
379 | const density = densityRange > 0 ? matchIndices.length / densityRange : 1;
380 |
381 | // Length factor (longer queries are better)
382 | const lengthFactor = Math.min(1, query.length / 5);
383 |
384 | const score = weight * 0.4 * (1 - gapPenalty) * (1 + 0.3 * positionBonus + 0.3 * density) * lengthFactor;
385 |
386 | return { score, indices: matchIndices };
387 | }
388 | }
389 |
--------------------------------------------------------------------------------
/src/ssr.ts:
--------------------------------------------------------------------------------
1 | import { createSSRApp } from 'vue';
2 | import { renderToString } from 'vue/server-renderer';
3 | import App from './App.vue';
4 |
5 | const app = createSSRApp(App);
6 |
7 | renderToString(app).then((html) => {
8 | console.log(html);
9 | });
10 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | @import "bootstrap/dist/css/bootstrap.css";
2 |
3 | a {
4 | color: #1f8bff;
5 | text-decoration: none;
6 | }
7 |
8 | a:hover {
9 | color: #99caff;
10 | text-decoration: underline;
11 | }
12 |
13 | code {
14 | color: #ec5fa1;
15 | }
16 |
17 | .card-body {
18 | padding-bottom: 0;
19 | }
20 |
21 | .card .table {
22 | font-size: 14px;
23 | margin-bottom: 0;
24 | }
25 |
26 | .card .table td:first-child,
27 | .card .table th:first-child {
28 | border-left: 0;
29 | }
30 |
31 | .card .table td:last-child,
32 | .card .table th:last-child {
33 | border-right: 0;
34 | }
35 |
36 | .card .btn-sm {
37 | padding-top: 0;
38 | padding-bottom: 0;
39 | line-height: 1.4;
40 | }
41 |
42 | .interface-list {
43 | padding: 0;
44 | list-style: none;
45 | }
46 |
47 | .method-list {
48 | padding: 0;
49 | list-style: none;
50 | font-size: 0.9rem;
51 | background-color: #2b3647;
52 | }
53 |
54 | .method-list a > b {
55 | color: #fff;
56 | }
57 |
58 | .interface-list li {
59 | text-overflow: ellipsis;
60 | overflow: hidden;
61 | white-space: nowrap;
62 | direction: rtl;
63 | }
64 |
65 | .header h1,
66 | .header h2,
67 | .header .separator {
68 | display: inline;
69 | font-size: 1.4rem;
70 | line-height: 38px;
71 | }
72 |
73 | .badge {
74 | transition: none;
75 | }
76 |
77 | a.badge {
78 | text-decoration: underline;
79 | }
80 |
81 | .no-select {
82 | user-select: none;
83 | }
84 |
85 | body {
86 | background-color: #161920;
87 | color: #acacac;
88 | }
89 |
90 | .header {
91 | background-color: #096295;
92 | border-bottom: 2px solid #67c1f5;
93 | color: #fff;
94 | }
95 |
96 | .search-input:focus,
97 | .search-input {
98 | border: 1px solid rgba(103, 193, 245, 0.7);
99 | background-color: #171b22;
100 | color: #fff;
101 | }
102 |
103 | .search-input:focus {
104 | box-shadow: 0 0 20px rgba(147, 211, 245, 0.5);
105 | }
106 |
107 | .search-input::placeholder {
108 | color: #888;
109 | }
110 |
111 | .header a {
112 | color: inherit;
113 | }
114 |
115 | .card {
116 | background: #22252b;
117 | color: #e5e5e5;
118 | border: 0;
119 | border-radius: 0;
120 | transition: box-shadow 0.2s;
121 | }
122 |
123 | .card:target {
124 | box-shadow: 0 0 0 5px #66c0f4;
125 | }
126 |
127 | .card-header {
128 | background: #4e5155;
129 | border: 0;
130 | top: 0;
131 | z-index: 10;
132 | }
133 |
134 | .card-header .badge {
135 | margin-right: 0.3rem;
136 | }
137 |
138 | .card-header .badge-version {
139 | margin-left: 0.3rem;
140 | }
141 |
142 | .card-inner-header {
143 | padding: 0.75rem 1.25rem;
144 | }
145 |
146 | .card-method-name {
147 | color: inherit;
148 | word-break: break-all;
149 | }
150 |
151 | .card hr {
152 | border-top: 1px solid #4e5155;
153 | }
154 |
155 | .card .table {
156 | color: #acacac;
157 | border-color: #161920;
158 | }
159 |
160 | .card .table > :not(caption) > * > * {
161 | /* bootstrap 5.3 fix */
162 | color: unset;
163 | background: unset;
164 | }
165 |
166 | .card .table .custom-control-label {
167 | color: #ddd;
168 | }
169 |
170 | .card .table th,
171 | .card .table td {
172 | border-color: #161920;
173 | }
174 |
175 | .card .table tr:nth-child(odd) td {
176 | background: #1d2027;
177 | }
178 |
179 | .attribute:hover {
180 | border-bottom-color: rgba(255, 255, 255, 0.4);
181 | }
182 |
183 | .card .btn-outline-primary,
184 | .card .form-select,
185 | .card .form-control {
186 | background-color: #232323;
187 | border: 1px solid #535354;
188 | color: #cda869;
189 | fill: currentColor;
190 | word-break: break-all;
191 | }
192 |
193 | .card .btn-outline-primary:hover {
194 | background-color: #535354;
195 | }
196 |
197 | .card .form-check-input:not(:checked) {
198 | background-color: #acacac;
199 | }
200 |
201 | .card .table .form-control {
202 | background-color: transparent;
203 | }
204 |
205 | .card .table .form-control:focus {
206 | background-color: rgba(13, 110, 253, 0.25);
207 | box-shadow: none;
208 | }
209 |
210 | .card .table .level-1 td:first-child {
211 | border-left: 10px solid #22252b;
212 | }
213 |
214 | .card .table .level-2 td:first-child {
215 | border-left: 20px solid #22252b;
216 | }
217 |
218 | .card .table .level-3 td:first-child {
219 | border-left: 30px solid #22252b;
220 | }
221 |
222 | .card .table .level-4 td:first-child {
223 | border-left: 40px solid #22252b;
224 | }
225 |
226 | .card .table .level-5 td:first-child {
227 | border-left: 50px solid #22252b;
228 | }
229 |
230 | .prefilled-key {
231 | color: #acacac;
232 | font-style: italic;
233 | }
234 |
235 | .interface-list-container + .interface-list-container {
236 | margin-top: 1rem;
237 | }
238 |
239 | .interface-group-name {
240 | margin-bottom: 0.1rem;
241 | color: #ddd;
242 | font-weight: bold;
243 | font-size: 1.2rem;
244 | }
245 |
246 | .interface-group-name::marker {
247 | color: #535354;
248 | }
249 |
250 | .interface-group-name:hover::marker,
251 | .interface-group-name:hover {
252 | color: #fff;
253 | }
254 |
255 | .interface-group-name img {
256 | border-radius: 3px;
257 | vertical-align: -5px;
258 | }
259 |
260 | .interface-list a {
261 | color: #98caff;
262 | }
263 |
264 | .interface-list a:hover {
265 | color: #fff;
266 | }
267 |
268 | .custom-control-label::before {
269 | background-color: transparent;
270 | }
271 |
272 | .no-email {
273 | color: hsl(45, 94%, 40%);
274 | background-color: hsl(46, 100%, 10%);
275 | border: 0;
276 | font-size: 13px;
277 | padding: 5px 10px;
278 | }
279 |
280 | .hidden-token,
281 | .hidden-key {
282 | font-size: 0;
283 | }
284 |
285 | .hidden-key:not(:empty):before {
286 | content: "key=is_here_but_hidden";
287 | font-size: 1rem;
288 | color: #997433;
289 | }
290 |
291 | .hidden-token:not(:empty):before {
292 | content: "access_token=is_here_but_hidden";
293 | font-size: 1rem;
294 | color: #997433;
295 | }
296 |
297 | .add-param-array {
298 | padding: 0;
299 | border-radius: 50%;
300 | height: 26px;
301 | width: 26px;
302 | line-height: 26px;
303 | float: right;
304 | border: 0;
305 | }
306 |
307 | .sidebar {
308 | scrollbar-gutter: stable;
309 | overflow-y: auto;
310 | scrollbar-width: thin;
311 | overscroll-behavior: contain;
312 | -webkit-overflow-scrolling: touch;
313 | }
314 |
315 | @media (max-width: 991px) {
316 | .sidebar {
317 | height: 200px;
318 | margin-top: 1.5rem;
319 | padding-top: 0 !important;
320 | padding-bottom: 0 !important;
321 | }
322 |
323 | .interface-list a {
324 | display: block;
325 | padding: 5px 0;
326 | }
327 |
328 | .header div[role="search"] {
329 | order: 2;
330 | margin-top: 0.5rem;
331 | }
332 |
333 | .card-method-name {
334 | display: block;
335 | }
336 |
337 | .value-column {
338 | min-width: 13em;
339 | }
340 | }
341 |
342 | @media (max-width: 575px) {
343 | .header .separator {
344 | display: none;
345 | }
346 |
347 | .header h1,
348 | .header h2 {
349 | display: block;
350 | font-size: 16px;
351 | line-height: 16px;
352 | }
353 | }
354 |
355 | @media (min-width: 992px) {
356 | html {
357 | scrollbar-gutter: stable;
358 | scroll-padding-top: 69px;
359 | }
360 |
361 | .header {
362 | height: 54px;
363 | position: sticky;
364 | top: 0;
365 | z-index: 100;
366 | }
367 |
368 | .sidebar {
369 | top: 54px;
370 | height: calc(100vh - 54px);
371 | position: sticky;
372 | }
373 |
374 | .card-header {
375 | position: sticky;
376 | top: 54px;
377 | }
378 |
379 | .value-column {
380 | width: 13em;
381 | }
382 | }
383 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@vue/tsconfig/tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "dist",
5 | "target": "esnext",
6 | "moduleResolution": "node",
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "skipLibCheck": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/update.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")"
4 |
5 | #disabled because it needs better check for valid apis (due to server errors?)
6 | #php generate_api_from_protos.php
7 |
8 | php generate_api.php
9 |
10 | git add -A
11 | git commit -a -m "Update Steam Web API reference" || exit 0
12 | git push
13 |
--------------------------------------------------------------------------------
/vue-shim.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import { defineComponent } from 'vue';
3 |
4 | const component: ReturnType;
5 | export default component;
6 | }
7 |
--------------------------------------------------------------------------------
/wrangler.jsonc:
--------------------------------------------------------------------------------
1 | {
2 | "name": "steamapi",
3 | "compatibility_date": "2025-04-01",
4 | "assets": {
5 | "directory": "./public/",
6 | "not_found_handling": "404-page"
7 | }
8 | }
--------------------------------------------------------------------------------