ssrwire 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 (74) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/CONTRIBUTING.md +49 -0
  3. package/LICENSE +21 -0
  4. package/PUBLISHING.md +134 -0
  5. package/README.md +403 -0
  6. package/SECURITY.md +26 -0
  7. package/dist/agents.d.ts +14 -0
  8. package/dist/agents.d.ts.map +1 -0
  9. package/dist/agents.js +100 -0
  10. package/dist/agents.js.map +1 -0
  11. package/dist/analyze.d.ts +4 -0
  12. package/dist/analyze.d.ts.map +1 -0
  13. package/dist/analyze.js +494 -0
  14. package/dist/analyze.js.map +1 -0
  15. package/dist/audit.d.ts +3 -0
  16. package/dist/audit.d.ts.map +1 -0
  17. package/dist/audit.js +69 -0
  18. package/dist/audit.js.map +1 -0
  19. package/dist/bin.d.ts +3 -0
  20. package/dist/bin.d.ts.map +1 -0
  21. package/dist/bin.js +4 -0
  22. package/dist/bin.js.map +1 -0
  23. package/dist/cli.d.ts +2 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +173 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/config.d.ts +17 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +262 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/http-probe.d.ts +7 -0
  32. package/dist/http-probe.d.ts.map +1 -0
  33. package/dist/http-probe.js +406 -0
  34. package/dist/http-probe.js.map +1 -0
  35. package/dist/index.d.ts +11 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +10 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/redact.d.ts +10 -0
  40. package/dist/redact.d.ts.map +1 -0
  41. package/dist/redact.js +154 -0
  42. package/dist/redact.js.map +1 -0
  43. package/dist/reporters.d.ts +9 -0
  44. package/dist/reporters.d.ts.map +1 -0
  45. package/dist/reporters.js +220 -0
  46. package/dist/reporters.js.map +1 -0
  47. package/dist/stream-parser.d.ts +9 -0
  48. package/dist/stream-parser.d.ts.map +1 -0
  49. package/dist/stream-parser.js +366 -0
  50. package/dist/stream-parser.js.map +1 -0
  51. package/dist/types.d.ts +134 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +2 -0
  54. package/dist/types.js.map +1 -0
  55. package/dist/version.d.ts +2 -0
  56. package/dist/version.d.ts.map +1 -0
  57. package/dist/version.js +14 -0
  58. package/dist/version.js.map +1 -0
  59. package/examples/github-actions.yml +73 -0
  60. package/examples/ssrwire.config.yml +37 -0
  61. package/package.json +91 -0
  62. package/src/agents.ts +129 -0
  63. package/src/analyze.ts +628 -0
  64. package/src/audit.ts +89 -0
  65. package/src/bin.ts +5 -0
  66. package/src/cli.ts +207 -0
  67. package/src/config.ts +313 -0
  68. package/src/http-probe.ts +461 -0
  69. package/src/index.ts +34 -0
  70. package/src/redact.ts +173 -0
  71. package/src/reporters.ts +274 -0
  72. package/src/stream-parser.ts +424 -0
  73. package/src/types.ts +160 -0
  74. package/src/version.ts +19 -0
package/dist/audit.js ADDED
@@ -0,0 +1,69 @@
1
+ import { analyzeTarget, summarizeAudit } from "./analyze.js";
2
+ import { probeUrl } from "./http-probe.js";
3
+ import { redactAudit } from "./redact.js";
4
+ import { VERSION } from "./version.js";
5
+ const DEFAULT_CONCURRENCY = 4;
6
+ async function runPool(inputs, limit, worker) {
7
+ const results = new Array(inputs.length);
8
+ let cursor = 0;
9
+ async function consume() {
10
+ while (cursor < inputs.length) {
11
+ const index = cursor;
12
+ cursor += 1;
13
+ const input = inputs[index];
14
+ if (input === undefined) {
15
+ continue;
16
+ }
17
+ results[index] = await worker(input);
18
+ }
19
+ }
20
+ const workers = Array.from({ length: Math.min(limit, inputs.length) }, () => consume());
21
+ await Promise.all(workers);
22
+ return results;
23
+ }
24
+ export async function runAudit(config) {
25
+ const started = performance.now();
26
+ const tasks = [];
27
+ for (const [targetIndex, target] of config.targets.entries()) {
28
+ for (const [agentIndex, agent] of config.agents.entries()) {
29
+ tasks.push({
30
+ targetIndex,
31
+ agentIndex,
32
+ options: {
33
+ url: target.url,
34
+ agent,
35
+ headers: config.headers,
36
+ timeoutMs: config.timeoutMs,
37
+ maxBytes: config.maxBytes,
38
+ maxRedirects: config.maxRedirects,
39
+ redactHeaderValues: false,
40
+ },
41
+ });
42
+ }
43
+ }
44
+ const secrets = Object.values(config.headers);
45
+ const probes = await runPool(tasks, DEFAULT_CONCURRENCY, async (task) => {
46
+ const probe = await probeUrl(task.options);
47
+ return { task, probe };
48
+ });
49
+ const results = config.targets.map((target, targetIndex) => {
50
+ const targetProbes = probes
51
+ .filter((item) => item.task.targetIndex === targetIndex)
52
+ .sort((a, b) => a.task.agentIndex - b.task.agentIndex)
53
+ .map((item) => item.probe);
54
+ return {
55
+ target,
56
+ probes: targetProbes,
57
+ findings: analyzeTarget(target, targetProbes),
58
+ };
59
+ });
60
+ const audit = {
61
+ version: VERSION,
62
+ generatedAt: new Date().toISOString(),
63
+ durationMs: Math.round(performance.now() - started),
64
+ results,
65
+ summary: summarizeAudit(results),
66
+ };
67
+ return redactAudit(audit, secrets);
68
+ }
69
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./cli.js";
3
+ await main();
4
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,MAAM,IAAI,EAAE,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function main(argv?: readonly string[]): Promise<void>;
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAkKA,wBAAsB,IAAI,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4ChF"}
package/dist/cli.js ADDED
@@ -0,0 +1,173 @@
1
+ import { access, mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { Command, CommanderError, InvalidArgumentError } from "commander";
4
+ import { runAudit } from "./audit.js";
5
+ import { ConfigError, loadConfig } from "./config.js";
6
+ import { renderReport } from "./reporters.js";
7
+ import { VERSION } from "./version.js";
8
+ const CONFIG_TEMPLATE = `# SSRWire configuration
9
+ targets:
10
+ - url: https://example.com/
11
+ expectedStatus: 200
12
+ require:
13
+ title: true
14
+ description: true
15
+ canonical: true
16
+ h1: true
17
+ mainText: true
18
+
19
+ agents:
20
+ - browser
21
+ - googlebot
22
+ - bingbot
23
+ - twitterbot
24
+
25
+ timeoutMs: 15000
26
+ maxBytes: 10485760
27
+ maxRedirects: 10
28
+
29
+ # Keep preview credentials in environment variables. SSRWire redacts configured values from reports.
30
+ # headers:
31
+ # Authorization: \${PREVIEW_TOKEN}
32
+ `;
33
+ function collect(value, previous) {
34
+ return [...previous, value];
35
+ }
36
+ function parseInteger(value) {
37
+ const parsed = Number(value);
38
+ if (!Number.isInteger(parsed)) {
39
+ throw new InvalidArgumentError("Expected an integer.");
40
+ }
41
+ return parsed;
42
+ }
43
+ function parseFormat(value) {
44
+ if (value === "terminal" || value === "json" || value === "sarif") {
45
+ return value;
46
+ }
47
+ throw new InvalidArgumentError("Expected terminal, json, or sarif.");
48
+ }
49
+ function parseFailOn(value) {
50
+ if (value === "error" || value === "warning" || value === "never") {
51
+ return value;
52
+ }
53
+ throw new InvalidArgumentError("Expected error, warning, or never.");
54
+ }
55
+ function addCheckOptions(command) {
56
+ return command
57
+ .option("-c, --config <path>", "configuration file")
58
+ .option("-a, --agent <name>", "built-in crawler agent; repeatable", collect, [])
59
+ .option("-H, --header <header>", "same-origin request header; repeatable", collect, [])
60
+ .option("--timeout <ms>", "request timeout in milliseconds", parseInteger)
61
+ .option("--max-bytes <bytes>", "maximum response bytes", parseInteger)
62
+ .option("--max-redirects <count>", "maximum redirects", parseInteger)
63
+ .option("-f, --format <format>", "terminal, json, or sarif", parseFormat, "terminal")
64
+ .option("-o, --output <path>", "write the report to a file")
65
+ .option("--fail-on <level>", "error, warning, or never", parseFailOn, "error")
66
+ .option("--no-color", "disable terminal colors");
67
+ }
68
+ function optionsFrom(command) {
69
+ return command.optsWithGlobals();
70
+ }
71
+ function reportExitCode(summary, failOn) {
72
+ if (summary.incomplete > 0) {
73
+ return 2;
74
+ }
75
+ if (failOn === "never") {
76
+ return 0;
77
+ }
78
+ if (summary.errors > 0) {
79
+ return 1;
80
+ }
81
+ if (failOn === "warning" && summary.warnings > 0) {
82
+ return 1;
83
+ }
84
+ return 0;
85
+ }
86
+ async function writeReport(path, report) {
87
+ const absolute = resolve(path);
88
+ await mkdir(dirname(absolute), { recursive: true });
89
+ await writeFile(absolute, report, "utf8");
90
+ }
91
+ async function check(urls, options) {
92
+ const config = await loadConfig({
93
+ ...(options.config ? { configPath: options.config } : {}),
94
+ urls,
95
+ agents: options.agent,
96
+ headers: options.header,
97
+ ...(options.timeout === undefined ? {} : { timeoutMs: options.timeout }),
98
+ ...(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }),
99
+ ...(options.maxRedirects === undefined ? {} : { maxRedirects: options.maxRedirects }),
100
+ });
101
+ const audit = await runAudit(config);
102
+ const color = options.color &&
103
+ !options.output &&
104
+ Boolean(process.stdout.isTTY) &&
105
+ !Reflect.has(process.env, "NO_COLOR");
106
+ const report = renderReport(audit, options.format, { color });
107
+ if (options.output) {
108
+ await writeReport(options.output, report);
109
+ process.stderr.write(`SSRWire wrote ${options.format} report to ${options.output}\n`);
110
+ }
111
+ else {
112
+ process.stdout.write(report);
113
+ }
114
+ process.exitCode = reportExitCode(audit.summary, options.failOn);
115
+ }
116
+ async function initialize(path, force) {
117
+ const absolute = resolve(path);
118
+ if (!force) {
119
+ try {
120
+ await access(absolute);
121
+ throw new ConfigError(`${path} already exists. Use --force to replace it.`);
122
+ }
123
+ catch (error) {
124
+ if (error instanceof ConfigError) {
125
+ throw error;
126
+ }
127
+ }
128
+ }
129
+ await mkdir(dirname(absolute), { recursive: true });
130
+ await writeFile(absolute, CONFIG_TEMPLATE, { encoding: "utf8", flag: force ? "w" : "wx" });
131
+ process.stdout.write(`Created ${path}\n`);
132
+ }
133
+ export async function main(argv = process.argv) {
134
+ const program = new Command();
135
+ program
136
+ .name("ssrwire")
137
+ .description("Inspect streamed SSR HTML and crawler-specific metadata delivery.")
138
+ .version(VERSION)
139
+ .exitOverride()
140
+ .showHelpAfterError();
141
+ addCheckOptions(program)
142
+ .argument("[urls...]", "HTTP or HTTPS URLs to inspect")
143
+ .action(async (urls, _options, command) => {
144
+ await check(urls, optionsFrom(command));
145
+ });
146
+ addCheckOptions(program
147
+ .command("check")
148
+ .description("inspect one or more SSR responses")
149
+ .argument("[urls...]", "HTTP or HTTPS URLs to inspect")).action(async (urls, _options, command) => {
150
+ await check(urls, optionsFrom(command));
151
+ });
152
+ program
153
+ .command("init")
154
+ .description("create a documented starter configuration")
155
+ .argument("[path]", "configuration path", "ssrwire.config.yml")
156
+ .option("--force", "replace an existing file")
157
+ .action(async (path, options) => {
158
+ await initialize(path, options.force ?? false);
159
+ });
160
+ try {
161
+ await program.parseAsync([...argv]);
162
+ }
163
+ catch (error) {
164
+ if (error instanceof CommanderError) {
165
+ process.exitCode = error.exitCode === 0 ? 0 : 2;
166
+ return;
167
+ }
168
+ const message = error instanceof Error ? error.message : String(error);
169
+ process.stderr.write(`SSRWire: ${message}\n`);
170
+ process.exitCode = 2;
171
+ }
172
+ }
173
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { SsrWireConfig } from "./types.js";
2
+ export interface LoadConfigOptions {
3
+ readonly configPath?: string;
4
+ readonly urls?: readonly string[];
5
+ readonly agents?: readonly string[];
6
+ readonly headers?: readonly string[];
7
+ readonly timeoutMs?: number;
8
+ readonly maxBytes?: number;
9
+ readonly maxRedirects?: number;
10
+ readonly cwd?: string;
11
+ }
12
+ export declare class ConfigError extends Error {
13
+ constructor(message: string);
14
+ }
15
+ export declare function parseHeaderOption(value: string): readonly [string, string];
16
+ export declare function loadConfig(options?: LoadConfigOptions): Promise<SsrWireConfig>;
17
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAA6B,aAAa,EAAsB,MAAM,YAAY,CAAC;AAoE/F,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,WAAY,SAAQ,KAAK;gBACjB,OAAO,EAAE,MAAM;CAInC;AAoFD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAM1E;AAoFD,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CAiDxF"}
package/dist/config.js ADDED
@@ -0,0 +1,262 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import { extname, resolve } from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { z } from "zod";
5
+ import { resolveAgents } from "./agents.js";
6
+ const DEFAULT_TIMEOUT_MS = 15_000;
7
+ const DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
8
+ const DEFAULT_MAX_REDIRECTS = 10;
9
+ const DEFAULT_AGENTS = ["browser", "googlebot", "bingbot", "twitterbot"];
10
+ const DEFAULT_CONFIG_FILES = [
11
+ "ssrwire.config.yml",
12
+ "ssrwire.config.yaml",
13
+ "ssrwire.config.json",
14
+ ];
15
+ const requireSchema = z
16
+ .object({
17
+ title: z.boolean().optional(),
18
+ description: z.boolean().optional(),
19
+ canonical: z.boolean().optional(),
20
+ h1: z.boolean().optional(),
21
+ mainText: z.boolean().optional(),
22
+ })
23
+ .strict();
24
+ const targetObjectSchema = z
25
+ .object({
26
+ url: z.string().min(1),
27
+ expectedStatus: z
28
+ .union([
29
+ z.number().int().min(100).max(599),
30
+ z.array(z.number().int().min(100).max(599)).min(1),
31
+ ])
32
+ .optional(),
33
+ expectedFinalUrl: z.string().min(1).optional(),
34
+ require: requireSchema.optional(),
35
+ maxFirstByteMs: z.number().positive().finite().optional(),
36
+ maxCriticalMs: z.number().positive().finite().optional(),
37
+ })
38
+ .strict();
39
+ const agentObjectSchema = z
40
+ .object({
41
+ key: z.string().regex(/^[a-z0-9][a-z0-9-]*$/i),
42
+ label: z.string().min(1).optional(),
43
+ userAgent: z.string().min(1),
44
+ requiresHeadMetadata: z.boolean().optional(),
45
+ })
46
+ .strict();
47
+ const fileConfigSchema = z
48
+ .object({
49
+ targets: z.array(z.union([z.string().min(1), targetObjectSchema])).optional(),
50
+ agents: z
51
+ .array(z.union([z.string().min(1), agentObjectSchema]))
52
+ .min(1)
53
+ .optional(),
54
+ headers: z.record(z.string(), z.string()).optional(),
55
+ timeoutMs: z.number().int().min(100).max(120_000).optional(),
56
+ maxBytes: z
57
+ .number()
58
+ .int()
59
+ .min(1_024)
60
+ .max(50 * 1024 * 1024)
61
+ .optional(),
62
+ maxRedirects: z.number().int().min(0).max(20).optional(),
63
+ })
64
+ .strict();
65
+ export class ConfigError extends Error {
66
+ constructor(message) {
67
+ super(message);
68
+ this.name = "ConfigError";
69
+ }
70
+ }
71
+ function validateHttpUrl(value, label) {
72
+ let url;
73
+ try {
74
+ url = new URL(value);
75
+ }
76
+ catch {
77
+ throw new ConfigError(`${label} must be an absolute HTTP or HTTPS URL.`);
78
+ }
79
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
80
+ throw new ConfigError(`${label} must use HTTP or HTTPS.`);
81
+ }
82
+ if (url.username || url.password) {
83
+ throw new ConfigError(`${label} must not contain embedded credentials.`);
84
+ }
85
+ url.hash = "";
86
+ return url.href;
87
+ }
88
+ function normalizeStatuses(value) {
89
+ const statuses = value === undefined ? [200] : Array.isArray(value) ? value : [value];
90
+ return [...new Set(statuses)];
91
+ }
92
+ function normalizeTarget(value) {
93
+ const item = typeof value === "string" ? { url: value } : value;
94
+ const required = item.require;
95
+ const expectations = {
96
+ statuses: normalizeStatuses(item.expectedStatus),
97
+ ...(item.expectedFinalUrl
98
+ ? { finalUrl: validateHttpUrl(item.expectedFinalUrl, "expectedFinalUrl") }
99
+ : {}),
100
+ requireTitle: required?.title ?? true,
101
+ requireDescription: required?.description ?? true,
102
+ requireCanonical: required?.canonical ?? true,
103
+ requireH1: required?.h1 ?? true,
104
+ requireMainText: required?.mainText ?? true,
105
+ ...(item.maxFirstByteMs === undefined ? {} : { maxFirstByteMs: item.maxFirstByteMs }),
106
+ ...(item.maxCriticalMs === undefined ? {} : { maxCriticalMs: item.maxCriticalMs }),
107
+ };
108
+ return {
109
+ url: validateHttpUrl(item.url, "target URL"),
110
+ expectations,
111
+ };
112
+ }
113
+ function interpolateEnvironment(value) {
114
+ return value.replace(/\$\{([A-Z_][A-Z0-9_]*)\}/gi, (_match, name) => {
115
+ const resolved = process.env[name];
116
+ if (resolved === undefined) {
117
+ throw new ConfigError(`Environment variable ${name} is required by a configured header.`);
118
+ }
119
+ return resolved;
120
+ });
121
+ }
122
+ const FORBIDDEN_HEADERS = new Set([
123
+ "accept-encoding",
124
+ "connection",
125
+ "content-length",
126
+ "host",
127
+ "transfer-encoding",
128
+ "user-agent",
129
+ ]);
130
+ function validateHeader(name, value) {
131
+ const normalizedName = name.trim().toLowerCase();
132
+ if (!/^[!#$%&'*+.^_`|~0-9a-z-]+$/i.test(normalizedName)) {
133
+ throw new ConfigError(`Invalid header name: ${name.trim() || "(empty)"}.`);
134
+ }
135
+ if (FORBIDDEN_HEADERS.has(normalizedName)) {
136
+ throw new ConfigError(`Header ${normalizedName} is managed by SSRWire and cannot be overridden.`);
137
+ }
138
+ if (/\r|\n/.test(value)) {
139
+ throw new ConfigError(`Header ${normalizedName} contains a forbidden line break.`);
140
+ }
141
+ return [normalizedName, interpolateEnvironment(value.trim())];
142
+ }
143
+ export function parseHeaderOption(value) {
144
+ const separator = value.indexOf(":");
145
+ if (separator < 1) {
146
+ throw new ConfigError("Headers must use the form 'Name: value'.");
147
+ }
148
+ return validateHeader(value.slice(0, separator), value.slice(separator + 1));
149
+ }
150
+ function normalizeHeaders(configured, commandLine) {
151
+ const headers = new Map();
152
+ for (const [name, value] of Object.entries(configured ?? {})) {
153
+ const [normalizedName, normalizedValue] = validateHeader(name, value);
154
+ headers.set(normalizedName, normalizedValue);
155
+ }
156
+ for (const value of commandLine ?? []) {
157
+ const [name, normalizedValue] = parseHeaderOption(value);
158
+ headers.set(name, normalizedValue);
159
+ }
160
+ return Object.fromEntries(headers);
161
+ }
162
+ async function fileExists(path) {
163
+ try {
164
+ await access(path);
165
+ return true;
166
+ }
167
+ catch {
168
+ return false;
169
+ }
170
+ }
171
+ async function resolveConfigPath(explicitPath, cwd) {
172
+ if (explicitPath) {
173
+ const path = resolve(cwd, explicitPath);
174
+ if (!(await fileExists(path))) {
175
+ throw new ConfigError(`Configuration file not found: ${explicitPath}`);
176
+ }
177
+ return path;
178
+ }
179
+ for (const name of DEFAULT_CONFIG_FILES) {
180
+ const path = resolve(cwd, name);
181
+ if (await fileExists(path)) {
182
+ return path;
183
+ }
184
+ }
185
+ return undefined;
186
+ }
187
+ function parseConfigText(path, text) {
188
+ try {
189
+ return extname(path).toLowerCase() === ".json" ? JSON.parse(text) : parseYaml(text);
190
+ }
191
+ catch {
192
+ // Parser messages may quote the malformed source line, including a literal header secret.
193
+ throw new ConfigError("Could not parse configuration file.");
194
+ }
195
+ }
196
+ async function readConfig(path) {
197
+ if (!path) {
198
+ return {};
199
+ }
200
+ const raw = parseConfigText(path, await readFile(path, "utf8"));
201
+ const parsed = fileConfigSchema.safeParse(raw);
202
+ if (!parsed.success) {
203
+ const detail = parsed.error.issues
204
+ .slice(0, 5)
205
+ .map((issue) => `${issue.path.join(".") || "config"}: ${issue.message}`)
206
+ .join("; ");
207
+ throw new ConfigError(`Invalid configuration: ${detail}`);
208
+ }
209
+ return parsed.data;
210
+ }
211
+ function uniqueTargets(targets) {
212
+ const seen = new Set();
213
+ return targets.filter((target) => {
214
+ if (seen.has(target.url)) {
215
+ return false;
216
+ }
217
+ seen.add(target.url);
218
+ return true;
219
+ });
220
+ }
221
+ export async function loadConfig(options = {}) {
222
+ const cwd = options.cwd ?? process.cwd();
223
+ const configPath = await resolveConfigPath(options.configPath, cwd);
224
+ const file = await readConfig(configPath);
225
+ const fileTargets = (file.targets ?? []).map(normalizeTarget);
226
+ const cliTargets = (options.urls ?? []).map(normalizeTarget);
227
+ const targets = uniqueTargets([...fileTargets, ...cliTargets]);
228
+ if (targets.length === 0) {
229
+ throw new ConfigError("No target URL was provided. Pass a URL or add targets to ssrwire.config.yml.");
230
+ }
231
+ const agentInputs = options.agents && options.agents.length > 0
232
+ ? options.agents
233
+ : (file.agents ?? DEFAULT_AGENTS);
234
+ let agents;
235
+ try {
236
+ agents = resolveAgents(agentInputs);
237
+ }
238
+ catch (error) {
239
+ throw new ConfigError(error instanceof Error ? error.message : "Invalid crawler agent configuration.");
240
+ }
241
+ const timeoutMs = options.timeoutMs ?? file.timeoutMs ?? DEFAULT_TIMEOUT_MS;
242
+ const maxBytes = options.maxBytes ?? file.maxBytes ?? DEFAULT_MAX_BYTES;
243
+ const maxRedirects = options.maxRedirects ?? file.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
244
+ if (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 120_000) {
245
+ throw new ConfigError("timeoutMs must be an integer between 100 and 120000.");
246
+ }
247
+ if (!Number.isInteger(maxBytes) || maxBytes < 1_024 || maxBytes > 50 * 1024 * 1024) {
248
+ throw new ConfigError("maxBytes must be an integer between 1024 and 52428800.");
249
+ }
250
+ if (!Number.isInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > 20) {
251
+ throw new ConfigError("maxRedirects must be an integer between 0 and 20.");
252
+ }
253
+ return {
254
+ targets,
255
+ agents,
256
+ headers: normalizeHeaders(file.headers, options.headers),
257
+ timeoutMs,
258
+ maxBytes,
259
+ maxRedirects,
260
+ };
261
+ }
262
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ProbeOptions, ProbeResult } from "./types.js";
2
+ /**
3
+ * Read one URL exactly as an HTTP crawler would: no browser, no hydration, and redirects handled
4
+ * explicitly so caller-supplied headers cannot cross an origin boundary.
5
+ */
6
+ export declare function probeUrl(options: ProbeOptions): Promise<ProbeResult>;
7
+ //# sourceMappingURL=http-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-probe.d.ts","sourceRoot":"","sources":["../src/http-probe.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAIV,YAAY,EACZ,WAAW,EAGZ,MAAM,YAAY,CAAC;AA4KpB;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA+Q1E"}