meodp 0.1.0 → 0.2.1

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 (48) hide show
  1. package/README.md +28 -1
  2. package/dist/check/cli.cjs +130 -39
  3. package/dist/check/cli.mjs +130 -39
  4. package/dist/check/index.cjs +12 -8
  5. package/dist/check/index.d.cts +5 -68
  6. package/dist/check/index.d.mts +5 -68
  7. package/dist/check/index.d.ts +5 -68
  8. package/dist/check/index.mjs +4 -2
  9. package/dist/cli/main.cjs +59 -6
  10. package/dist/cli/main.mjs +59 -6
  11. package/dist/config/index.cjs +7 -0
  12. package/dist/config/index.d.cts +47 -0
  13. package/dist/config/index.d.mts +47 -0
  14. package/dist/config/index.d.ts +47 -0
  15. package/dist/config/index.mjs +5 -0
  16. package/dist/notify/cli.cjs +107 -0
  17. package/dist/notify/cli.d.cts +3 -0
  18. package/dist/notify/cli.d.mts +3 -0
  19. package/dist/notify/cli.d.ts +3 -0
  20. package/dist/notify/cli.mjs +101 -0
  21. package/dist/notify/email.cjs +38 -0
  22. package/dist/notify/email.d.cts +29 -0
  23. package/dist/notify/email.d.mts +29 -0
  24. package/dist/notify/email.d.ts +29 -0
  25. package/dist/notify/email.mjs +35 -0
  26. package/dist/notify/feishu.cjs +162 -0
  27. package/dist/notify/feishu.d.cts +74 -0
  28. package/dist/notify/feishu.d.mts +74 -0
  29. package/dist/notify/feishu.d.ts +74 -0
  30. package/dist/notify/feishu.mjs +157 -0
  31. package/dist/notify/index.cjs +64 -0
  32. package/dist/notify/index.d.cts +27 -0
  33. package/dist/notify/index.d.mts +27 -0
  34. package/dist/notify/index.d.ts +27 -0
  35. package/dist/notify/index.mjs +62 -0
  36. package/dist/shared/{meodp.a0bcc3e7.cjs → meodp.2b00b0ae.cjs} +13 -365
  37. package/dist/shared/meodp.4f1da070.d.cts +41 -0
  38. package/dist/shared/meodp.63483e20.cjs +30 -0
  39. package/dist/shared/meodp.80ff918d.mjs +465 -0
  40. package/dist/shared/meodp.8369c4c1.d.ts +41 -0
  41. package/dist/shared/meodp.93e06e00.d.cts +64 -0
  42. package/dist/shared/meodp.93e06e00.d.mts +64 -0
  43. package/dist/shared/meodp.93e06e00.d.ts +64 -0
  44. package/dist/shared/{meodp.d0916bc5.mjs → meodp.9c706389.mjs} +1 -350
  45. package/dist/shared/meodp.a704f8db.d.mts +41 -0
  46. package/dist/shared/meodp.c4c70565.cjs +477 -0
  47. package/dist/shared/meodp.f96d0510.mjs +24 -0
  48. package/package.json +50 -3
@@ -1,74 +1,11 @@
1
- interface LinkTarget {
2
- url: string;
3
- name?: string;
4
- }
5
- type Availability = 'reachable' | 'restricted' | 'unavailable';
6
- type FailureReason = 'http' | 'dns' | 'tls' | 'timeout' | 'network' | 'redirect';
7
- interface LinkObservation extends LinkTarget {
8
- status: Availability;
9
- checkedAt: string;
10
- durationMs: number;
11
- attempts: number;
12
- finalUrl: string;
13
- httpStatus?: number;
14
- redirects: {
15
- url: string;
16
- status: number;
17
- location: string;
18
- }[];
19
- reason?: FailureReason;
20
- detail?: string;
21
- consecutiveFailures: number;
22
- firstFailureAt?: string;
23
- lastSuccessAt?: string;
24
- changed: boolean;
25
- recovered: boolean;
26
- }
27
- interface CheckReport {
28
- schemaVersion: 1;
29
- observer: string;
30
- startedAt: string;
31
- completedAt: string;
32
- summary: Record<Availability, number> & {
33
- total: number;
34
- redirected: number;
35
- recovered: number;
36
- };
37
- results: LinkObservation[];
38
- }
39
- interface CheckOptions {
40
- /** Maximum simultaneous site checks. Default: 5. */
41
- concurrency?: number;
42
- /** Timeout for each HTTP request, including its body. Default: 10000 ms. */
43
- timeoutMs?: number;
44
- /** Retries for transport errors and 5xx responses. Default: 1; 429 is not retried. */
45
- retries?: number;
46
- /** Maximum followed redirects per attempt. Default: 5. */
47
- maxRedirects?: number;
48
- /** Identifies the network/environment. Must match previousReport.observer. */
49
- observer?: string;
50
- previousReport?: CheckReport;
51
- onResult?: (result: LinkObservation) => void | Promise<void>;
52
- }
53
- interface SitemapOptions extends CheckOptions {
54
- /** Treat the input as a site URL: read robots.txt, falling back to /sitemap.xml. */
55
- discover?: boolean;
56
- /** Reject before page checks if discovery exceeds this many unique pages. Default: 10000. */
57
- maxUrls?: number;
58
- /** Maximum number of unique sitemap documents to read. Default: 100. */
59
- maxSitemaps?: number;
60
- /** Maximum downloaded and decompressed size per discovery document. Default: 10 MiB. */
61
- maxSitemapBytes?: number;
62
- }
1
+ import { L as LinkTarget, a as CheckOptions, C as CheckReport, S as SitemapOptions, A as Availability, b as LinkObservation } from '../shared/meodp.93e06e00.cjs';
2
+ export { F as FailureReason } from '../shared/meodp.93e06e00.cjs';
3
+ import { b as ReportSiteOptions } from '../shared/meodp.4f1da070.cjs';
4
+ export { H as HtmlReporterOptions, a as ReportVerificationOptions, R as ReporterConfig, c as ReporterDescription, d as ReporterName, e as ReporterOptions, f as ReporterOutput, g as waitForReport, w as writeReporters } from '../shared/meodp.4f1da070.cjs';
63
5
 
64
6
  /** Check only the supplied URLs. HTTP failures become observations; invalid input rejects. */
65
7
  declare function checkLinks(input: readonly (string | LinkTarget)[], options?: CheckOptions): Promise<CheckReport>;
66
8
 
67
- interface ReportSiteOptions {
68
- /** Automatically load this HTTP(S) or relative JSON URL when hosted. */
69
- dataUrl?: string;
70
- }
71
-
72
9
  declare function formatReport(report: CheckReport, format?: 'json' | 'markdown' | 'html'): string;
73
10
  declare function writeReports(report: CheckReport, directory: string): Promise<{
74
11
  json: string;
@@ -104,4 +41,4 @@ declare function checkSitemap(source: string, options?: SitemapOptions): Promise
104
41
  results: LinkObservation[];
105
42
  }>;
106
43
 
107
- export { type Availability, type CheckOptions, type CheckReport, type FailureReason, type LinkObservation, type LinkTarget, type ReportSiteOptions, type SitemapOptions, checkLinks, checkSitemap, formatReport, parseReport, readReport, readSitemapUrls, saveReport, writeReportSite, writeReports };
44
+ export { Availability, CheckOptions, CheckReport, LinkObservation, LinkTarget, ReportSiteOptions, SitemapOptions, checkLinks, checkSitemap, formatReport, parseReport, readReport, readSitemapUrls, saveReport, writeReportSite, writeReports };
@@ -1,74 +1,11 @@
1
- interface LinkTarget {
2
- url: string;
3
- name?: string;
4
- }
5
- type Availability = 'reachable' | 'restricted' | 'unavailable';
6
- type FailureReason = 'http' | 'dns' | 'tls' | 'timeout' | 'network' | 'redirect';
7
- interface LinkObservation extends LinkTarget {
8
- status: Availability;
9
- checkedAt: string;
10
- durationMs: number;
11
- attempts: number;
12
- finalUrl: string;
13
- httpStatus?: number;
14
- redirects: {
15
- url: string;
16
- status: number;
17
- location: string;
18
- }[];
19
- reason?: FailureReason;
20
- detail?: string;
21
- consecutiveFailures: number;
22
- firstFailureAt?: string;
23
- lastSuccessAt?: string;
24
- changed: boolean;
25
- recovered: boolean;
26
- }
27
- interface CheckReport {
28
- schemaVersion: 1;
29
- observer: string;
30
- startedAt: string;
31
- completedAt: string;
32
- summary: Record<Availability, number> & {
33
- total: number;
34
- redirected: number;
35
- recovered: number;
36
- };
37
- results: LinkObservation[];
38
- }
39
- interface CheckOptions {
40
- /** Maximum simultaneous site checks. Default: 5. */
41
- concurrency?: number;
42
- /** Timeout for each HTTP request, including its body. Default: 10000 ms. */
43
- timeoutMs?: number;
44
- /** Retries for transport errors and 5xx responses. Default: 1; 429 is not retried. */
45
- retries?: number;
46
- /** Maximum followed redirects per attempt. Default: 5. */
47
- maxRedirects?: number;
48
- /** Identifies the network/environment. Must match previousReport.observer. */
49
- observer?: string;
50
- previousReport?: CheckReport;
51
- onResult?: (result: LinkObservation) => void | Promise<void>;
52
- }
53
- interface SitemapOptions extends CheckOptions {
54
- /** Treat the input as a site URL: read robots.txt, falling back to /sitemap.xml. */
55
- discover?: boolean;
56
- /** Reject before page checks if discovery exceeds this many unique pages. Default: 10000. */
57
- maxUrls?: number;
58
- /** Maximum number of unique sitemap documents to read. Default: 100. */
59
- maxSitemaps?: number;
60
- /** Maximum downloaded and decompressed size per discovery document. Default: 10 MiB. */
61
- maxSitemapBytes?: number;
62
- }
1
+ import { L as LinkTarget, a as CheckOptions, C as CheckReport, S as SitemapOptions, A as Availability, b as LinkObservation } from '../shared/meodp.93e06e00.mjs';
2
+ export { F as FailureReason } from '../shared/meodp.93e06e00.mjs';
3
+ import { b as ReportSiteOptions } from '../shared/meodp.a704f8db.mjs';
4
+ export { H as HtmlReporterOptions, a as ReportVerificationOptions, R as ReporterConfig, c as ReporterDescription, d as ReporterName, e as ReporterOptions, f as ReporterOutput, g as waitForReport, w as writeReporters } from '../shared/meodp.a704f8db.mjs';
63
5
 
64
6
  /** Check only the supplied URLs. HTTP failures become observations; invalid input rejects. */
65
7
  declare function checkLinks(input: readonly (string | LinkTarget)[], options?: CheckOptions): Promise<CheckReport>;
66
8
 
67
- interface ReportSiteOptions {
68
- /** Automatically load this HTTP(S) or relative JSON URL when hosted. */
69
- dataUrl?: string;
70
- }
71
-
72
9
  declare function formatReport(report: CheckReport, format?: 'json' | 'markdown' | 'html'): string;
73
10
  declare function writeReports(report: CheckReport, directory: string): Promise<{
74
11
  json: string;
@@ -104,4 +41,4 @@ declare function checkSitemap(source: string, options?: SitemapOptions): Promise
104
41
  results: LinkObservation[];
105
42
  }>;
106
43
 
107
- export { type Availability, type CheckOptions, type CheckReport, type FailureReason, type LinkObservation, type LinkTarget, type ReportSiteOptions, type SitemapOptions, checkLinks, checkSitemap, formatReport, parseReport, readReport, readSitemapUrls, saveReport, writeReportSite, writeReports };
44
+ export { Availability, CheckOptions, CheckReport, LinkObservation, LinkTarget, ReportSiteOptions, SitemapOptions, checkLinks, checkSitemap, formatReport, parseReport, readReport, readSitemapUrls, saveReport, writeReportSite, writeReports };
@@ -1,74 +1,11 @@
1
- interface LinkTarget {
2
- url: string;
3
- name?: string;
4
- }
5
- type Availability = 'reachable' | 'restricted' | 'unavailable';
6
- type FailureReason = 'http' | 'dns' | 'tls' | 'timeout' | 'network' | 'redirect';
7
- interface LinkObservation extends LinkTarget {
8
- status: Availability;
9
- checkedAt: string;
10
- durationMs: number;
11
- attempts: number;
12
- finalUrl: string;
13
- httpStatus?: number;
14
- redirects: {
15
- url: string;
16
- status: number;
17
- location: string;
18
- }[];
19
- reason?: FailureReason;
20
- detail?: string;
21
- consecutiveFailures: number;
22
- firstFailureAt?: string;
23
- lastSuccessAt?: string;
24
- changed: boolean;
25
- recovered: boolean;
26
- }
27
- interface CheckReport {
28
- schemaVersion: 1;
29
- observer: string;
30
- startedAt: string;
31
- completedAt: string;
32
- summary: Record<Availability, number> & {
33
- total: number;
34
- redirected: number;
35
- recovered: number;
36
- };
37
- results: LinkObservation[];
38
- }
39
- interface CheckOptions {
40
- /** Maximum simultaneous site checks. Default: 5. */
41
- concurrency?: number;
42
- /** Timeout for each HTTP request, including its body. Default: 10000 ms. */
43
- timeoutMs?: number;
44
- /** Retries for transport errors and 5xx responses. Default: 1; 429 is not retried. */
45
- retries?: number;
46
- /** Maximum followed redirects per attempt. Default: 5. */
47
- maxRedirects?: number;
48
- /** Identifies the network/environment. Must match previousReport.observer. */
49
- observer?: string;
50
- previousReport?: CheckReport;
51
- onResult?: (result: LinkObservation) => void | Promise<void>;
52
- }
53
- interface SitemapOptions extends CheckOptions {
54
- /** Treat the input as a site URL: read robots.txt, falling back to /sitemap.xml. */
55
- discover?: boolean;
56
- /** Reject before page checks if discovery exceeds this many unique pages. Default: 10000. */
57
- maxUrls?: number;
58
- /** Maximum number of unique sitemap documents to read. Default: 100. */
59
- maxSitemaps?: number;
60
- /** Maximum downloaded and decompressed size per discovery document. Default: 10 MiB. */
61
- maxSitemapBytes?: number;
62
- }
1
+ import { L as LinkTarget, a as CheckOptions, C as CheckReport, S as SitemapOptions, A as Availability, b as LinkObservation } from '../shared/meodp.93e06e00.js';
2
+ export { F as FailureReason } from '../shared/meodp.93e06e00.js';
3
+ import { b as ReportSiteOptions } from '../shared/meodp.8369c4c1.js';
4
+ export { H as HtmlReporterOptions, a as ReportVerificationOptions, R as ReporterConfig, c as ReporterDescription, d as ReporterName, e as ReporterOptions, f as ReporterOutput, g as waitForReport, w as writeReporters } from '../shared/meodp.8369c4c1.js';
63
5
 
64
6
  /** Check only the supplied URLs. HTTP failures become observations; invalid input rejects. */
65
7
  declare function checkLinks(input: readonly (string | LinkTarget)[], options?: CheckOptions): Promise<CheckReport>;
66
8
 
67
- interface ReportSiteOptions {
68
- /** Automatically load this HTTP(S) or relative JSON URL when hosted. */
69
- dataUrl?: string;
70
- }
71
-
72
9
  declare function formatReport(report: CheckReport, format?: 'json' | 'markdown' | 'html'): string;
73
10
  declare function writeReports(report: CheckReport, directory: string): Promise<{
74
11
  json: string;
@@ -104,4 +41,4 @@ declare function checkSitemap(source: string, options?: SitemapOptions): Promise
104
41
  results: LinkObservation[];
105
42
  }>;
106
43
 
107
- export { type Availability, type CheckOptions, type CheckReport, type FailureReason, type LinkObservation, type LinkTarget, type ReportSiteOptions, type SitemapOptions, checkLinks, checkSitemap, formatReport, parseReport, readReport, readSitemapUrls, saveReport, writeReportSite, writeReports };
44
+ export { Availability, CheckOptions, CheckReport, LinkObservation, LinkTarget, ReportSiteOptions, SitemapOptions, checkLinks, checkSitemap, formatReport, parseReport, readReport, readSitemapUrls, saveReport, writeReportSite, writeReports };
@@ -1,11 +1,13 @@
1
- export { a as checkLinks, c as checkSitemap, f as formatReport, p as parseReport, r as readReport, d as readSitemapUrls, s as saveReport, b as writeReportSite, w as writeReports } from '../shared/meodp.d0916bc5.mjs';
1
+ export { a as checkLinks, c as checkSitemap, r as readSitemapUrls, b as waitForReport, w as writeReporters } from '../shared/meodp.80ff918d.mjs';
2
+ export { f as formatReport, p as parseReport, r as readReport, s as saveReport, a as writeReportSite, w as writeReports } from '../shared/meodp.9c706389.mjs';
2
3
  import 'node:timers/promises';
3
4
  import 'linkinator';
4
5
  import 'node:os';
5
- import 'node:crypto';
6
6
  import 'node:fs/promises';
7
7
  import 'node:path';
8
+ import 'node:process';
8
9
  import 'node:buffer';
9
10
  import 'node:util';
10
11
  import 'node:zlib';
11
12
  import 'fast-xml-parser';
13
+ import 'node:crypto';
package/dist/cli/main.cjs CHANGED
@@ -8,7 +8,7 @@ const process__default = /*#__PURE__*/_interopDefaultCompat(process);
8
8
 
9
9
  const name = "meodp";
10
10
  const type = "module";
11
- const version = "0.1.0";
11
+ const version = "0.2.1";
12
12
  const description = "Check website and friend-link availability with sitemap discovery, history, and portable reports.";
13
13
  const author = {
14
14
  name: "YunYouJun",
@@ -47,6 +47,46 @@ const exports$1 = {
47
47
  types: "./dist/check/index.d.cts",
48
48
  "default": "./dist/check/index.cjs"
49
49
  }
50
+ },
51
+ "./config": {
52
+ "import": {
53
+ types: "./dist/config/index.d.mts",
54
+ "default": "./dist/config/index.mjs"
55
+ },
56
+ require: {
57
+ types: "./dist/config/index.d.cts",
58
+ "default": "./dist/config/index.cjs"
59
+ }
60
+ },
61
+ "./notify": {
62
+ "import": {
63
+ types: "./dist/notify/index.d.mts",
64
+ "default": "./dist/notify/index.mjs"
65
+ },
66
+ require: {
67
+ types: "./dist/notify/index.d.cts",
68
+ "default": "./dist/notify/index.cjs"
69
+ }
70
+ },
71
+ "./notify/feishu": {
72
+ "import": {
73
+ types: "./dist/notify/feishu.d.mts",
74
+ "default": "./dist/notify/feishu.mjs"
75
+ },
76
+ require: {
77
+ types: "./dist/notify/feishu.d.cts",
78
+ "default": "./dist/notify/feishu.cjs"
79
+ }
80
+ },
81
+ "./notify/email": {
82
+ "import": {
83
+ types: "./dist/notify/email.d.mts",
84
+ "default": "./dist/notify/email.mjs"
85
+ },
86
+ require: {
87
+ types: "./dist/notify/email.d.cts",
88
+ "default": "./dist/notify/email.cjs"
89
+ }
50
90
  }
51
91
  };
52
92
  const main = "./dist/index.mjs";
@@ -65,17 +105,22 @@ const engines = {
65
105
  const scripts = {
66
106
  build: "tsx scripts/build-report-viewer.ts && unbuild",
67
107
  dev: "tsx scripts/build-report-viewer.ts && unbuild --stub",
68
- test: "tsx scripts/build-report-viewer.ts && tsx --test test/check.test.ts test/sitemap.test.ts",
108
+ test: "tsx scripts/build-report-viewer.ts && tsx --test test/*.test.ts",
69
109
  "test:e2e": "tsx scripts/build-report-viewer.ts && playwright test",
70
110
  typecheck: "tsx scripts/build-report-viewer.ts && tsc --noEmit -p tsconfig.json",
71
111
  prepack: "npm run build",
112
+ "verify:package": "pnpm build && tsx scripts/verify-package.ts",
72
113
  release: "npm version --no-git-tag-version"
73
114
  };
74
115
  const peerDependencies = {
116
+ nodemailer: "^10.0.3",
75
117
  playwright: "^1",
76
118
  typescript: "^5.0.0"
77
119
  };
78
120
  const peerDependenciesMeta = {
121
+ nodemailer: {
122
+ optional: true
123
+ },
79
124
  playwright: {
80
125
  optional: true
81
126
  },
@@ -84,7 +129,7 @@ const peerDependenciesMeta = {
84
129
  }
85
130
  };
86
131
  const dependencies = {
87
- c12: "^2.0.1",
132
+ c12: "^3.3.4",
88
133
  "cli-progress": "^3.12.0",
89
134
  consola: "^3.2.3",
90
135
  "date-fns": "^4.1.0",
@@ -106,9 +151,11 @@ const devDependencies = {
106
151
  "@types/fs-extra": "^11.0.4",
107
152
  "@types/js-yaml": "^4.0.9",
108
153
  "@types/node": "^22.9.0",
154
+ "@types/nodemailer": "^8.0.1",
109
155
  "@types/yargs": "^17.0.33",
110
156
  cilicili: "^0.1.1",
111
157
  esbuild: "^0.28.2",
158
+ nodemailer: "^10.0.3",
112
159
  playwright: "^1.48.2",
113
160
  tsx: "^4.19.2",
114
161
  unbuild: "^2.0.0",
@@ -149,7 +196,8 @@ const help = `Usage: meodp <command> [options]
149
196
  Commands:
150
197
  check <links.json|links.yml> Request listed HTTP(S) URLs and write fresh reports
151
198
  sitemap <sitemap-url> Check pages listed in an XML sitemap or nested index
152
- report [report.json] Export a static viewer from saved data; no site checks
199
+ report [report.json] Render saved data using JSON, Markdown or HTML reporters
200
+ notify Send configured report notifications; supports --dry-run
153
201
  scan [root] Run the legacy browser scanner using meodp.config.ts
154
202
  export [root] Export a legacy browser-scan report
155
203
 
@@ -161,6 +209,7 @@ Examples:
161
209
  meodp check links.yml --output reports/links
162
210
  meodp sitemap https://example.com/sitemap.xml --output reports/pages
163
211
  meodp report reports/links/report.json --output reports/site
212
+ meodp report reports/links/report.json --reporter json,markdown,html
164
213
  meodp check --help
165
214
  meodp help report
166
215
 
@@ -185,10 +234,14 @@ async function runCli(args = process__default.argv.slice(2)) {
185
234
  if (command === "help") {
186
235
  if (!rest.length)
187
236
  return runCli(["--help"]);
188
- if (rest.length !== 1 || !["check", "sitemap", "report", "scan", "export"].includes(rest[0]))
189
- throw new Error("Use meodp help <check|sitemap|report|scan|export>");
237
+ if (rest.length !== 1 || !["check", "sitemap", "report", "notify", "scan", "export"].includes(rest[0]))
238
+ throw new Error("Use meodp help <check|sitemap|report|notify|scan|export>");
190
239
  return runCli([rest[0], "--help"]);
191
240
  }
241
+ if (command === "notify") {
242
+ const { runNotifyCli } = await import('../notify/cli.cjs');
243
+ return runNotifyCli(rest);
244
+ }
192
245
  if (command === "check") {
193
246
  const { runCheckCli } = await import('../check/cli.cjs');
194
247
  return runCheckCli(rest);
package/dist/cli/main.mjs CHANGED
@@ -2,7 +2,7 @@ import process from 'node:process';
2
2
 
3
3
  const name = "meodp";
4
4
  const type = "module";
5
- const version = "0.1.0";
5
+ const version = "0.2.1";
6
6
  const description = "Check website and friend-link availability with sitemap discovery, history, and portable reports.";
7
7
  const author = {
8
8
  name: "YunYouJun",
@@ -41,6 +41,46 @@ const exports = {
41
41
  types: "./dist/check/index.d.cts",
42
42
  "default": "./dist/check/index.cjs"
43
43
  }
44
+ },
45
+ "./config": {
46
+ "import": {
47
+ types: "./dist/config/index.d.mts",
48
+ "default": "./dist/config/index.mjs"
49
+ },
50
+ require: {
51
+ types: "./dist/config/index.d.cts",
52
+ "default": "./dist/config/index.cjs"
53
+ }
54
+ },
55
+ "./notify": {
56
+ "import": {
57
+ types: "./dist/notify/index.d.mts",
58
+ "default": "./dist/notify/index.mjs"
59
+ },
60
+ require: {
61
+ types: "./dist/notify/index.d.cts",
62
+ "default": "./dist/notify/index.cjs"
63
+ }
64
+ },
65
+ "./notify/feishu": {
66
+ "import": {
67
+ types: "./dist/notify/feishu.d.mts",
68
+ "default": "./dist/notify/feishu.mjs"
69
+ },
70
+ require: {
71
+ types: "./dist/notify/feishu.d.cts",
72
+ "default": "./dist/notify/feishu.cjs"
73
+ }
74
+ },
75
+ "./notify/email": {
76
+ "import": {
77
+ types: "./dist/notify/email.d.mts",
78
+ "default": "./dist/notify/email.mjs"
79
+ },
80
+ require: {
81
+ types: "./dist/notify/email.d.cts",
82
+ "default": "./dist/notify/email.cjs"
83
+ }
44
84
  }
45
85
  };
46
86
  const main = "./dist/index.mjs";
@@ -59,17 +99,22 @@ const engines = {
59
99
  const scripts = {
60
100
  build: "tsx scripts/build-report-viewer.ts && unbuild",
61
101
  dev: "tsx scripts/build-report-viewer.ts && unbuild --stub",
62
- test: "tsx scripts/build-report-viewer.ts && tsx --test test/check.test.ts test/sitemap.test.ts",
102
+ test: "tsx scripts/build-report-viewer.ts && tsx --test test/*.test.ts",
63
103
  "test:e2e": "tsx scripts/build-report-viewer.ts && playwright test",
64
104
  typecheck: "tsx scripts/build-report-viewer.ts && tsc --noEmit -p tsconfig.json",
65
105
  prepack: "npm run build",
106
+ "verify:package": "pnpm build && tsx scripts/verify-package.ts",
66
107
  release: "npm version --no-git-tag-version"
67
108
  };
68
109
  const peerDependencies = {
110
+ nodemailer: "^10.0.3",
69
111
  playwright: "^1",
70
112
  typescript: "^5.0.0"
71
113
  };
72
114
  const peerDependenciesMeta = {
115
+ nodemailer: {
116
+ optional: true
117
+ },
73
118
  playwright: {
74
119
  optional: true
75
120
  },
@@ -78,7 +123,7 @@ const peerDependenciesMeta = {
78
123
  }
79
124
  };
80
125
  const dependencies = {
81
- c12: "^2.0.1",
126
+ c12: "^3.3.4",
82
127
  "cli-progress": "^3.12.0",
83
128
  consola: "^3.2.3",
84
129
  "date-fns": "^4.1.0",
@@ -100,9 +145,11 @@ const devDependencies = {
100
145
  "@types/fs-extra": "^11.0.4",
101
146
  "@types/js-yaml": "^4.0.9",
102
147
  "@types/node": "^22.9.0",
148
+ "@types/nodemailer": "^8.0.1",
103
149
  "@types/yargs": "^17.0.33",
104
150
  cilicili: "^0.1.1",
105
151
  esbuild: "^0.28.2",
152
+ nodemailer: "^10.0.3",
106
153
  playwright: "^1.48.2",
107
154
  tsx: "^4.19.2",
108
155
  unbuild: "^2.0.0",
@@ -143,7 +190,8 @@ const help = `Usage: meodp <command> [options]
143
190
  Commands:
144
191
  check <links.json|links.yml> Request listed HTTP(S) URLs and write fresh reports
145
192
  sitemap <sitemap-url> Check pages listed in an XML sitemap or nested index
146
- report [report.json] Export a static viewer from saved data; no site checks
193
+ report [report.json] Render saved data using JSON, Markdown or HTML reporters
194
+ notify Send configured report notifications; supports --dry-run
147
195
  scan [root] Run the legacy browser scanner using meodp.config.ts
148
196
  export [root] Export a legacy browser-scan report
149
197
 
@@ -155,6 +203,7 @@ Examples:
155
203
  meodp check links.yml --output reports/links
156
204
  meodp sitemap https://example.com/sitemap.xml --output reports/pages
157
205
  meodp report reports/links/report.json --output reports/site
206
+ meodp report reports/links/report.json --reporter json,markdown,html
158
207
  meodp check --help
159
208
  meodp help report
160
209
 
@@ -179,10 +228,14 @@ async function runCli(args = process.argv.slice(2)) {
179
228
  if (command === "help") {
180
229
  if (!rest.length)
181
230
  return runCli(["--help"]);
182
- if (rest.length !== 1 || !["check", "sitemap", "report", "scan", "export"].includes(rest[0]))
183
- throw new Error("Use meodp help <check|sitemap|report|scan|export>");
231
+ if (rest.length !== 1 || !["check", "sitemap", "report", "notify", "scan", "export"].includes(rest[0]))
232
+ throw new Error("Use meodp help <check|sitemap|report|notify|scan|export>");
184
233
  return runCli([rest[0], "--help"]);
185
234
  }
235
+ if (command === "notify") {
236
+ const { runNotifyCli } = await import('../notify/cli.mjs');
237
+ return runNotifyCli(rest);
238
+ }
186
239
  if (command === "check") {
187
240
  const { runCheckCli } = await import('../check/cli.mjs');
188
241
  return runCheckCli(rest);
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ function defineConfig(config) {
4
+ return config;
5
+ }
6
+
7
+ exports.defineConfig = defineConfig;
@@ -0,0 +1,47 @@
1
+ import { R as ReporterConfig, a as ReportVerificationOptions } from '../shared/meodp.4f1da070.cjs';
2
+ import { S as SitemapOptions } from '../shared/meodp.93e06e00.cjs';
3
+ import { EmailOptions } from '../notify/email.cjs';
4
+ import { FeishuOptions } from '../notify/feishu.cjs';
5
+ import { NotificationOptions } from '../notify/index.cjs';
6
+
7
+ interface ScanConfig extends Omit<SitemapOptions, 'previousReport' | 'onResult'> {
8
+ input?: string;
9
+ reporter?: ReporterConfig;
10
+ output?: string;
11
+ history?: string;
12
+ /** Seed missing history from a committed snapshot. */
13
+ historySeed?: string;
14
+ observerMismatch?: 'error' | 'reset';
15
+ site?: string;
16
+ failOn?: 'unavailable' | 'review' | 'none';
17
+ }
18
+ interface NotificationConfig extends Omit<NotificationOptions, 'previousReport' | 'mode'> {
19
+ input: string;
20
+ previousReport?: string;
21
+ timeZone?: string;
22
+ maxItems?: number;
23
+ feishu?: FeishuOptions & {
24
+ mode?: NotificationOptions['mode'];
25
+ };
26
+ email?: EmailOptions & {
27
+ mode?: NotificationOptions['mode'];
28
+ };
29
+ }
30
+ interface MeodpConfig {
31
+ /** Shared reporters; command sections may override this selection. */
32
+ reporter?: ReporterConfig;
33
+ check?: ScanConfig;
34
+ sitemap?: ScanConfig;
35
+ report?: {
36
+ reporter?: ReporterConfig;
37
+ input?: string;
38
+ output?: string;
39
+ dataUrl?: string;
40
+ verify?: ReportVerificationOptions;
41
+ };
42
+ notify?: NotificationConfig;
43
+ }
44
+ /** Lightweight configuration entry; importing it does not load browser or mail clients. */
45
+ declare function defineConfig<const T extends MeodpConfig>(config: T): T;
46
+
47
+ export { type MeodpConfig, type NotificationConfig, type ScanConfig, defineConfig };
@@ -0,0 +1,47 @@
1
+ import { R as ReporterConfig, a as ReportVerificationOptions } from '../shared/meodp.a704f8db.mjs';
2
+ import { S as SitemapOptions } from '../shared/meodp.93e06e00.mjs';
3
+ import { EmailOptions } from '../notify/email.mjs';
4
+ import { FeishuOptions } from '../notify/feishu.mjs';
5
+ import { NotificationOptions } from '../notify/index.mjs';
6
+
7
+ interface ScanConfig extends Omit<SitemapOptions, 'previousReport' | 'onResult'> {
8
+ input?: string;
9
+ reporter?: ReporterConfig;
10
+ output?: string;
11
+ history?: string;
12
+ /** Seed missing history from a committed snapshot. */
13
+ historySeed?: string;
14
+ observerMismatch?: 'error' | 'reset';
15
+ site?: string;
16
+ failOn?: 'unavailable' | 'review' | 'none';
17
+ }
18
+ interface NotificationConfig extends Omit<NotificationOptions, 'previousReport' | 'mode'> {
19
+ input: string;
20
+ previousReport?: string;
21
+ timeZone?: string;
22
+ maxItems?: number;
23
+ feishu?: FeishuOptions & {
24
+ mode?: NotificationOptions['mode'];
25
+ };
26
+ email?: EmailOptions & {
27
+ mode?: NotificationOptions['mode'];
28
+ };
29
+ }
30
+ interface MeodpConfig {
31
+ /** Shared reporters; command sections may override this selection. */
32
+ reporter?: ReporterConfig;
33
+ check?: ScanConfig;
34
+ sitemap?: ScanConfig;
35
+ report?: {
36
+ reporter?: ReporterConfig;
37
+ input?: string;
38
+ output?: string;
39
+ dataUrl?: string;
40
+ verify?: ReportVerificationOptions;
41
+ };
42
+ notify?: NotificationConfig;
43
+ }
44
+ /** Lightweight configuration entry; importing it does not load browser or mail clients. */
45
+ declare function defineConfig<const T extends MeodpConfig>(config: T): T;
46
+
47
+ export { type MeodpConfig, type NotificationConfig, type ScanConfig, defineConfig };