@utilix-tech/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +199 -0
  3. package/dist/api-8aZtWhSj.d.cts +308 -0
  4. package/dist/api-8aZtWhSj.d.ts +308 -0
  5. package/dist/chunk-2CJSLYWI.js +520 -0
  6. package/dist/chunk-3BAHSW4C.js +1385 -0
  7. package/dist/chunk-6YPV2AB5.js +1246 -0
  8. package/dist/chunk-BPVAB4P2.js +1126 -0
  9. package/dist/chunk-FL53T24A.js +257 -0
  10. package/dist/chunk-L6KCTHUW.js +1086 -0
  11. package/dist/chunk-MLKGABMK.js +7 -0
  12. package/dist/chunk-ROTPLW7T.js +265 -0
  13. package/dist/chunk-TSAGO3XP.js +1253 -0
  14. package/dist/chunk-UC656APA.js +1080 -0
  15. package/dist/chunk-W4UBLYFU.js +1219 -0
  16. package/dist/chunk-XST6X3HT.js +896 -0
  17. package/dist/chunk-XXYZLLHI.js +2227 -0
  18. package/dist/chunk-ZKL2VX2G.js +2215 -0
  19. package/dist/chunk-ZPQZEIXP.js +685 -0
  20. package/dist/code-QNrdLIR3.d.cts +327 -0
  21. package/dist/code-QNrdLIR3.d.ts +327 -0
  22. package/dist/color-tPwZCr9H.d.cts +229 -0
  23. package/dist/color-tPwZCr9H.d.ts +229 -0
  24. package/dist/css-Cf7AMGM-.d.cts +318 -0
  25. package/dist/css-Cf7AMGM-.d.ts +318 -0
  26. package/dist/data-rMjWNiOJ.d.cts +215 -0
  27. package/dist/data-rMjWNiOJ.d.ts +215 -0
  28. package/dist/encoding-7gmq-vkV.d.cts +108 -0
  29. package/dist/encoding-7gmq-vkV.d.ts +108 -0
  30. package/dist/generators-BGtRGpJZ.d.cts +118 -0
  31. package/dist/generators-BGtRGpJZ.d.ts +118 -0
  32. package/dist/hashing-CnetQFD_.d.cts +76 -0
  33. package/dist/hashing-CnetQFD_.d.ts +76 -0
  34. package/dist/index.cjs +15466 -0
  35. package/dist/index.d.cts +18 -0
  36. package/dist/index.d.ts +18 -0
  37. package/dist/index.js +20 -0
  38. package/dist/json-BjSoIS1h.d.cts +198 -0
  39. package/dist/json-BjSoIS1h.d.ts +198 -0
  40. package/dist/misc-DcVBManm.d.cts +201 -0
  41. package/dist/misc-DcVBManm.d.ts +201 -0
  42. package/dist/network-CNtmrDeN.d.cts +170 -0
  43. package/dist/network-CNtmrDeN.d.ts +170 -0
  44. package/dist/text-DqAjPtQ0.d.cts +319 -0
  45. package/dist/text-DqAjPtQ0.d.ts +319 -0
  46. package/dist/time-DbT8fjaF.d.cts +145 -0
  47. package/dist/time-DbT8fjaF.d.ts +145 -0
  48. package/dist/tools/api.cjs +1216 -0
  49. package/dist/tools/api.d.cts +1 -0
  50. package/dist/tools/api.d.ts +1 -0
  51. package/dist/tools/api.js +2 -0
  52. package/dist/tools/code.cjs +2212 -0
  53. package/dist/tools/code.d.cts +1 -0
  54. package/dist/tools/code.d.ts +1 -0
  55. package/dist/tools/code.js +2 -0
  56. package/dist/tools/color.cjs +1122 -0
  57. package/dist/tools/color.d.cts +1 -0
  58. package/dist/tools/color.d.ts +1 -0
  59. package/dist/tools/color.js +2 -0
  60. package/dist/tools/css.cjs +1242 -0
  61. package/dist/tools/css.d.cts +1 -0
  62. package/dist/tools/css.d.ts +1 -0
  63. package/dist/tools/css.js +2 -0
  64. package/dist/tools/data.cjs +1097 -0
  65. package/dist/tools/data.d.cts +1 -0
  66. package/dist/tools/data.d.ts +1 -0
  67. package/dist/tools/data.js +2 -0
  68. package/dist/tools/encoding.cjs +261 -0
  69. package/dist/tools/encoding.d.cts +1 -0
  70. package/dist/tools/encoding.d.ts +1 -0
  71. package/dist/tools/encoding.js +2 -0
  72. package/dist/tools/generators.cjs +521 -0
  73. package/dist/tools/generators.d.cts +1 -0
  74. package/dist/tools/generators.d.ts +1 -0
  75. package/dist/tools/generators.js +2 -0
  76. package/dist/tools/hashing.cjs +259 -0
  77. package/dist/tools/hashing.d.cts +1 -0
  78. package/dist/tools/hashing.d.ts +1 -0
  79. package/dist/tools/hashing.js +2 -0
  80. package/dist/tools/json.cjs +1270 -0
  81. package/dist/tools/json.d.cts +1 -0
  82. package/dist/tools/json.d.ts +1 -0
  83. package/dist/tools/json.js +2 -0
  84. package/dist/tools/misc.cjs +1082 -0
  85. package/dist/tools/misc.d.cts +1 -0
  86. package/dist/tools/misc.d.ts +1 -0
  87. package/dist/tools/misc.js +2 -0
  88. package/dist/tools/network.cjs +1381 -0
  89. package/dist/tools/network.d.cts +1 -0
  90. package/dist/tools/network.d.ts +1 -0
  91. package/dist/tools/network.js +2 -0
  92. package/dist/tools/text.cjs +2224 -0
  93. package/dist/tools/text.d.cts +1 -0
  94. package/dist/tools/text.d.ts +1 -0
  95. package/dist/tools/text.js +2 -0
  96. package/dist/tools/time.cjs +681 -0
  97. package/dist/tools/time.d.cts +1 -0
  98. package/dist/tools/time.d.ts +1 -0
  99. package/dist/tools/time.js +2 -0
  100. package/dist/tools/units.cjs +892 -0
  101. package/dist/tools/units.d.cts +1 -0
  102. package/dist/tools/units.d.ts +1 -0
  103. package/dist/tools/units.js +2 -0
  104. package/dist/units-6lwDYBvX.d.cts +302 -0
  105. package/dist/units-6lwDYBvX.d.ts +302 -0
  106. package/package.json +148 -0
@@ -0,0 +1,1219 @@
1
+ import { __export } from './chunk-MLKGABMK.js';
2
+ import { createHmac } from 'crypto';
3
+
4
+ // src/tools/api.ts
5
+ var api_exports = {};
6
+ __export(api_exports, {
7
+ COMMON_HEADERS: () => COMMON_HEADERS,
8
+ COMMON_PRESETS: () => COMMON_PRESETS,
9
+ CORS_COMMON_HEADERS: () => CORS_COMMON_HEADERS,
10
+ DEFAULT_CORS_CONFIG: () => DEFAULT_CORS_CONFIG,
11
+ DIRECTIVE_DESCRIPTIONS: () => DIRECTIVE_DESCRIPTIONS,
12
+ HTTP_METHODS: () => HTTP_METHODS,
13
+ SUPPORTED_LANGUAGES: () => SUPPORTED_LANGUAGES,
14
+ addParam: () => addParam,
15
+ base64urlDecode: () => base64urlDecode,
16
+ base64urlEncode: () => base64urlEncode,
17
+ buildCurl: () => buildCurl,
18
+ buildCurlMultiline: () => buildCurlMultiline,
19
+ buildUrl: () => buildUrl,
20
+ convertToCode: () => convertToCode,
21
+ decodeJwt: () => decodeJwt,
22
+ decodeUrlComponent: () => decodeUrlComponent,
23
+ detectFormat: () => detectFormat,
24
+ encodeUrlComponent: () => encodeUrlComponent,
25
+ extractJsonPaths: () => extractJsonPaths,
26
+ formatJwtJson: () => formatJwtJson,
27
+ formatResponse: () => formatResponse,
28
+ generateCors: () => generateCors,
29
+ generateCspHeader: () => generateCspHeader,
30
+ generateFullHeader: () => generateFullHeader,
31
+ generateMetaHtml: () => generateMetaHtml,
32
+ getParam: () => getParam,
33
+ getStats: () => getStats,
34
+ isValidUrl: () => isValidUrl,
35
+ normalizeUrl: () => normalizeUrl,
36
+ parseCspHeader: () => parseCspHeader,
37
+ parseCurl: () => parseCurl,
38
+ parseCurlCommand: () => parseCurlCommand,
39
+ parseMetaTags: () => parseMetaTags,
40
+ parseUrl: () => parseUrl,
41
+ removeParam: () => removeParam,
42
+ signJwt: () => signJwt,
43
+ validateCorsConfig: () => validateCorsConfig,
44
+ validateCspConfig: () => validateCspConfig,
45
+ validateOgTags: () => validateOgTags
46
+ });
47
+ function escapeShell(value) {
48
+ return `'${value.replace(/'/g, "'\\''")}'`;
49
+ }
50
+ function buildCurl(config) {
51
+ const parts = ["curl"];
52
+ if (config.verbose) parts.push("-v");
53
+ if (config.silent) parts.push("-s");
54
+ if (config.followRedirects) parts.push("-L");
55
+ if (config.timeout !== void 0) parts.push(`--max-time ${config.timeout}`);
56
+ if (config.method !== "GET") {
57
+ parts.push(`-X ${config.method}`);
58
+ }
59
+ for (const header of config.headers) {
60
+ if (header.key.trim()) {
61
+ parts.push(`-H ${escapeShell(`${header.key}: ${header.value}`)}`);
62
+ }
63
+ }
64
+ if (config.body !== void 0 && config.body !== "") {
65
+ parts.push(`-d ${escapeShell(config.body)}`);
66
+ }
67
+ parts.push(escapeShell(config.url));
68
+ return parts.join(" ");
69
+ }
70
+ function buildCurlMultiline(config) {
71
+ const parts = ["curl"];
72
+ if (config.verbose) parts.push("-v");
73
+ if (config.silent) parts.push("-s");
74
+ if (config.followRedirects) parts.push("-L");
75
+ if (config.timeout !== void 0) parts.push(`--max-time ${config.timeout}`);
76
+ if (config.method !== "GET") {
77
+ parts.push(`-X ${config.method}`);
78
+ }
79
+ for (const header of config.headers) {
80
+ if (header.key.trim()) {
81
+ parts.push(`-H ${escapeShell(`${header.key}: ${header.value}`)}`);
82
+ }
83
+ }
84
+ if (config.body !== void 0 && config.body !== "") {
85
+ parts.push(`-d ${escapeShell(config.body)}`);
86
+ }
87
+ parts.push(escapeShell(config.url));
88
+ return parts.join(" \\\n ");
89
+ }
90
+ function unquoteCurl(s) {
91
+ if (s.startsWith("'") && s.endsWith("'") || s.startsWith('"') && s.endsWith('"')) {
92
+ return s.slice(1, -1).replace(/\\'/g, "'").replace(/\\"/g, '"');
93
+ }
94
+ return s;
95
+ }
96
+ function parseCurl(command) {
97
+ const trimmed = command.trim().replace(/\\\n\s*/g, " ");
98
+ if (!trimmed.startsWith("curl ") && trimmed !== "curl") {
99
+ return { error: 'Command must start with "curl"' };
100
+ }
101
+ const config = {
102
+ method: "GET",
103
+ url: "",
104
+ headers: []
105
+ };
106
+ const tokenRe = /(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|\S)+/g;
107
+ const tokens = trimmed.match(tokenRe) || [];
108
+ let i = 1;
109
+ while (i < tokens.length) {
110
+ const token = tokens[i];
111
+ if (token === "-v" || token === "--verbose") {
112
+ config.verbose = true;
113
+ i++;
114
+ } else if (token === "-s" || token === "--silent") {
115
+ config.silent = true;
116
+ i++;
117
+ } else if (token === "-L" || token === "--location") {
118
+ config.followRedirects = true;
119
+ i++;
120
+ } else if (token === "--max-time" || token === "-m") {
121
+ i++;
122
+ if (i < tokens.length) {
123
+ config.timeout = parseFloat(tokens[i]);
124
+ i++;
125
+ }
126
+ } else if (token === "-X" || token === "--request") {
127
+ i++;
128
+ if (i < tokens.length) {
129
+ config.method = tokens[i].toUpperCase();
130
+ i++;
131
+ }
132
+ } else if (token === "-H" || token === "--header") {
133
+ i++;
134
+ if (i < tokens.length) {
135
+ const raw = unquoteCurl(tokens[i]);
136
+ const colonIdx = raw.indexOf(":");
137
+ if (colonIdx !== -1) {
138
+ config.headers.push({
139
+ key: raw.slice(0, colonIdx).trim(),
140
+ value: raw.slice(colonIdx + 1).trim()
141
+ });
142
+ }
143
+ i++;
144
+ }
145
+ } else if (token === "-d" || token === "--data" || token === "--data-raw") {
146
+ i++;
147
+ if (i < tokens.length) {
148
+ config.body = unquoteCurl(tokens[i]);
149
+ if (config.method === "GET") config.method = "POST";
150
+ i++;
151
+ }
152
+ } else if (!token.startsWith("-")) {
153
+ config.url = unquoteCurl(token);
154
+ i++;
155
+ } else {
156
+ i++;
157
+ }
158
+ }
159
+ if (!config.url) {
160
+ return { error: "No URL found in command" };
161
+ }
162
+ return config;
163
+ }
164
+ var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
165
+ var COMMON_HEADERS = [
166
+ { label: "JSON Content-Type", key: "Content-Type", value: "application/json" },
167
+ { label: "Form Content-Type", key: "Content-Type", value: "application/x-www-form-urlencoded" },
168
+ { label: "Accept JSON", key: "Accept", value: "application/json" },
169
+ { label: "Accept Any", key: "Accept", value: "*/*" },
170
+ { label: "Bearer Auth", key: "Authorization", value: "Bearer <token>" },
171
+ { label: "Basic Auth", key: "Authorization", value: "Basic <base64>" },
172
+ { label: "User Agent", key: "User-Agent", value: "Mozilla/5.0" },
173
+ { label: "Cache Control", key: "Cache-Control", value: "no-cache" },
174
+ { label: "CORS Origin", key: "Origin", value: "https://example.com" },
175
+ { label: "API Key Header", key: "X-API-Key", value: "<api-key>" }
176
+ ];
177
+ var SUPPORTED_LANGUAGES = [
178
+ { value: "fetch", label: "JavaScript (fetch)" },
179
+ { value: "axios", label: "JavaScript (axios)" },
180
+ { value: "python-requests", label: "Python (requests)" },
181
+ { value: "go-http", label: "Go (net/http)" },
182
+ { value: "php-curl", label: "PHP (cURL)" },
183
+ { value: "ruby-net-http", label: "Ruby (Net::HTTP)" }
184
+ ];
185
+ function tokenizeCurlCommand(curl) {
186
+ const tokens = [];
187
+ let i = 0;
188
+ const s = curl.trim();
189
+ while (i < s.length) {
190
+ while (i < s.length && /\s/.test(s[i])) i++;
191
+ if (i >= s.length) break;
192
+ if (s[i] === "'" || s[i] === '"') {
193
+ const quote = s[i];
194
+ i++;
195
+ let token = "";
196
+ while (i < s.length && s[i] !== quote) {
197
+ if (s[i] === "\\" && i + 1 < s.length) {
198
+ i++;
199
+ token += s[i];
200
+ } else {
201
+ token += s[i];
202
+ }
203
+ i++;
204
+ }
205
+ i++;
206
+ tokens.push(token);
207
+ } else {
208
+ let token = "";
209
+ while (i < s.length && !/\s/.test(s[i])) {
210
+ token += s[i];
211
+ i++;
212
+ }
213
+ tokens.push(token);
214
+ }
215
+ }
216
+ return tokens;
217
+ }
218
+ function parseCurlCommand(curl) {
219
+ const trimmed = curl.trim();
220
+ if (!trimmed.startsWith("curl")) {
221
+ return { error: 'Input must start with "curl"' };
222
+ }
223
+ const tokens = tokenizeCurlCommand(trimmed);
224
+ if (tokens[0] !== "curl") return { error: 'Input must start with "curl"' };
225
+ let method = "GET";
226
+ let url = "";
227
+ const headers = {};
228
+ let body;
229
+ let followRedirects = false;
230
+ let i = 1;
231
+ while (i < tokens.length) {
232
+ const token = tokens[i];
233
+ if (token === "-X" || token === "--request") {
234
+ i++;
235
+ method = tokens[i]?.toUpperCase() ?? "GET";
236
+ } else if (token === "-H" || token === "--header") {
237
+ i++;
238
+ const header = tokens[i] ?? "";
239
+ const colonIdx = header.indexOf(":");
240
+ if (colonIdx === -1) return { error: `Invalid header: ${header}` };
241
+ const key = header.slice(0, colonIdx).trim();
242
+ const val = header.slice(colonIdx + 1).trim();
243
+ headers[key] = val;
244
+ } else if (token === "-d" || token === "--data" || token === "--data-raw" || token === "--data-binary") {
245
+ i++;
246
+ body = tokens[i];
247
+ if (method === "GET") method = "POST";
248
+ } else if (token === "-L" || token === "--location") {
249
+ followRedirects = true;
250
+ } else if (token === "--compressed") ; else if (!token.startsWith("-")) {
251
+ url = token;
252
+ }
253
+ i++;
254
+ }
255
+ if (!url) return { error: "No URL found in curl command" };
256
+ const result = { method, url, headers };
257
+ if (body !== void 0) result.body = body;
258
+ if (followRedirects) result.followRedirects = true;
259
+ return result;
260
+ }
261
+ function generateFetch(cmd) {
262
+ const hasBody = cmd.body !== void 0;
263
+ const hasHeaders = Object.keys(cmd.headers).length > 0;
264
+ const options = [];
265
+ if (cmd.method !== "GET") options.push(` method: '${cmd.method}'`);
266
+ if (hasHeaders) {
267
+ const entries = Object.entries(cmd.headers).map(([k, v]) => ` '${k}': '${v}'`).join(",\n");
268
+ options.push(` headers: {
269
+ ${entries}
270
+ }`);
271
+ }
272
+ if (hasBody) options.push(` body: ${JSON.stringify(cmd.body)}`);
273
+ if (options.length === 0) {
274
+ return `const response = await fetch('${cmd.url}');
275
+ const data = await response.json();
276
+ console.log(data);`;
277
+ }
278
+ return `const response = await fetch('${cmd.url}', {
279
+ ${options.join(",\n")}
280
+ });
281
+ const data = await response.json();
282
+ console.log(data);`;
283
+ }
284
+ function generateAxios(cmd) {
285
+ const method = cmd.method.toLowerCase();
286
+ const hasHeaders = Object.keys(cmd.headers).length > 0;
287
+ const lines = ["import axios from 'axios';", ""];
288
+ const configParts = [];
289
+ if (hasHeaders) {
290
+ const entries = Object.entries(cmd.headers).map(([k, v]) => ` '${k}': '${v}'`).join(",\n");
291
+ configParts.push(` headers: {
292
+ ${entries}
293
+ }`);
294
+ }
295
+ if (cmd.body !== void 0 && (method === "post" || method === "put" || method === "patch")) {
296
+ const config = configParts.length > 0 ? `,
297
+ {
298
+ ${configParts.join(",\n")}
299
+ }` : "";
300
+ lines.push(`const response = await axios.${method}('${cmd.url}', ${JSON.stringify(cmd.body)}${config});`);
301
+ } else if (configParts.length > 0) {
302
+ lines.push(`const response = await axios.${method}('${cmd.url}', {
303
+ ${configParts.join(",\n")}
304
+ });`);
305
+ } else {
306
+ lines.push(`const response = await axios.${method}('${cmd.url}');`);
307
+ }
308
+ lines.push("console.log(response.data);");
309
+ return lines.join("\n");
310
+ }
311
+ function generatePythonRequests(cmd) {
312
+ const lines = ["import requests", ""];
313
+ const method = cmd.method.toLowerCase();
314
+ const hasHeaders = Object.keys(cmd.headers).length > 0;
315
+ const args = [`'${cmd.url}'`];
316
+ if (hasHeaders) {
317
+ const entries = Object.entries(cmd.headers).map(([k, v]) => ` '${k}': '${v}'`).join(",\n");
318
+ lines.push(`headers = {
319
+ ${entries}
320
+ }`);
321
+ args.push("headers=headers");
322
+ }
323
+ if (cmd.body !== void 0) {
324
+ lines.push(`data = ${JSON.stringify(cmd.body)}`);
325
+ args.push("data=data");
326
+ }
327
+ if (cmd.followRedirects !== void 0) args.push(`allow_redirects=${cmd.followRedirects ? "True" : "False"}`);
328
+ if (hasHeaders || cmd.body !== void 0) lines.push("");
329
+ lines.push(`response = requests.${method}(${args.join(", ")})`);
330
+ lines.push("print(response.json())");
331
+ return lines.join("\n");
332
+ }
333
+ function generateGoHttp(cmd) {
334
+ const lines = [
335
+ "package main",
336
+ "",
337
+ "import (",
338
+ ' "fmt"',
339
+ ' "io"',
340
+ ' "net/http"'
341
+ ];
342
+ if (cmd.body !== void 0) lines.splice(5, 0, ' "strings"');
343
+ lines.push(")", "");
344
+ lines.push("func main() {");
345
+ if (cmd.body !== void 0) {
346
+ lines.push(` body := strings.NewReader(${JSON.stringify(cmd.body)})`);
347
+ lines.push(` req, err := http.NewRequest("${cmd.method}", "${cmd.url}", body)`);
348
+ } else {
349
+ lines.push(` req, err := http.NewRequest("${cmd.method}", "${cmd.url}", nil)`);
350
+ }
351
+ lines.push(" if err != nil {");
352
+ lines.push(" panic(err)");
353
+ lines.push(" }");
354
+ for (const [k, v] of Object.entries(cmd.headers)) {
355
+ lines.push(` req.Header.Set("${k}", "${v}")`);
356
+ }
357
+ lines.push("");
358
+ lines.push(" client := &http.Client{}");
359
+ lines.push(" resp, err := client.Do(req)");
360
+ lines.push(" if err != nil {");
361
+ lines.push(" panic(err)");
362
+ lines.push(" }");
363
+ lines.push(" defer resp.Body.Close()");
364
+ lines.push(" body2, _ := io.ReadAll(resp.Body)");
365
+ lines.push(" fmt.Println(string(body2))");
366
+ lines.push("}");
367
+ return lines.join("\n");
368
+ }
369
+ function generatePhpCurl(cmd) {
370
+ const lines = ["<?php", ""];
371
+ lines.push("$ch = curl_init();");
372
+ lines.push(`curl_setopt($ch, CURLOPT_URL, '${cmd.url}');`);
373
+ lines.push("curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);");
374
+ if (cmd.method !== "GET") {
375
+ lines.push(`curl_setopt($ch, CURLOPT_CUSTOMREQUEST, '${cmd.method}');`);
376
+ }
377
+ if (cmd.body !== void 0) {
378
+ lines.push(`curl_setopt($ch, CURLOPT_POSTFIELDS, ${JSON.stringify(cmd.body)});`);
379
+ }
380
+ if (Object.keys(cmd.headers).length > 0) {
381
+ const entries = Object.entries(cmd.headers).map(([k, v]) => ` '${k}: ${v}'`).join(",\n");
382
+ lines.push(`curl_setopt($ch, CURLOPT_HTTPHEADER, [
383
+ ${entries}
384
+ ]);`);
385
+ }
386
+ if (cmd.followRedirects) lines.push("curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);");
387
+ lines.push("");
388
+ lines.push("$response = curl_exec($ch);");
389
+ lines.push("curl_close($ch);");
390
+ lines.push("echo $response;");
391
+ return lines.join("\n");
392
+ }
393
+ function generateRubyNetHttp(cmd) {
394
+ const lines = [
395
+ "require 'net/http'",
396
+ "require 'uri'",
397
+ "require 'json'",
398
+ ""
399
+ ];
400
+ lines.push(`uri = URI.parse('${cmd.url}')`);
401
+ lines.push("http = Net::HTTP.new(uri.host, uri.port)");
402
+ lines.push("http.use_ssl = uri.scheme == 'https'");
403
+ lines.push("");
404
+ const methodClass = cmd.method.charAt(0).toUpperCase() + cmd.method.slice(1).toLowerCase();
405
+ lines.push(`request = Net::HTTP::${methodClass}.new(uri.request_uri)`);
406
+ for (const [k, v] of Object.entries(cmd.headers)) {
407
+ lines.push(`request['${k}'] = '${v}'`);
408
+ }
409
+ if (cmd.body !== void 0) {
410
+ lines.push(`request.body = ${JSON.stringify(cmd.body)}`);
411
+ }
412
+ lines.push("");
413
+ lines.push("response = http.request(request)");
414
+ lines.push("puts response.body");
415
+ return lines.join("\n");
416
+ }
417
+ function convertToCode(cmd, target) {
418
+ switch (target) {
419
+ case "fetch":
420
+ return generateFetch(cmd);
421
+ case "axios":
422
+ return generateAxios(cmd);
423
+ case "python-requests":
424
+ return generatePythonRequests(cmd);
425
+ case "go-http":
426
+ return generateGoHttp(cmd);
427
+ case "php-curl":
428
+ return generatePhpCurl(cmd);
429
+ case "ruby-net-http":
430
+ return generateRubyNetHttp(cmd);
431
+ }
432
+ }
433
+ function b64urlDecodeStr(str) {
434
+ const base64 = str.replace(/-/g, "+").replace(/_/g, "/");
435
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
436
+ return Buffer.from(padded, "base64").toString("utf8");
437
+ }
438
+ function decodeSegment(segment) {
439
+ const json = b64urlDecodeStr(segment);
440
+ return JSON.parse(json);
441
+ }
442
+ function decodeJwt(token) {
443
+ const trimmed = token.trim();
444
+ if (!trimmed) return { ok: false, error: "No token provided" };
445
+ const parts = trimmed.split(".");
446
+ if (parts.length !== 3) {
447
+ return { ok: false, error: `Expected 3 parts (header.payload.signature), got ${parts.length}` };
448
+ }
449
+ const [rawHeader, rawPayload, rawSig] = parts;
450
+ let header;
451
+ try {
452
+ header = decodeSegment(rawHeader);
453
+ } catch {
454
+ return { ok: false, error: "Failed to decode header \u2014 not valid base64url JSON" };
455
+ }
456
+ let payload;
457
+ try {
458
+ payload = decodeSegment(rawPayload);
459
+ } catch {
460
+ return { ok: false, error: "Failed to decode payload \u2014 not valid base64url JSON" };
461
+ }
462
+ const algorithm = typeof header.alg === "string" ? header.alg : "unknown";
463
+ const now = Math.floor(Date.now() / 1e3);
464
+ const exp = typeof payload.exp === "number" ? payload.exp : null;
465
+ const iat = typeof payload.iat === "number" ? payload.iat : null;
466
+ let expiry;
467
+ if (exp === null) {
468
+ expiry = "no-exp";
469
+ } else if (exp < now) {
470
+ expiry = "expired";
471
+ } else {
472
+ expiry = "valid";
473
+ }
474
+ return {
475
+ ok: true,
476
+ header: { raw: rawHeader, decoded: header },
477
+ payload: { raw: rawPayload, decoded: payload },
478
+ signature: rawSig,
479
+ algorithm,
480
+ expiry,
481
+ expiresAt: exp !== null ? new Date(exp * 1e3) : null,
482
+ issuedAt: iat !== null ? new Date(iat * 1e3) : null
483
+ };
484
+ }
485
+ function formatJwtJson(obj) {
486
+ return JSON.stringify(obj, null, 2);
487
+ }
488
+ var ALG_TO_NODE_HASH = {
489
+ HS256: "sha256",
490
+ HS384: "sha384",
491
+ HS512: "sha512"
492
+ };
493
+ function base64urlEncode(str) {
494
+ return Buffer.from(str, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
495
+ }
496
+ function base64urlDecode(str) {
497
+ const base64 = str.replace(/-/g, "+").replace(/_/g, "/");
498
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
499
+ return Buffer.from(padded, "base64").toString("utf8");
500
+ }
501
+ async function signJwt(options) {
502
+ const { secret, payload, expiresInSeconds } = options;
503
+ const algorithm = options.algorithm ?? "HS256";
504
+ if (!secret) {
505
+ throw new Error("Secret is required for JWT signing");
506
+ }
507
+ const hashName = ALG_TO_NODE_HASH[algorithm];
508
+ const header = { alg: algorithm, typ: "JWT" };
509
+ const claims = { ...payload };
510
+ if (!("iat" in claims)) {
511
+ claims.iat = 0;
512
+ }
513
+ if (expiresInSeconds !== void 0) {
514
+ const iat = typeof claims.iat === "number" ? claims.iat : 0;
515
+ claims.exp = iat + expiresInSeconds;
516
+ }
517
+ const encodedHeader = base64urlEncode(JSON.stringify(header));
518
+ const encodedPayload = base64urlEncode(JSON.stringify(claims));
519
+ const signingInput = `${encodedHeader}.${encodedPayload}`;
520
+ const signatureBuffer = createHmac(hashName, secret).update(signingInput, "utf8").digest();
521
+ const encodedSignature = signatureBuffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
522
+ return `${signingInput}.${encodedSignature}`;
523
+ }
524
+ var CORS_COMMON_HEADERS = [
525
+ "Accept",
526
+ "Accept-Encoding",
527
+ "Accept-Language",
528
+ "Authorization",
529
+ "Cache-Control",
530
+ "Content-Length",
531
+ "Content-Type",
532
+ "Cookie",
533
+ "DNT",
534
+ "Host",
535
+ "If-Modified-Since",
536
+ "Keep-Alive",
537
+ "Origin",
538
+ "Pragma",
539
+ "Referer",
540
+ "TE",
541
+ "Upgrade-Insecure-Requests",
542
+ "User-Agent",
543
+ "Via",
544
+ "X-CustomHeader",
545
+ "X-Forwarded-For",
546
+ "X-Forwarded-Host",
547
+ "X-Forwarded-Proto",
548
+ "X-Requested-With"
549
+ ];
550
+ var DEFAULT_CORS_CONFIG = {
551
+ allowedOrigins: ["*"],
552
+ allowedMethods: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"],
553
+ allowedHeaders: ["Content-Type", "Authorization"],
554
+ exposedHeaders: [],
555
+ allowCredentials: false,
556
+ maxAge: 86400
557
+ };
558
+ function validateCorsConfig(config) {
559
+ const warnings = [];
560
+ if (config.allowCredentials && config.allowedOrigins.includes("*")) {
561
+ warnings.push(
562
+ 'allowCredentials cannot be true when allowedOrigins includes "*". Browsers will reject this configuration.'
563
+ );
564
+ }
565
+ if (config.allowedOrigins.length === 0) {
566
+ warnings.push("No allowed origins specified. All cross-origin requests will be blocked.");
567
+ }
568
+ if (config.allowedMethods.length === 0) {
569
+ warnings.push("No allowed methods specified.");
570
+ }
571
+ if (config.maxAge < 0) {
572
+ warnings.push("maxAge should be a non-negative number.");
573
+ }
574
+ if (config.maxAge > 86400) {
575
+ warnings.push("maxAge exceeds 86400 seconds (24 hours). Some browsers cap this value.");
576
+ }
577
+ for (const origin of config.allowedOrigins) {
578
+ if (origin !== "*" && !origin.startsWith("http://") && !origin.startsWith("https://")) {
579
+ warnings.push(`Origin "${origin}" should start with http:// or https://.`);
580
+ }
581
+ }
582
+ const valid = warnings.every(
583
+ (w) => !w.includes("cannot be true when allowedOrigins includes")
584
+ );
585
+ return { valid, warnings };
586
+ }
587
+ function generateCors(config) {
588
+ const headers = {};
589
+ const originValue = config.allowedOrigins.includes("*") ? "*" : config.allowedOrigins.join(", ");
590
+ headers["Access-Control-Allow-Origin"] = originValue;
591
+ if (config.allowedMethods.length > 0) {
592
+ headers["Access-Control-Allow-Methods"] = config.allowedMethods.join(", ");
593
+ }
594
+ if (config.allowedHeaders.length > 0) {
595
+ headers["Access-Control-Allow-Headers"] = config.allowedHeaders.join(", ");
596
+ }
597
+ if (config.exposedHeaders.length > 0) {
598
+ headers["Access-Control-Expose-Headers"] = config.exposedHeaders.join(", ");
599
+ }
600
+ if (config.allowCredentials) {
601
+ headers["Access-Control-Allow-Credentials"] = "true";
602
+ }
603
+ if (config.maxAge > 0) {
604
+ headers["Access-Control-Max-Age"] = String(config.maxAge);
605
+ }
606
+ const nginxLines = [];
607
+ nginxLines.push("# Add inside your location block");
608
+ nginxLines.push(`add_header 'Access-Control-Allow-Origin' '${originValue}';`);
609
+ nginxLines.push(`add_header 'Access-Control-Allow-Methods' '${config.allowedMethods.join(", ")}';`);
610
+ if (config.allowedHeaders.length > 0) {
611
+ nginxLines.push(`add_header 'Access-Control-Allow-Headers' '${config.allowedHeaders.join(", ")}';`);
612
+ }
613
+ if (config.exposedHeaders.length > 0) {
614
+ nginxLines.push(`add_header 'Access-Control-Expose-Headers' '${config.exposedHeaders.join(", ")}';`);
615
+ }
616
+ if (config.allowCredentials) {
617
+ nginxLines.push(`add_header 'Access-Control-Allow-Credentials' 'true';`);
618
+ }
619
+ if (config.maxAge > 0) {
620
+ nginxLines.push(`add_header 'Access-Control-Max-Age' '${config.maxAge}';`);
621
+ }
622
+ nginxLines.push("");
623
+ nginxLines.push("if ($request_method = OPTIONS) {");
624
+ nginxLines.push(" return 204;");
625
+ nginxLines.push("}");
626
+ const nginxConfig = nginxLines.join("\n");
627
+ const originsArray = config.allowedOrigins.includes("*") ? "'*'" : config.allowedOrigins.map((o) => `'${o}'`).join(", ");
628
+ const expressLines = [];
629
+ expressLines.push('const cors = require("cors");');
630
+ expressLines.push("");
631
+ expressLines.push("app.use(cors({");
632
+ expressLines.push(` origin: ${config.allowedOrigins.includes("*") ? "'*'" : `[${originsArray}]`},`);
633
+ expressLines.push(` methods: [${config.allowedMethods.map((m) => `'${m}'`).join(", ")}],`);
634
+ if (config.allowedHeaders.length > 0) {
635
+ expressLines.push(` allowedHeaders: [${config.allowedHeaders.map((h) => `'${h}'`).join(", ")}],`);
636
+ }
637
+ if (config.exposedHeaders.length > 0) {
638
+ expressLines.push(` exposedHeaders: [${config.exposedHeaders.map((h) => `'${h}'`).join(", ")}],`);
639
+ }
640
+ expressLines.push(` credentials: ${config.allowCredentials},`);
641
+ if (config.maxAge > 0) {
642
+ expressLines.push(` maxAge: ${config.maxAge},`);
643
+ }
644
+ expressLines.push("}));");
645
+ const expressCode = expressLines.join("\n");
646
+ const apacheLines = [];
647
+ apacheLines.push("# Add to .htaccess or Apache config");
648
+ apacheLines.push("<IfModule mod_headers.c>");
649
+ if (config.allowedOrigins.includes("*")) {
650
+ apacheLines.push(` Header set Access-Control-Allow-Origin "*"`);
651
+ } else {
652
+ for (const origin of config.allowedOrigins) {
653
+ apacheLines.push(` Header set Access-Control-Allow-Origin "${origin}"`);
654
+ }
655
+ }
656
+ apacheLines.push(` Header set Access-Control-Allow-Methods "${config.allowedMethods.join(", ")}"`);
657
+ if (config.allowedHeaders.length > 0) {
658
+ apacheLines.push(` Header set Access-Control-Allow-Headers "${config.allowedHeaders.join(", ")}"`);
659
+ }
660
+ if (config.exposedHeaders.length > 0) {
661
+ apacheLines.push(` Header set Access-Control-Expose-Headers "${config.exposedHeaders.join(", ")}"`);
662
+ }
663
+ if (config.allowCredentials) {
664
+ apacheLines.push(` Header set Access-Control-Allow-Credentials "true"`);
665
+ }
666
+ if (config.maxAge > 0) {
667
+ apacheLines.push(` Header set Access-Control-Max-Age "${config.maxAge}"`);
668
+ }
669
+ apacheLines.push("</IfModule>");
670
+ const apacheConfig = apacheLines.join("\n");
671
+ return { headers, nginxConfig, expressCode, apacheConfig };
672
+ }
673
+ var NO_SOURCE_DIRECTIVES = ["upgrade-insecure-requests", "block-all-mixed-content"];
674
+ function generateCspHeader(config) {
675
+ const parts = [];
676
+ for (const d of config.directives) {
677
+ if (NO_SOURCE_DIRECTIVES.includes(d.directive) || d.sources.length === 0) {
678
+ parts.push(d.directive);
679
+ } else {
680
+ parts.push([d.directive, ...d.sources].join(" "));
681
+ }
682
+ }
683
+ if (config.reportUri) {
684
+ parts.push(`report-uri ${config.reportUri}`);
685
+ }
686
+ return parts.join("; ");
687
+ }
688
+ function generateFullHeader(config) {
689
+ return {
690
+ name: config.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy",
691
+ value: generateCspHeader(config)
692
+ };
693
+ }
694
+ function parseCspHeader(headerValue) {
695
+ if (!headerValue || !headerValue.trim()) {
696
+ return { error: "Empty header" };
697
+ }
698
+ const directives = [];
699
+ let reportUri;
700
+ const parts = headerValue.split(";").map((p) => p.trim()).filter(Boolean);
701
+ for (const part of parts) {
702
+ const tokens = part.split(/\s+/).filter(Boolean);
703
+ if (tokens.length === 0) continue;
704
+ const directive = tokens[0].toLowerCase();
705
+ const sources = tokens.slice(1);
706
+ if (directive === "report-uri") {
707
+ reportUri = sources[0];
708
+ } else {
709
+ directives.push({ directive, sources });
710
+ }
711
+ }
712
+ const config = { directives };
713
+ if (reportUri) {
714
+ config.reportUri = reportUri;
715
+ }
716
+ return config;
717
+ }
718
+ function validateCspConfig(config) {
719
+ const warnings = [];
720
+ const hasDefaultSrc = config.directives.some((d) => d.directive === "default-src");
721
+ if (!hasDefaultSrc) {
722
+ warnings.push("No 'default-src' directive present. Browsers will not apply a fallback policy.");
723
+ }
724
+ for (const d of config.directives) {
725
+ if (d.sources.includes("'unsafe-inline'") && d.sources.includes("'strict-dynamic'")) {
726
+ warnings.push(`Directive '${d.directive}' has both 'unsafe-inline' and 'strict-dynamic'. 'unsafe-inline' is ignored when 'strict-dynamic' is present.`);
727
+ }
728
+ if (d.sources.includes("'unsafe-eval'")) {
729
+ warnings.push(`Directive '${d.directive}' uses 'unsafe-eval', which allows dynamic code execution and reduces security.`);
730
+ }
731
+ }
732
+ return { warnings };
733
+ }
734
+ var DIRECTIVE_DESCRIPTIONS = {
735
+ "default-src": "Fallback for fetch directives that are not explicitly set.",
736
+ "script-src": "Controls valid sources for JavaScript.",
737
+ "style-src": "Controls valid sources for stylesheets.",
738
+ "img-src": "Controls valid sources for images.",
739
+ "font-src": "Controls valid sources for fonts loaded via @font-face.",
740
+ "connect-src": "Restricts URLs for fetch, XHR, WebSocket, and EventSource connections.",
741
+ "media-src": "Controls valid sources for audio and video elements.",
742
+ "object-src": "Controls valid sources for plugin elements like <object> and <embed>.",
743
+ "frame-src": "Controls valid sources for nested browsing contexts like <frame> and <iframe>.",
744
+ "worker-src": "Controls valid sources for Worker, SharedWorker, and ServiceWorker scripts.",
745
+ "manifest-src": "Controls valid sources for application manifest files.",
746
+ "prefetch-src": "Controls valid sources for prefetch and prerender requests.",
747
+ "form-action": "Restricts URLs that can be used as form submission targets.",
748
+ "frame-ancestors": "Specifies valid parents that may embed the page using <frame>, <iframe>, etc.",
749
+ "base-uri": "Restricts URLs that can be used in the <base> element.",
750
+ "upgrade-insecure-requests": "Instructs the browser to treat all HTTP URLs as HTTPS.",
751
+ "block-all-mixed-content": "Prevents loading any assets using HTTP when the page is loaded over HTTPS.",
752
+ "report-uri": "Specifies a URL where the browser sends reports about policy violations.",
753
+ "report-to": "Specifies a reporting group for sending violation reports via the Reporting API."
754
+ };
755
+ var COMMON_PRESETS = [
756
+ {
757
+ name: "Strict",
758
+ description: "Maximum security. Only allows same-origin resources with no inline scripts or styles.",
759
+ config: {
760
+ directives: [
761
+ { directive: "default-src", sources: ["'none'"] },
762
+ { directive: "script-src", sources: ["'self'"] },
763
+ { directive: "style-src", sources: ["'self'"] },
764
+ { directive: "img-src", sources: ["'self'", "data:"] },
765
+ { directive: "font-src", sources: ["'self'"] },
766
+ { directive: "connect-src", sources: ["'self'"] }
767
+ ]
768
+ }
769
+ },
770
+ {
771
+ name: "Moderate",
772
+ description: "Balanced security allowing same-origin resources and inline styles/scripts.",
773
+ config: {
774
+ directives: [
775
+ { directive: "default-src", sources: ["'self'"] },
776
+ { directive: "script-src", sources: ["'self'", "'unsafe-inline'"] },
777
+ { directive: "style-src", sources: ["'self'", "'unsafe-inline'"] },
778
+ { directive: "img-src", sources: ["'self'", "data:", "https:"] }
779
+ ]
780
+ }
781
+ },
782
+ {
783
+ name: "Permissive",
784
+ description: "Very permissive policy suitable for development. Not recommended for production.",
785
+ config: {
786
+ directives: [
787
+ { directive: "default-src", sources: ["*"] },
788
+ { directive: "script-src", sources: ["*", "'unsafe-inline'", "'unsafe-eval'"] },
789
+ { directive: "style-src", sources: ["*", "'unsafe-inline'"] }
790
+ ]
791
+ }
792
+ },
793
+ {
794
+ name: "SPA",
795
+ description: "Suitable for single-page applications with API calls, fonts, and blob URLs.",
796
+ config: {
797
+ directives: [
798
+ { directive: "default-src", sources: ["'self'"] },
799
+ { directive: "script-src", sources: ["'self'", "'unsafe-inline'"] },
800
+ { directive: "style-src", sources: ["'self'", "'unsafe-inline'"] },
801
+ { directive: "img-src", sources: ["'self'", "data:", "blob:"] },
802
+ { directive: "connect-src", sources: ["'self'", "https:"] },
803
+ { directive: "font-src", sources: ["'self'", "data:"] }
804
+ ]
805
+ }
806
+ }
807
+ ];
808
+ function detectFormat(content) {
809
+ const trimmed = content.trim();
810
+ if (!trimmed) return "unknown";
811
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
812
+ try {
813
+ JSON.parse(trimmed);
814
+ return "json";
815
+ } catch {
816
+ }
817
+ }
818
+ if (trimmed.startsWith("<") && trimmed.includes(">")) {
819
+ const lower = trimmed.toLowerCase();
820
+ if (lower.startsWith("<!doctype html") || lower.startsWith("<html") || lower.includes("<html") || lower.includes("<body")) {
821
+ return "html";
822
+ }
823
+ return "xml";
824
+ }
825
+ const lines = trimmed.split("\n");
826
+ if (lines.length >= 2) {
827
+ const firstLine = lines[0];
828
+ const allLinesHaveCommas = lines.every((line) => line.includes(","));
829
+ const firstLineIsHeaders = /^[a-zA-Z0-9_,\s"']+$/.test(firstLine) && firstLine.includes(",");
830
+ if (allLinesHaveCommas && firstLineIsHeaders) {
831
+ return "csv";
832
+ }
833
+ }
834
+ return "text";
835
+ }
836
+ function prettifyXml(xml) {
837
+ const tokens = xml.replace(/>\s*</g, "><").split(/(<[^>]+>)/);
838
+ let indent = 0;
839
+ const result = [];
840
+ for (const token of tokens) {
841
+ if (!token.trim()) continue;
842
+ if (/^<\//.test(token)) {
843
+ indent = Math.max(0, indent - 1);
844
+ result.push(" ".repeat(indent) + token);
845
+ } else if (/^<[^?!][^>]*[^/]>$/.test(token)) {
846
+ result.push(" ".repeat(indent) + token);
847
+ indent++;
848
+ } else if (/^<[^?!][^>]*\/>$/.test(token)) {
849
+ result.push(" ".repeat(indent) + token);
850
+ } else if (/^<[?!]/.test(token)) {
851
+ result.push(" ".repeat(indent) + token);
852
+ } else {
853
+ result.push(" ".repeat(indent) + token);
854
+ }
855
+ }
856
+ return result.join("\n");
857
+ }
858
+ function formatResponse(content, hint) {
859
+ const size = Buffer.byteLength(content, "utf8");
860
+ const lines = content.split("\n").length;
861
+ const format = hint ?? detectFormat(content);
862
+ if (format === "json") {
863
+ try {
864
+ const parsed = JSON.parse(content.trim());
865
+ const formatted = JSON.stringify(parsed, null, 2);
866
+ const minified = JSON.stringify(parsed);
867
+ return { format, formatted, minified, size, lines, valid: true };
868
+ } catch (e) {
869
+ return { format, formatted: content, size, lines, valid: false, error: e.message };
870
+ }
871
+ }
872
+ if (format === "xml") {
873
+ try {
874
+ const formatted = prettifyXml(content.trim());
875
+ return { format, formatted, size, lines, valid: true };
876
+ } catch (e) {
877
+ return { format, formatted: content, size, lines, valid: false, error: e.message };
878
+ }
879
+ }
880
+ if (format === "html") {
881
+ try {
882
+ const formatted = prettifyXml(content.trim());
883
+ return { format, formatted, size, lines, valid: true };
884
+ } catch (e) {
885
+ return { format, formatted: content, size, lines, valid: false, error: e.message };
886
+ }
887
+ }
888
+ return { format, formatted: content, size, lines, valid: true };
889
+ }
890
+ function getStats(content) {
891
+ const size = Buffer.byteLength(content, "utf8");
892
+ const lines = content.split("\n").length;
893
+ const format = detectFormat(content);
894
+ if (format === "json") {
895
+ try {
896
+ const parsed = JSON.parse(content.trim());
897
+ const jsonKeys = Array.isArray(parsed) ? parsed.length : Object.keys(parsed).length;
898
+ return { size, lines, format, jsonKeys };
899
+ } catch {
900
+ return { size, lines, format };
901
+ }
902
+ }
903
+ if (format === "xml") {
904
+ const xmlElements = (content.match(/<[a-zA-Z][^/!>][^>]*>/g) ?? []).length;
905
+ return { size, lines, format, xmlElements };
906
+ }
907
+ return { size, lines, format };
908
+ }
909
+ function extractJsonPaths(content) {
910
+ try {
911
+ const parsed = JSON.parse(content.trim());
912
+ if (Array.isArray(parsed)) {
913
+ return parsed.map((_, i) => `[${i}]`);
914
+ }
915
+ if (typeof parsed === "object" && parsed !== null) {
916
+ const paths = [];
917
+ for (const key of Object.keys(parsed)) {
918
+ paths.push(key);
919
+ const value = parsed[key];
920
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
921
+ for (const subKey of Object.keys(value)) {
922
+ paths.push(`${key}.${subKey}`);
923
+ }
924
+ }
925
+ }
926
+ return paths;
927
+ }
928
+ return [];
929
+ } catch {
930
+ return [];
931
+ }
932
+ }
933
+ function parseUrl(url) {
934
+ const trimmed = url.trim();
935
+ if (!trimmed) {
936
+ return {
937
+ protocol: "",
938
+ hostname: "",
939
+ pathname: "",
940
+ search: "",
941
+ hash: "",
942
+ params: [],
943
+ isValid: false,
944
+ isAbsolute: false
945
+ };
946
+ }
947
+ try {
948
+ const parsed = new URL(trimmed);
949
+ const params = [];
950
+ parsed.searchParams.forEach((value, key) => {
951
+ params.push({ key, value });
952
+ });
953
+ return {
954
+ protocol: parsed.protocol.replace(":", ""),
955
+ username: parsed.username || void 0,
956
+ password: parsed.password || void 0,
957
+ hostname: parsed.hostname,
958
+ port: parsed.port || void 0,
959
+ pathname: parsed.pathname,
960
+ search: parsed.search,
961
+ hash: parsed.hash,
962
+ params,
963
+ isValid: true,
964
+ isAbsolute: true
965
+ };
966
+ } catch {
967
+ if (trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("../")) {
968
+ const [pathAndQuery, hash] = trimmed.split("#");
969
+ const [pathname, queryString] = pathAndQuery.split("?");
970
+ const search = queryString ? `?${queryString}` : "";
971
+ const params = [];
972
+ if (queryString) {
973
+ for (const part of queryString.split("&")) {
974
+ const [k, v] = part.split("=");
975
+ if (k) params.push({ key: decodeURIComponent(k), value: decodeURIComponent(v ?? "") });
976
+ }
977
+ }
978
+ return {
979
+ protocol: "",
980
+ hostname: "",
981
+ pathname,
982
+ search,
983
+ hash: hash ? `#${hash}` : "",
984
+ params,
985
+ isValid: true,
986
+ isAbsolute: false
987
+ };
988
+ }
989
+ return {
990
+ protocol: "",
991
+ hostname: trimmed,
992
+ pathname: "",
993
+ search: "",
994
+ hash: "",
995
+ params: [],
996
+ isValid: false,
997
+ isAbsolute: false
998
+ };
999
+ }
1000
+ }
1001
+ function buildUrl(parsed) {
1002
+ const protocol = parsed.protocol || "https";
1003
+ const host = parsed.hostname;
1004
+ const port = parsed.port ? `:${parsed.port}` : "";
1005
+ const auth = parsed.username ? `${encodeURIComponent(parsed.username)}${parsed.password ? `:${encodeURIComponent(parsed.password)}` : ""}@` : "";
1006
+ const pathname = parsed.pathname || "/";
1007
+ const params = parsed.params || [];
1008
+ let search = "";
1009
+ if (params.length > 0) {
1010
+ const sp = new URLSearchParams();
1011
+ for (const { key, value } of params) {
1012
+ sp.append(key, value);
1013
+ }
1014
+ search = `?${sp.toString()}`;
1015
+ } else if (parsed.search && parsed.search !== "?") {
1016
+ search = parsed.search.startsWith("?") ? parsed.search : `?${parsed.search}`;
1017
+ }
1018
+ const hash = parsed.hash || "";
1019
+ return `${protocol}://${auth}${host}${port}${pathname}${search}${hash}`;
1020
+ }
1021
+ function addParam(url, key, value) {
1022
+ try {
1023
+ const parsed = new URL(url);
1024
+ parsed.searchParams.append(key, value);
1025
+ return parsed.toString();
1026
+ } catch {
1027
+ const sep = url.includes("?") ? "&" : "?";
1028
+ return `${url}${sep}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
1029
+ }
1030
+ }
1031
+ function removeParam(url, key) {
1032
+ try {
1033
+ const parsed = new URL(url);
1034
+ parsed.searchParams.delete(key);
1035
+ return parsed.toString();
1036
+ } catch {
1037
+ return url;
1038
+ }
1039
+ }
1040
+ function getParam(url, key) {
1041
+ try {
1042
+ const parsed = new URL(url);
1043
+ return parsed.searchParams.get(key);
1044
+ } catch {
1045
+ return null;
1046
+ }
1047
+ }
1048
+ function encodeUrlComponent(value) {
1049
+ return encodeURIComponent(value);
1050
+ }
1051
+ function decodeUrlComponent(value) {
1052
+ try {
1053
+ return decodeURIComponent(value);
1054
+ } catch {
1055
+ return value;
1056
+ }
1057
+ }
1058
+ function isValidUrl(url) {
1059
+ try {
1060
+ new URL(url.trim());
1061
+ return true;
1062
+ } catch {
1063
+ return false;
1064
+ }
1065
+ }
1066
+ function normalizeUrl(url) {
1067
+ try {
1068
+ const parsed = new URL(url.trim());
1069
+ parsed.hostname = parsed.hostname.toLowerCase();
1070
+ const keys = Array.from(parsed.searchParams.keys()).sort();
1071
+ const values = keys.map((k) => [k, parsed.searchParams.get(k)]);
1072
+ parsed.search = "";
1073
+ const sp = new URLSearchParams();
1074
+ for (const [k, v] of values) {
1075
+ sp.append(k, v);
1076
+ }
1077
+ if (values.length > 0) parsed.search = sp.toString();
1078
+ let result = parsed.toString();
1079
+ if (result.endsWith("/") && parsed.pathname === "/") {
1080
+ result = result.replace(/\/$/, "");
1081
+ }
1082
+ return result;
1083
+ } catch {
1084
+ return url;
1085
+ }
1086
+ }
1087
+ function getMetaContent(html, property) {
1088
+ const escaped = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1089
+ const patterns = [
1090
+ new RegExp(
1091
+ `<meta[^>]+property=["']${escaped}["'][^>]+content=["']([^"']*)["']`,
1092
+ "i"
1093
+ ),
1094
+ new RegExp(
1095
+ `<meta[^>]+content=["']([^"']*)["'][^>]+property=["']${escaped}["']`,
1096
+ "i"
1097
+ ),
1098
+ new RegExp(
1099
+ `<meta[^>]+name=["']${escaped}["'][^>]+content=["']([^"']*)["']`,
1100
+ "i"
1101
+ ),
1102
+ new RegExp(
1103
+ `<meta[^>]+content=["']([^"']*)["'][^>]+name=["']${escaped}["']`,
1104
+ "i"
1105
+ )
1106
+ ];
1107
+ for (const pattern of patterns) {
1108
+ const match = html.match(pattern);
1109
+ if (match) return match[1];
1110
+ }
1111
+ return void 0;
1112
+ }
1113
+ function parseMetaTags(html) {
1114
+ const titleMatch = html.match(/<title[^>]*>([^<]*)<\/title>/i);
1115
+ const canonicalMatch = html.match(
1116
+ /<link[^>]+rel=["']canonical["'][^>]+href=["']([^"']*)["']/i
1117
+ ) || html.match(
1118
+ /<link[^>]+href=["']([^"']*)["'][^>]+rel=["']canonical["']/i
1119
+ );
1120
+ const charsetMatch = html.match(/<meta[^>]+charset=["']([^"']*)["']/i) || html.match(/<meta[^>]+charset=([^\s>]*)/i);
1121
+ return {
1122
+ og: {
1123
+ title: getMetaContent(html, "og:title"),
1124
+ description: getMetaContent(html, "og:description"),
1125
+ image: getMetaContent(html, "og:image"),
1126
+ imageAlt: getMetaContent(html, "og:image:alt"),
1127
+ imageWidth: getMetaContent(html, "og:image:width"),
1128
+ imageHeight: getMetaContent(html, "og:image:height"),
1129
+ url: getMetaContent(html, "og:url"),
1130
+ type: getMetaContent(html, "og:type"),
1131
+ siteName: getMetaContent(html, "og:site_name"),
1132
+ locale: getMetaContent(html, "og:locale")
1133
+ },
1134
+ twitter: {
1135
+ card: getMetaContent(html, "twitter:card"),
1136
+ site: getMetaContent(html, "twitter:site"),
1137
+ creator: getMetaContent(html, "twitter:creator"),
1138
+ title: getMetaContent(html, "twitter:title"),
1139
+ description: getMetaContent(html, "twitter:description"),
1140
+ image: getMetaContent(html, "twitter:image")
1141
+ },
1142
+ standard: {
1143
+ title: titleMatch ? titleMatch[1].trim() : void 0,
1144
+ description: getMetaContent(html, "description"),
1145
+ keywords: getMetaContent(html, "keywords"),
1146
+ canonical: canonicalMatch ? canonicalMatch[1] : void 0,
1147
+ robots: getMetaContent(html, "robots"),
1148
+ viewport: getMetaContent(html, "viewport"),
1149
+ charset: charsetMatch ? charsetMatch[1] : void 0
1150
+ }
1151
+ };
1152
+ }
1153
+ function validateOgTags(tags) {
1154
+ const warnings = [];
1155
+ const missing = [];
1156
+ const required = ["title", "description", "image", "url", "type"];
1157
+ for (const field of required) {
1158
+ if (!tags[field]) {
1159
+ missing.push(`og:${field}`);
1160
+ }
1161
+ }
1162
+ if (tags.image && !/^https?:\/\//i.test(tags.image)) {
1163
+ warnings.push("og:image should be an absolute URL");
1164
+ }
1165
+ if (tags.url && !/^https?:\/\//i.test(tags.url)) {
1166
+ warnings.push("og:url should be an absolute URL");
1167
+ }
1168
+ if (tags.title && tags.title.length > 95) {
1169
+ warnings.push("og:title is longer than 95 characters and may be truncated");
1170
+ }
1171
+ if (tags.description && tags.description.length > 300) {
1172
+ warnings.push("og:description is longer than 300 characters and may be truncated");
1173
+ }
1174
+ if (tags.type && !["website", "article", "video.movie", "video.episode", "music.song", "music.album", "book", "profile"].includes(tags.type)) {
1175
+ warnings.push(`og:type value "${tags.type}" is not a standard type`);
1176
+ }
1177
+ return { warnings, missing };
1178
+ }
1179
+ function generateMetaHtml(tags) {
1180
+ const lines = [];
1181
+ const ogMap = {
1182
+ title: "og:title",
1183
+ description: "og:description",
1184
+ image: "og:image",
1185
+ imageAlt: "og:image:alt",
1186
+ imageWidth: "og:image:width",
1187
+ imageHeight: "og:image:height",
1188
+ url: "og:url",
1189
+ type: "og:type",
1190
+ siteName: "og:site_name",
1191
+ locale: "og:locale"
1192
+ };
1193
+ const twitterMap = {
1194
+ card: "twitter:card",
1195
+ site: "twitter:site",
1196
+ creator: "twitter:creator"
1197
+ };
1198
+ for (const [key, property] of Object.entries(ogMap)) {
1199
+ const value = tags[key];
1200
+ if (value) {
1201
+ lines.push(`<meta property="${property}" content="${value}" />`);
1202
+ }
1203
+ }
1204
+ for (const [key, name] of Object.entries(twitterMap)) {
1205
+ const value = tags[key];
1206
+ if (value) {
1207
+ lines.push(`<meta name="${name}" content="${value}" />`);
1208
+ }
1209
+ }
1210
+ if (tags.title && !tags.title) {
1211
+ lines.push(`<meta name="twitter:title" content="${tags.title}" />`);
1212
+ }
1213
+ if (tags.description && !tags.description) {
1214
+ lines.push(`<meta name="twitter:description" content="${tags.description}" />`);
1215
+ }
1216
+ return lines.join("\n");
1217
+ }
1218
+
1219
+ export { COMMON_HEADERS, COMMON_PRESETS, CORS_COMMON_HEADERS, DEFAULT_CORS_CONFIG, DIRECTIVE_DESCRIPTIONS, HTTP_METHODS, SUPPORTED_LANGUAGES, addParam, api_exports, base64urlDecode, base64urlEncode, buildCurl, buildCurlMultiline, buildUrl, convertToCode, decodeJwt, decodeUrlComponent, detectFormat, encodeUrlComponent, extractJsonPaths, formatJwtJson, formatResponse, generateCors, generateCspHeader, generateFullHeader, generateMetaHtml, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags };