meodp 0.1.0 → 0.2.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 (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 +57 -5
  10. package/dist/cli/main.mjs +57 -5
  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 +48 -2
@@ -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.0";
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,21 @@ 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",
72
112
  release: "npm version --no-git-tag-version"
73
113
  };
74
114
  const peerDependencies = {
115
+ nodemailer: "^10.0.3",
75
116
  playwright: "^1",
76
117
  typescript: "^5.0.0"
77
118
  };
78
119
  const peerDependenciesMeta = {
120
+ nodemailer: {
121
+ optional: true
122
+ },
79
123
  playwright: {
80
124
  optional: true
81
125
  },
@@ -106,9 +150,11 @@ const devDependencies = {
106
150
  "@types/fs-extra": "^11.0.4",
107
151
  "@types/js-yaml": "^4.0.9",
108
152
  "@types/node": "^22.9.0",
153
+ "@types/nodemailer": "^8.0.1",
109
154
  "@types/yargs": "^17.0.33",
110
155
  cilicili: "^0.1.1",
111
156
  esbuild: "^0.28.2",
157
+ nodemailer: "^10.0.3",
112
158
  playwright: "^1.48.2",
113
159
  tsx: "^4.19.2",
114
160
  unbuild: "^2.0.0",
@@ -149,7 +195,8 @@ const help = `Usage: meodp <command> [options]
149
195
  Commands:
150
196
  check <links.json|links.yml> Request listed HTTP(S) URLs and write fresh reports
151
197
  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
198
+ report [report.json] Render saved data using JSON, Markdown or HTML reporters
199
+ notify Send configured report notifications; supports --dry-run
153
200
  scan [root] Run the legacy browser scanner using meodp.config.ts
154
201
  export [root] Export a legacy browser-scan report
155
202
 
@@ -161,6 +208,7 @@ Examples:
161
208
  meodp check links.yml --output reports/links
162
209
  meodp sitemap https://example.com/sitemap.xml --output reports/pages
163
210
  meodp report reports/links/report.json --output reports/site
211
+ meodp report reports/links/report.json --reporter json,markdown,html
164
212
  meodp check --help
165
213
  meodp help report
166
214
 
@@ -185,10 +233,14 @@ async function runCli(args = process__default.argv.slice(2)) {
185
233
  if (command === "help") {
186
234
  if (!rest.length)
187
235
  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>");
236
+ if (rest.length !== 1 || !["check", "sitemap", "report", "notify", "scan", "export"].includes(rest[0]))
237
+ throw new Error("Use meodp help <check|sitemap|report|notify|scan|export>");
190
238
  return runCli([rest[0], "--help"]);
191
239
  }
240
+ if (command === "notify") {
241
+ const { runNotifyCli } = await import('../notify/cli.cjs');
242
+ return runNotifyCli(rest);
243
+ }
192
244
  if (command === "check") {
193
245
  const { runCheckCli } = await import('../check/cli.cjs');
194
246
  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.0";
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,21 @@ 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",
66
106
  release: "npm version --no-git-tag-version"
67
107
  };
68
108
  const peerDependencies = {
109
+ nodemailer: "^10.0.3",
69
110
  playwright: "^1",
70
111
  typescript: "^5.0.0"
71
112
  };
72
113
  const peerDependenciesMeta = {
114
+ nodemailer: {
115
+ optional: true
116
+ },
73
117
  playwright: {
74
118
  optional: true
75
119
  },
@@ -100,9 +144,11 @@ const devDependencies = {
100
144
  "@types/fs-extra": "^11.0.4",
101
145
  "@types/js-yaml": "^4.0.9",
102
146
  "@types/node": "^22.9.0",
147
+ "@types/nodemailer": "^8.0.1",
103
148
  "@types/yargs": "^17.0.33",
104
149
  cilicili: "^0.1.1",
105
150
  esbuild: "^0.28.2",
151
+ nodemailer: "^10.0.3",
106
152
  playwright: "^1.48.2",
107
153
  tsx: "^4.19.2",
108
154
  unbuild: "^2.0.0",
@@ -143,7 +189,8 @@ const help = `Usage: meodp <command> [options]
143
189
  Commands:
144
190
  check <links.json|links.yml> Request listed HTTP(S) URLs and write fresh reports
145
191
  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
192
+ report [report.json] Render saved data using JSON, Markdown or HTML reporters
193
+ notify Send configured report notifications; supports --dry-run
147
194
  scan [root] Run the legacy browser scanner using meodp.config.ts
148
195
  export [root] Export a legacy browser-scan report
149
196
 
@@ -155,6 +202,7 @@ Examples:
155
202
  meodp check links.yml --output reports/links
156
203
  meodp sitemap https://example.com/sitemap.xml --output reports/pages
157
204
  meodp report reports/links/report.json --output reports/site
205
+ meodp report reports/links/report.json --reporter json,markdown,html
158
206
  meodp check --help
159
207
  meodp help report
160
208
 
@@ -179,10 +227,14 @@ async function runCli(args = process.argv.slice(2)) {
179
227
  if (command === "help") {
180
228
  if (!rest.length)
181
229
  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>");
230
+ if (rest.length !== 1 || !["check", "sitemap", "report", "notify", "scan", "export"].includes(rest[0]))
231
+ throw new Error("Use meodp help <check|sitemap|report|notify|scan|export>");
184
232
  return runCli([rest[0], "--help"]);
185
233
  }
234
+ if (command === "notify") {
235
+ const { runNotifyCli } = await import('../notify/cli.mjs');
236
+ return runNotifyCli(rest);
237
+ }
186
238
  if (command === "check") {
187
239
  const { runCheckCli } = await import('../check/cli.mjs');
188
240
  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 };
@@ -0,0 +1,47 @@
1
+ import { R as ReporterConfig, a as ReportVerificationOptions } from '../shared/meodp.8369c4c1.js';
2
+ import { S as SitemapOptions } from '../shared/meodp.93e06e00.js';
3
+ import { EmailOptions } from '../notify/email.js';
4
+ import { FeishuOptions } from '../notify/feishu.js';
5
+ import { NotificationOptions } from '../notify/index.js';
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 };