@utilix-tech/sdk 0.4.0 → 0.5.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.
- package/README.md +16 -6
- package/dist/{api-8aZtWhSj.d.cts → api-Xl7OzIgq.d.cts} +35 -2
- package/dist/{api-8aZtWhSj.d.ts → api-Xl7OzIgq.d.ts} +35 -2
- package/dist/{chunk-HFRTZE7T.js → chunk-Q3B3YWOA.js} +51 -1
- package/dist/chunk-WWKPLYEP.js +277 -0
- package/dist/index.cjs +194 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/media-D-K5aZnq.d.cts +53 -0
- package/dist/media-D-K5aZnq.d.ts +53 -0
- package/dist/tools/api.cjs +50 -0
- package/dist/tools/api.d.cts +1 -1
- package/dist/tools/api.d.ts +1 -1
- package/dist/tools/api.js +1 -1
- package/dist/tools/media.cjs +143 -0
- package/dist/tools/media.d.cts +1 -1
- package/dist/tools/media.d.ts +1 -1
- package/dist/tools/media.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-N7C52YGL.js +0 -134
- package/dist/media-DF2cx3pK.d.cts +0 -28
- package/dist/media-DF2cx3pK.d.ts +0 -28
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/sdk
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**523 developer utility functions for Node.js: runs locally, no API key required.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
6
6
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
@@ -285,7 +285,7 @@ parseHar(har);
|
|
|
285
285
|
### `/api`: cURL, JWT, CORS, HTTP
|
|
286
286
|
|
|
287
287
|
```ts
|
|
288
|
-
import { buildCurl, parseCurlCommand, decodeJwt, signJwt,
|
|
288
|
+
import { buildCurl, parseCurlCommand, decodeJwt, signJwt, parseJwks,
|
|
289
289
|
generateCors, generateCspHeader } from "@utilix-tech/sdk/api";
|
|
290
290
|
|
|
291
291
|
buildCurl({
|
|
@@ -305,6 +305,10 @@ parseCurlCommand('curl -X GET https://api.example.com -H "Authorization: Bearer
|
|
|
305
305
|
decodeJwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...");
|
|
306
306
|
// { header: {...}, payload: {...}, isExpired: false, expiresIn: "2h" }
|
|
307
307
|
|
|
308
|
+
// JWKS: parse a key set (or a single bare JWK) — inspection only, no verification
|
|
309
|
+
parseJwks('{"keys":[{"kty":"RSA","use":"sig","kid":"1","n":"...","e":"AQAB"}]}');
|
|
310
|
+
// { ok: true, keys: [{ kty: "RSA", kid: "1", keySize: 2048, ... }], count: 1, duplicateKids: [] }
|
|
311
|
+
|
|
308
312
|
// Generate CORS headers
|
|
309
313
|
generateCors({ origins: ["https://myapp.com"], methods: ["GET", "POST"] });
|
|
310
314
|
|
|
@@ -412,16 +416,22 @@ analyzeString("café"); // { length: 4, codePoints: [...], ... }
|
|
|
412
416
|
|
|
413
417
|
---
|
|
414
418
|
|
|
415
|
-
### `/media`: Image Header Parsing
|
|
419
|
+
### `/media`: Image Header Parsing & PDF Metadata
|
|
416
420
|
|
|
417
421
|
```ts
|
|
418
|
-
import { readImageInfo } from "@utilix-tech/sdk/media";
|
|
422
|
+
import { readImageInfo, readPdfMetadata } from "@utilix-tech/sdk/media";
|
|
419
423
|
|
|
420
424
|
// Reads format, dimensions, bit depth, and alpha channel straight from
|
|
421
425
|
// file bytes: no decoding, no canvas, no image library.
|
|
422
426
|
const bytes = await fs.promises.readFile("photo.png");
|
|
423
427
|
readImageInfo(new Uint8Array(bytes));
|
|
424
428
|
// { format: "png", width: 1920, height: 1080, bitDepth: 8, colorType: "rgba", hasAlpha: true }
|
|
429
|
+
|
|
430
|
+
// Reads title, author, dates, page count, and encryption flag from a PDF's
|
|
431
|
+
// trailer/Info dictionary: no pdf.js or other PDF library required.
|
|
432
|
+
const pdfBytes = await fs.promises.readFile("report.pdf");
|
|
433
|
+
readPdfMetadata(new Uint8Array(pdfBytes));
|
|
434
|
+
// { version: "1.7", pageCount: 12, title: "Q3 Report", author: "Jane Doe", ... }
|
|
425
435
|
```
|
|
426
436
|
|
|
427
437
|
Supports PNG, JPEG, GIF, WebP, and BMP.
|
|
@@ -441,13 +451,13 @@ Supports PNG, JPEG, GIF, WebP, and BMP.
|
|
|
441
451
|
| `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
|
|
442
452
|
| `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format |
|
|
443
453
|
| `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs, HAR file parsing |
|
|
444
|
-
| `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, CORS headers, CSP header |
|
|
454
|
+
| `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header |
|
|
445
455
|
| `@utilix-tech/sdk/code` | SQL format/minify, HTML format/minify, regex tester, GraphQL format |
|
|
446
456
|
| `@utilix-tech/sdk/color` | Hex/RGB/HSL/HSV/CMYK convert, palette generation, contrast check |
|
|
447
457
|
| `@utilix-tech/sdk/css` | CSS gradient, box-shadow, border-radius, keyframe animation generators |
|
|
448
458
|
| `@utilix-tech/sdk/misc` | SVG optimize/sanitize, file size format, Unicode inspector |
|
|
449
459
|
| `@utilix-tech/sdk/ai_agent` | Token estimate/trim, chunk text, extract URLs/JSON/keywords, sanitize HTML, flatten/merge JSON, dedupe lines, validate schema, PII/secret/injection detect |
|
|
450
|
-
| `@utilix-tech/sdk/media` | Image format & dimension reading from raw bytes
|
|
460
|
+
| `@utilix-tech/sdk/media` | Image format & dimension reading from raw bytes (PNG, JPEG, GIF, WebP, BMP); PDF metadata reading |
|
|
451
461
|
|
|
452
462
|
---
|
|
453
463
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* - curl-builder : buildCurl, buildCurlMultiline, parseCurl
|
|
5
5
|
* - curl-to-code : parseCurlCommand, convertToCode
|
|
6
6
|
* - jwt-decoder : decodeJwt, formatJwtJson
|
|
7
|
+
* - jwk-viewer : parseJwks
|
|
7
8
|
* - jwt-signer : base64urlEncode, base64urlDecode, signJwt
|
|
8
9
|
* - cors-builder : validateCorsConfig, generateCors
|
|
9
10
|
* - csp-builder : generateCspHeader, generateFullHeader, parseCspHeader, validateCspConfig
|
|
@@ -78,6 +79,33 @@ interface JwtDecodeError {
|
|
|
78
79
|
type JwtResult = JwtDecodeResult | JwtDecodeError;
|
|
79
80
|
declare function decodeJwt(token: string): JwtResult;
|
|
80
81
|
declare function formatJwtJson(obj: Record<string, unknown>): string;
|
|
82
|
+
interface JwkSummary {
|
|
83
|
+
kty: string;
|
|
84
|
+
use?: string;
|
|
85
|
+
keyOps?: string[];
|
|
86
|
+
alg?: string;
|
|
87
|
+
kid?: string;
|
|
88
|
+
keySize: number | null;
|
|
89
|
+
curve?: string;
|
|
90
|
+
raw: Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
interface JwksResult {
|
|
93
|
+
ok: true;
|
|
94
|
+
keys: JwkSummary[];
|
|
95
|
+
count: number;
|
|
96
|
+
duplicateKids: string[];
|
|
97
|
+
}
|
|
98
|
+
interface JwksError {
|
|
99
|
+
ok: false;
|
|
100
|
+
error: string;
|
|
101
|
+
}
|
|
102
|
+
type JwksParseResult = JwksResult | JwksError;
|
|
103
|
+
/**
|
|
104
|
+
* Parse a JSON Web Key Set (or a single bare JWK) and summarize each key's
|
|
105
|
+
* type, use, algorithm, key ID, and approximate size. Does not verify or
|
|
106
|
+
* use the keys cryptographically: this is inspection only.
|
|
107
|
+
*/
|
|
108
|
+
declare function parseJwks(input: string): JwksParseResult;
|
|
81
109
|
type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512';
|
|
82
110
|
interface JwtSignOptions {
|
|
83
111
|
algorithm?: JwtAlgorithm;
|
|
@@ -255,6 +283,10 @@ type api_FormatResult = FormatResult;
|
|
|
255
283
|
declare const api_HTTP_METHODS: typeof HTTP_METHODS;
|
|
256
284
|
type api_Header = Header;
|
|
257
285
|
type api_HttpMethod = HttpMethod;
|
|
286
|
+
type api_JwkSummary = JwkSummary;
|
|
287
|
+
type api_JwksError = JwksError;
|
|
288
|
+
type api_JwksParseResult = JwksParseResult;
|
|
289
|
+
type api_JwksResult = JwksResult;
|
|
258
290
|
type api_JwtAlgorithm = JwtAlgorithm;
|
|
259
291
|
type api_JwtDecodeError = JwtDecodeError;
|
|
260
292
|
type api_JwtDecodeResult = JwtDecodeResult;
|
|
@@ -294,6 +326,7 @@ declare const api_normalizeUrl: typeof normalizeUrl;
|
|
|
294
326
|
declare const api_parseCspHeader: typeof parseCspHeader;
|
|
295
327
|
declare const api_parseCurl: typeof parseCurl;
|
|
296
328
|
declare const api_parseCurlCommand: typeof parseCurlCommand;
|
|
329
|
+
declare const api_parseJwks: typeof parseJwks;
|
|
297
330
|
declare const api_parseMetaTags: typeof parseMetaTags;
|
|
298
331
|
declare const api_parseUrl: typeof parseUrl;
|
|
299
332
|
declare const api_removeParam: typeof removeParam;
|
|
@@ -302,7 +335,7 @@ declare const api_validateCorsConfig: typeof validateCorsConfig;
|
|
|
302
335
|
declare const api_validateCspConfig: typeof validateCspConfig;
|
|
303
336
|
declare const api_validateOgTags: typeof validateOgTags;
|
|
304
337
|
declare namespace api {
|
|
305
|
-
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
338
|
+
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwkSummary as JwkSummary, type api_JwksError as JwksError, type api_JwksParseResult as JwksParseResult, type api_JwksResult as JwksResult, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseJwks as parseJwks, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
306
339
|
}
|
|
307
340
|
|
|
308
|
-
export {
|
|
341
|
+
export { generateMetaHtml as $, base64urlDecode as A, base64urlEncode as B, COMMON_HEADERS as C, DEFAULT_CORS_CONFIG as D, buildCurl as E, type FormatResult as F, buildCurlMultiline as G, HTTP_METHODS as H, buildUrl as I, type JwkSummary as J, convertToCode as K, decodeJwt as L, type MetaTags as M, decodeUrlComponent as N, type OgTags as O, type ParsedUrl as P, detectFormat as Q, type ResponseFormat as R, SUPPORTED_LANGUAGES as S, type TargetLanguage as T, encodeUrlComponent as U, extractJsonPaths as V, formatJwtJson as W, formatResponse as X, generateCors as Y, generateCspHeader as Z, generateFullHeader as _, api as a, getParam as a0, getStats as a1, isValidUrl as a2, normalizeUrl as a3, parseCspHeader as a4, parseCurl as a5, parseCurlCommand as a6, parseJwks as a7, parseMetaTags as a8, parseUrl as a9, removeParam as aa, signJwt as ab, validateCorsConfig as ac, validateCspConfig as ad, validateOgTags as ae, COMMON_PRESETS as b, CORS_COMMON_HEADERS as c, type CorsConfig as d, type CorsOutput as e, type CspConfig as f, type CspDirective as g, type CspSource as h, type CurlCommand as i, type CurlConfig as j, DIRECTIVE_DESCRIPTIONS as k, type DirectiveConfig as l, type Header as m, type HttpMethod as n, type JwksError as o, type JwksParseResult as p, type JwksResult as q, type JwtAlgorithm as r, type JwtDecodeError as s, type JwtDecodeResult as t, type JwtExpiry as u, type JwtPart as v, type JwtResult as w, type JwtSignOptions as x, type TwitterTags as y, addParam as z };
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* - curl-builder : buildCurl, buildCurlMultiline, parseCurl
|
|
5
5
|
* - curl-to-code : parseCurlCommand, convertToCode
|
|
6
6
|
* - jwt-decoder : decodeJwt, formatJwtJson
|
|
7
|
+
* - jwk-viewer : parseJwks
|
|
7
8
|
* - jwt-signer : base64urlEncode, base64urlDecode, signJwt
|
|
8
9
|
* - cors-builder : validateCorsConfig, generateCors
|
|
9
10
|
* - csp-builder : generateCspHeader, generateFullHeader, parseCspHeader, validateCspConfig
|
|
@@ -78,6 +79,33 @@ interface JwtDecodeError {
|
|
|
78
79
|
type JwtResult = JwtDecodeResult | JwtDecodeError;
|
|
79
80
|
declare function decodeJwt(token: string): JwtResult;
|
|
80
81
|
declare function formatJwtJson(obj: Record<string, unknown>): string;
|
|
82
|
+
interface JwkSummary {
|
|
83
|
+
kty: string;
|
|
84
|
+
use?: string;
|
|
85
|
+
keyOps?: string[];
|
|
86
|
+
alg?: string;
|
|
87
|
+
kid?: string;
|
|
88
|
+
keySize: number | null;
|
|
89
|
+
curve?: string;
|
|
90
|
+
raw: Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
interface JwksResult {
|
|
93
|
+
ok: true;
|
|
94
|
+
keys: JwkSummary[];
|
|
95
|
+
count: number;
|
|
96
|
+
duplicateKids: string[];
|
|
97
|
+
}
|
|
98
|
+
interface JwksError {
|
|
99
|
+
ok: false;
|
|
100
|
+
error: string;
|
|
101
|
+
}
|
|
102
|
+
type JwksParseResult = JwksResult | JwksError;
|
|
103
|
+
/**
|
|
104
|
+
* Parse a JSON Web Key Set (or a single bare JWK) and summarize each key's
|
|
105
|
+
* type, use, algorithm, key ID, and approximate size. Does not verify or
|
|
106
|
+
* use the keys cryptographically: this is inspection only.
|
|
107
|
+
*/
|
|
108
|
+
declare function parseJwks(input: string): JwksParseResult;
|
|
81
109
|
type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512';
|
|
82
110
|
interface JwtSignOptions {
|
|
83
111
|
algorithm?: JwtAlgorithm;
|
|
@@ -255,6 +283,10 @@ type api_FormatResult = FormatResult;
|
|
|
255
283
|
declare const api_HTTP_METHODS: typeof HTTP_METHODS;
|
|
256
284
|
type api_Header = Header;
|
|
257
285
|
type api_HttpMethod = HttpMethod;
|
|
286
|
+
type api_JwkSummary = JwkSummary;
|
|
287
|
+
type api_JwksError = JwksError;
|
|
288
|
+
type api_JwksParseResult = JwksParseResult;
|
|
289
|
+
type api_JwksResult = JwksResult;
|
|
258
290
|
type api_JwtAlgorithm = JwtAlgorithm;
|
|
259
291
|
type api_JwtDecodeError = JwtDecodeError;
|
|
260
292
|
type api_JwtDecodeResult = JwtDecodeResult;
|
|
@@ -294,6 +326,7 @@ declare const api_normalizeUrl: typeof normalizeUrl;
|
|
|
294
326
|
declare const api_parseCspHeader: typeof parseCspHeader;
|
|
295
327
|
declare const api_parseCurl: typeof parseCurl;
|
|
296
328
|
declare const api_parseCurlCommand: typeof parseCurlCommand;
|
|
329
|
+
declare const api_parseJwks: typeof parseJwks;
|
|
297
330
|
declare const api_parseMetaTags: typeof parseMetaTags;
|
|
298
331
|
declare const api_parseUrl: typeof parseUrl;
|
|
299
332
|
declare const api_removeParam: typeof removeParam;
|
|
@@ -302,7 +335,7 @@ declare const api_validateCorsConfig: typeof validateCorsConfig;
|
|
|
302
335
|
declare const api_validateCspConfig: typeof validateCspConfig;
|
|
303
336
|
declare const api_validateOgTags: typeof validateOgTags;
|
|
304
337
|
declare namespace api {
|
|
305
|
-
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
338
|
+
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwkSummary as JwkSummary, type api_JwksError as JwksError, type api_JwksParseResult as JwksParseResult, type api_JwksResult as JwksResult, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseJwks as parseJwks, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
306
339
|
}
|
|
307
340
|
|
|
308
|
-
export {
|
|
341
|
+
export { generateMetaHtml as $, base64urlDecode as A, base64urlEncode as B, COMMON_HEADERS as C, DEFAULT_CORS_CONFIG as D, buildCurl as E, type FormatResult as F, buildCurlMultiline as G, HTTP_METHODS as H, buildUrl as I, type JwkSummary as J, convertToCode as K, decodeJwt as L, type MetaTags as M, decodeUrlComponent as N, type OgTags as O, type ParsedUrl as P, detectFormat as Q, type ResponseFormat as R, SUPPORTED_LANGUAGES as S, type TargetLanguage as T, encodeUrlComponent as U, extractJsonPaths as V, formatJwtJson as W, formatResponse as X, generateCors as Y, generateCspHeader as Z, generateFullHeader as _, api as a, getParam as a0, getStats as a1, isValidUrl as a2, normalizeUrl as a3, parseCspHeader as a4, parseCurl as a5, parseCurlCommand as a6, parseJwks as a7, parseMetaTags as a8, parseUrl as a9, removeParam as aa, signJwt as ab, validateCorsConfig as ac, validateCspConfig as ad, validateOgTags as ae, COMMON_PRESETS as b, CORS_COMMON_HEADERS as c, type CorsConfig as d, type CorsOutput as e, type CspConfig as f, type CspDirective as g, type CspSource as h, type CurlCommand as i, type CurlConfig as j, DIRECTIVE_DESCRIPTIONS as k, type DirectiveConfig as l, type Header as m, type HttpMethod as n, type JwksError as o, type JwksParseResult as p, type JwksResult as q, type JwtAlgorithm as r, type JwtDecodeError as s, type JwtDecodeResult as t, type JwtExpiry as u, type JwtPart as v, type JwtResult as w, type JwtSignOptions as x, type TwitterTags as y, addParam as z };
|
|
@@ -36,6 +36,7 @@ __export(api_exports, {
|
|
|
36
36
|
parseCspHeader: () => parseCspHeader,
|
|
37
37
|
parseCurl: () => parseCurl,
|
|
38
38
|
parseCurlCommand: () => parseCurlCommand,
|
|
39
|
+
parseJwks: () => parseJwks,
|
|
39
40
|
parseMetaTags: () => parseMetaTags,
|
|
40
41
|
parseUrl: () => parseUrl,
|
|
41
42
|
removeParam: () => removeParam,
|
|
@@ -485,6 +486,55 @@ function decodeJwt(token) {
|
|
|
485
486
|
function formatJwtJson(obj) {
|
|
486
487
|
return JSON.stringify(obj, null, 2);
|
|
487
488
|
}
|
|
489
|
+
function base64urlByteLength(s) {
|
|
490
|
+
const clean = s.replace(/=+$/, "");
|
|
491
|
+
return Math.floor(clean.length * 6 / 8);
|
|
492
|
+
}
|
|
493
|
+
function parseJwks(input) {
|
|
494
|
+
const trimmed = input.trim();
|
|
495
|
+
if (!trimmed) return { ok: false, error: "No input provided" };
|
|
496
|
+
let data;
|
|
497
|
+
try {
|
|
498
|
+
data = JSON.parse(trimmed);
|
|
499
|
+
} catch (e) {
|
|
500
|
+
return { ok: false, error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}` };
|
|
501
|
+
}
|
|
502
|
+
let rawKeys;
|
|
503
|
+
if (data && typeof data === "object" && Array.isArray(data.keys)) {
|
|
504
|
+
rawKeys = data.keys;
|
|
505
|
+
} else if (data && typeof data === "object" && typeof data.kty === "string") {
|
|
506
|
+
rawKeys = [data];
|
|
507
|
+
} else {
|
|
508
|
+
return { ok: false, error: 'Input must be a JWKS object with a "keys" array, or a single JWK object with a "kty" field' };
|
|
509
|
+
}
|
|
510
|
+
const keys = rawKeys.map((k) => {
|
|
511
|
+
const key = k ?? {};
|
|
512
|
+
const kty = typeof key.kty === "string" ? key.kty : "unknown";
|
|
513
|
+
let keySize = null;
|
|
514
|
+
let curve;
|
|
515
|
+
if (kty === "RSA" && typeof key.n === "string") {
|
|
516
|
+
keySize = base64urlByteLength(key.n) * 8;
|
|
517
|
+
} else if ((kty === "EC" || kty === "OKP") && typeof key.crv === "string") {
|
|
518
|
+
curve = key.crv;
|
|
519
|
+
} else if (kty === "oct" && typeof key.k === "string") {
|
|
520
|
+
keySize = base64urlByteLength(key.k) * 8;
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
kty,
|
|
524
|
+
use: typeof key.use === "string" ? key.use : void 0,
|
|
525
|
+
keyOps: Array.isArray(key.key_ops) ? key.key_ops.filter((x) => typeof x === "string") : void 0,
|
|
526
|
+
alg: typeof key.alg === "string" ? key.alg : void 0,
|
|
527
|
+
kid: typeof key.kid === "string" ? key.kid : void 0,
|
|
528
|
+
keySize,
|
|
529
|
+
curve,
|
|
530
|
+
raw: key
|
|
531
|
+
};
|
|
532
|
+
});
|
|
533
|
+
const kidCounts = /* @__PURE__ */ new Map();
|
|
534
|
+
for (const k of keys) if (k.kid) kidCounts.set(k.kid, (kidCounts.get(k.kid) ?? 0) + 1);
|
|
535
|
+
const duplicateKids = [...kidCounts.entries()].filter(([, c]) => c > 1).map(([kid]) => kid);
|
|
536
|
+
return { ok: true, keys, count: keys.length, duplicateKids };
|
|
537
|
+
}
|
|
488
538
|
var ALG_TO_NODE_HASH = {
|
|
489
539
|
HS256: "sha256",
|
|
490
540
|
HS384: "sha384",
|
|
@@ -1216,4 +1266,4 @@ function generateMetaHtml(tags) {
|
|
|
1216
1266
|
return lines.join("\n");
|
|
1217
1267
|
}
|
|
1218
1268
|
|
|
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 };
|
|
1269
|
+
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, parseJwks, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags };
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { __export } from './chunk-MLKGABMK.js';
|
|
2
|
+
|
|
3
|
+
// src/tools/media.ts
|
|
4
|
+
var media_exports = {};
|
|
5
|
+
__export(media_exports, {
|
|
6
|
+
readImageInfo: () => readImageInfo,
|
|
7
|
+
readPdfMetadata: () => readPdfMetadata
|
|
8
|
+
});
|
|
9
|
+
function readU32BE(bytes, offset) {
|
|
10
|
+
return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
11
|
+
}
|
|
12
|
+
function readI32LE(bytes, offset) {
|
|
13
|
+
return bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24;
|
|
14
|
+
}
|
|
15
|
+
var PNG_COLOR_TYPES = {
|
|
16
|
+
0: "grayscale",
|
|
17
|
+
2: "rgb",
|
|
18
|
+
3: "palette",
|
|
19
|
+
4: "grayscale+alpha",
|
|
20
|
+
6: "rgba"
|
|
21
|
+
};
|
|
22
|
+
function readPng(bytes) {
|
|
23
|
+
if (bytes.length < 33) return { error: "Truncated PNG file" };
|
|
24
|
+
const width = readU32BE(bytes, 16);
|
|
25
|
+
const height = readU32BE(bytes, 20);
|
|
26
|
+
const bitDepth = bytes[24];
|
|
27
|
+
const colorTypeNum = bytes[25];
|
|
28
|
+
const colorType = PNG_COLOR_TYPES[colorTypeNum] ?? "unknown";
|
|
29
|
+
const hasAlpha = colorTypeNum === 4 || colorTypeNum === 6;
|
|
30
|
+
return { format: "png", width, height, bitDepth, colorType, hasAlpha };
|
|
31
|
+
}
|
|
32
|
+
function readGif(bytes) {
|
|
33
|
+
if (bytes.length < 10) return { error: "Truncated GIF file" };
|
|
34
|
+
const width = bytes[6] | bytes[7] << 8;
|
|
35
|
+
const height = bytes[8] | bytes[9] << 8;
|
|
36
|
+
return { format: "gif", width, height };
|
|
37
|
+
}
|
|
38
|
+
function readBmp(bytes) {
|
|
39
|
+
if (bytes.length < 30) return { error: "Truncated BMP file" };
|
|
40
|
+
const width = readI32LE(bytes, 18);
|
|
41
|
+
const heightRaw = readI32LE(bytes, 22);
|
|
42
|
+
const bitDepth = bytes[28] | bytes[29] << 8;
|
|
43
|
+
return { format: "bmp", width: Math.abs(width), height: Math.abs(heightRaw), bitDepth };
|
|
44
|
+
}
|
|
45
|
+
function readWebp(bytes) {
|
|
46
|
+
if (bytes.length < 16) return { error: "Truncated WebP file" };
|
|
47
|
+
const fourCC = String.fromCharCode(bytes[12], bytes[13], bytes[14], bytes[15]);
|
|
48
|
+
if (fourCC === "VP8 ") {
|
|
49
|
+
if (bytes.length < 30) return { error: "Truncated WebP file" };
|
|
50
|
+
const width = (bytes[26] | bytes[27] << 8) & 16383;
|
|
51
|
+
const height = (bytes[28] | bytes[29] << 8) & 16383;
|
|
52
|
+
return { format: "webp", width, height };
|
|
53
|
+
}
|
|
54
|
+
if (fourCC === "VP8L") {
|
|
55
|
+
if (bytes.length < 25) return { error: "Truncated WebP file" };
|
|
56
|
+
const bits = bytes[21] | bytes[22] << 8 | bytes[23] << 16 | bytes[24] << 24;
|
|
57
|
+
const width = (bits & 16383) + 1;
|
|
58
|
+
const height = (bits >>> 14 & 16383) + 1;
|
|
59
|
+
const hasAlpha = !!(bits >>> 28 & 1);
|
|
60
|
+
return { format: "webp", width, height, hasAlpha };
|
|
61
|
+
}
|
|
62
|
+
if (fourCC === "VP8X") {
|
|
63
|
+
if (bytes.length < 30) return { error: "Truncated WebP file" };
|
|
64
|
+
const flags = bytes[20];
|
|
65
|
+
const hasAlpha = !!(flags & 16);
|
|
66
|
+
const width = (bytes[24] | bytes[25] << 8 | bytes[26] << 16) + 1;
|
|
67
|
+
const height = (bytes[27] | bytes[28] << 8 | bytes[29] << 16) + 1;
|
|
68
|
+
return { format: "webp", width, height, hasAlpha };
|
|
69
|
+
}
|
|
70
|
+
return { error: "Unrecognized WebP chunk format" };
|
|
71
|
+
}
|
|
72
|
+
var JPEG_SOF_MARKERS = /* @__PURE__ */ new Set([
|
|
73
|
+
192,
|
|
74
|
+
193,
|
|
75
|
+
194,
|
|
76
|
+
195,
|
|
77
|
+
197,
|
|
78
|
+
198,
|
|
79
|
+
199,
|
|
80
|
+
201,
|
|
81
|
+
202,
|
|
82
|
+
203,
|
|
83
|
+
205,
|
|
84
|
+
206,
|
|
85
|
+
207
|
|
86
|
+
]);
|
|
87
|
+
function readJpeg(bytes) {
|
|
88
|
+
let offset = 2;
|
|
89
|
+
while (offset < bytes.length - 1) {
|
|
90
|
+
if (bytes[offset] !== 255) {
|
|
91
|
+
offset++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const marker = bytes[offset + 1];
|
|
95
|
+
if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) {
|
|
96
|
+
offset += 2;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (marker === 217) break;
|
|
100
|
+
if (offset + 3 >= bytes.length) break;
|
|
101
|
+
const segmentLength = bytes[offset + 2] << 8 | bytes[offset + 3];
|
|
102
|
+
if (JPEG_SOF_MARKERS.has(marker)) {
|
|
103
|
+
if (offset + 9 >= bytes.length) return { error: "Truncated JPEG SOF segment" };
|
|
104
|
+
const bitDepth = bytes[offset + 4];
|
|
105
|
+
const height = bytes[offset + 5] << 8 | bytes[offset + 6];
|
|
106
|
+
const width = bytes[offset + 7] << 8 | bytes[offset + 8];
|
|
107
|
+
const components = bytes[offset + 9];
|
|
108
|
+
const colorType = components === 1 ? "grayscale" : components === 3 ? "rgb" : components === 4 ? "cmyk" : "unknown";
|
|
109
|
+
return { format: "jpeg", width, height, bitDepth, colorType };
|
|
110
|
+
}
|
|
111
|
+
offset += 2 + segmentLength;
|
|
112
|
+
}
|
|
113
|
+
return { error: "No SOF marker found in JPEG (file may be corrupt)" };
|
|
114
|
+
}
|
|
115
|
+
function readImageInfo(bytes) {
|
|
116
|
+
if (bytes.length < 10) return { error: "File too small to determine format" };
|
|
117
|
+
if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10) {
|
|
118
|
+
return readPng(bytes);
|
|
119
|
+
}
|
|
120
|
+
if (bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) {
|
|
121
|
+
return readGif(bytes);
|
|
122
|
+
}
|
|
123
|
+
if (bytes[0] === 66 && bytes[1] === 77) {
|
|
124
|
+
return readBmp(bytes);
|
|
125
|
+
}
|
|
126
|
+
if (bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
|
|
127
|
+
return readWebp(bytes);
|
|
128
|
+
}
|
|
129
|
+
if (bytes[0] === 255 && bytes[1] === 216) {
|
|
130
|
+
return readJpeg(bytes);
|
|
131
|
+
}
|
|
132
|
+
return { error: "Unrecognized image format. Supported formats: PNG, JPEG, GIF, WebP, BMP" };
|
|
133
|
+
}
|
|
134
|
+
function bytesToLatin1(bytes) {
|
|
135
|
+
let out = "";
|
|
136
|
+
const CHUNK = 32768;
|
|
137
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
138
|
+
out += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
function decodePdfString(raw, isHex) {
|
|
143
|
+
const bytes = [];
|
|
144
|
+
if (isHex) {
|
|
145
|
+
const hex = raw.replace(/\s+/g, "");
|
|
146
|
+
const padded = hex.length % 2 === 0 ? hex : hex + "0";
|
|
147
|
+
for (let i = 0; i < padded.length; i += 2) bytes.push(parseInt(padded.slice(i, i + 2), 16));
|
|
148
|
+
} else {
|
|
149
|
+
const s = raw.replace(/\\\r\n|\\\r|\\\n/g, "");
|
|
150
|
+
for (let i = 0; i < s.length; i++) {
|
|
151
|
+
const ch = s[i];
|
|
152
|
+
if (ch === "\\" && i + 1 < s.length) {
|
|
153
|
+
const next = s[i + 1];
|
|
154
|
+
if (next === "n") {
|
|
155
|
+
bytes.push(10);
|
|
156
|
+
i++;
|
|
157
|
+
} else if (next === "r") {
|
|
158
|
+
bytes.push(13);
|
|
159
|
+
i++;
|
|
160
|
+
} else if (next === "t") {
|
|
161
|
+
bytes.push(9);
|
|
162
|
+
i++;
|
|
163
|
+
} else if (next === "b") {
|
|
164
|
+
bytes.push(8);
|
|
165
|
+
i++;
|
|
166
|
+
} else if (next === "f") {
|
|
167
|
+
bytes.push(12);
|
|
168
|
+
i++;
|
|
169
|
+
} else if (next === "(" || next === ")" || next === "\\") {
|
|
170
|
+
bytes.push(next.charCodeAt(0));
|
|
171
|
+
i++;
|
|
172
|
+
} else if (/[0-7]/.test(next)) {
|
|
173
|
+
let oct = next;
|
|
174
|
+
i++;
|
|
175
|
+
for (let k = 0; k < 2 && i + 1 < s.length && /[0-7]/.test(s[i + 1]); k++) {
|
|
176
|
+
i++;
|
|
177
|
+
oct += s[i];
|
|
178
|
+
}
|
|
179
|
+
bytes.push(parseInt(oct, 8) & 255);
|
|
180
|
+
} else {
|
|
181
|
+
bytes.push(next.charCodeAt(0));
|
|
182
|
+
i++;
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
bytes.push(ch.charCodeAt(0) & 255);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (bytes.length >= 2 && bytes[0] === 254 && bytes[1] === 255) {
|
|
190
|
+
let out = "";
|
|
191
|
+
for (let i = 2; i + 1 < bytes.length; i += 2) out += String.fromCharCode(bytes[i] << 8 | bytes[i + 1]);
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
return bytes.map((b) => String.fromCharCode(b)).join("");
|
|
195
|
+
}
|
|
196
|
+
function extractDictField(dict, key) {
|
|
197
|
+
const litMatch = dict.match(new RegExp(`/${key}\\s*\\(((?:\\\\.|[^\\\\()])*)\\)`));
|
|
198
|
+
if (litMatch) return decodePdfString(litMatch[1], false);
|
|
199
|
+
const hexMatch = dict.match(new RegExp(`/${key}\\s*<([0-9A-Fa-f\\s]*)>`));
|
|
200
|
+
if (hexMatch) return decodePdfString(hexMatch[1], true);
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
function findObject(text, objNum, gen) {
|
|
204
|
+
const m = text.match(new RegExp(`(?:^|[^0-9])${objNum}\\s+${gen}\\s+obj([\\s\\S]*?)endobj`));
|
|
205
|
+
return m ? m[1] : null;
|
|
206
|
+
}
|
|
207
|
+
function parsePdfDate(raw) {
|
|
208
|
+
const m = raw.match(/^D:(\d{4})(\d{2})?(\d{2})?(\d{2})?(\d{2})?(\d{2})?([Z+-])?(\d{2})?'?(\d{2})?'?/);
|
|
209
|
+
if (!m) return null;
|
|
210
|
+
const [, y, mo = "01", d = "01", h = "00", mi = "00", s = "00", tz, tzh, tzm] = m;
|
|
211
|
+
let iso = `${y}-${mo}-${d}T${h}:${mi}:${s}`;
|
|
212
|
+
if (tz === "Z") iso += "Z";
|
|
213
|
+
else if (tz === "+" || tz === "-") iso += `${tz}${tzh ?? "00"}:${tzm ?? "00"}`;
|
|
214
|
+
return iso;
|
|
215
|
+
}
|
|
216
|
+
function readPdfMetadata(bytes) {
|
|
217
|
+
if (bytes.length < 8) return { error: "File too small to be a PDF" };
|
|
218
|
+
const header = bytesToLatin1(bytes.subarray(0, 16));
|
|
219
|
+
const versionMatch = header.match(/%PDF-(\d\.\d)/);
|
|
220
|
+
if (!versionMatch) return { error: "Not a valid PDF file (missing %PDF header)" };
|
|
221
|
+
const version = versionMatch[1];
|
|
222
|
+
const text = bytesToLatin1(bytes);
|
|
223
|
+
const trailerMatches = [...text.matchAll(/trailer\s*<<([\s\S]*?)>>/g)];
|
|
224
|
+
let infoDict = null;
|
|
225
|
+
let encrypted = false;
|
|
226
|
+
if (trailerMatches.length > 0) {
|
|
227
|
+
const trailer = trailerMatches[trailerMatches.length - 1][1];
|
|
228
|
+
encrypted = /\/Encrypt\s+\d+\s+\d+\s+R/.test(trailer);
|
|
229
|
+
const infoRef = trailer.match(/\/Info\s+(\d+)\s+(\d+)\s+R/);
|
|
230
|
+
if (infoRef) infoDict = findObject(text, Number(infoRef[1]), Number(infoRef[2]));
|
|
231
|
+
}
|
|
232
|
+
const objBlocks = [...text.matchAll(/(\d+)\s+(\d+)\s+obj([\s\S]*?)endobj/g)];
|
|
233
|
+
if (!infoDict) {
|
|
234
|
+
for (const b of objBlocks) {
|
|
235
|
+
if (/\/(Title|Author|Producer|Creator|CreationDate)\b/.test(b[3]) && !/\/Type\s*\/(Page|Pages|Catalog|Font)\b/.test(b[3])) {
|
|
236
|
+
infoDict = b[3];
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const title = infoDict ? extractDictField(infoDict, "Title") : null;
|
|
242
|
+
const author = infoDict ? extractDictField(infoDict, "Author") : null;
|
|
243
|
+
const subject = infoDict ? extractDictField(infoDict, "Subject") : null;
|
|
244
|
+
const keywords = infoDict ? extractDictField(infoDict, "Keywords") : null;
|
|
245
|
+
const creator = infoDict ? extractDictField(infoDict, "Creator") : null;
|
|
246
|
+
const producer = infoDict ? extractDictField(infoDict, "Producer") : null;
|
|
247
|
+
const creationDateRaw = infoDict ? extractDictField(infoDict, "CreationDate") : null;
|
|
248
|
+
const modDateRaw = infoDict ? extractDictField(infoDict, "ModDate") : null;
|
|
249
|
+
let pageCount = null;
|
|
250
|
+
for (const b of objBlocks) {
|
|
251
|
+
if (!/\/Type\s*\/Pages\b/.test(b[3])) continue;
|
|
252
|
+
const countMatch = b[3].match(/\/Count\s+(\d+)/);
|
|
253
|
+
if (countMatch) {
|
|
254
|
+
const c = Number(countMatch[1]);
|
|
255
|
+
if (pageCount === null || c > pageCount) pageCount = c;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (pageCount === null) {
|
|
259
|
+
const pageMatches = text.match(/\/Type\s*\/Page(?!s)\b/g);
|
|
260
|
+
if (pageMatches) pageCount = pageMatches.length;
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
version,
|
|
264
|
+
pageCount,
|
|
265
|
+
title,
|
|
266
|
+
author,
|
|
267
|
+
subject,
|
|
268
|
+
keywords,
|
|
269
|
+
creator,
|
|
270
|
+
producer,
|
|
271
|
+
creationDate: creationDateRaw ? parsePdfDate(creationDateRaw) ?? creationDateRaw : null,
|
|
272
|
+
modDate: modDateRaw ? parsePdfDate(modDateRaw) ?? modDateRaw : null,
|
|
273
|
+
encrypted
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export { media_exports, readImageInfo, readPdfMetadata };
|