@vigilbase/cli 0.1.4 → 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 (142) hide show
  1. package/CLOUDFLARE.md +2 -0
  2. package/COMMANDS.md +43 -6
  3. package/LOCAL.md +731 -0
  4. package/README.md +58 -6
  5. package/dist/auth/device-auth.d.ts.map +1 -1
  6. package/dist/auth/device-auth.js +7 -3
  7. package/dist/auth/device-auth.js.map +1 -1
  8. package/dist/auth/index.d.ts +3 -0
  9. package/dist/auth/index.d.ts.map +1 -1
  10. package/dist/auth/index.js +2 -0
  11. package/dist/auth/index.js.map +1 -1
  12. package/dist/auth/provider.d.ts +18 -0
  13. package/dist/auth/provider.d.ts.map +1 -0
  14. package/dist/auth/provider.js +62 -0
  15. package/dist/auth/provider.js.map +1 -0
  16. package/dist/auth/refresh.d.ts +10 -0
  17. package/dist/auth/refresh.d.ts.map +1 -0
  18. package/dist/auth/refresh.js +143 -0
  19. package/dist/auth/refresh.js.map +1 -0
  20. package/dist/auth/store.d.ts +27 -2
  21. package/dist/auth/store.d.ts.map +1 -1
  22. package/dist/auth/store.js +23 -8
  23. package/dist/auth/store.js.map +1 -1
  24. package/dist/auth/token-metadata.d.ts +10 -0
  25. package/dist/auth/token-metadata.d.ts.map +1 -0
  26. package/dist/auth/token-metadata.js +22 -0
  27. package/dist/auth/token-metadata.js.map +1 -0
  28. package/dist/auth/types.d.ts +8 -1
  29. package/dist/auth/types.d.ts.map +1 -1
  30. package/dist/cli.d.ts.map +1 -1
  31. package/dist/cli.js +40 -9
  32. package/dist/cli.js.map +1 -1
  33. package/dist/commands/auth.d.ts.map +1 -1
  34. package/dist/commands/auth.js +20 -8
  35. package/dist/commands/auth.js.map +1 -1
  36. package/dist/commands/helpers.d.ts +15 -0
  37. package/dist/commands/helpers.d.ts.map +1 -1
  38. package/dist/commands/helpers.js +2 -2
  39. package/dist/commands/helpers.js.map +1 -1
  40. package/dist/commands/index.d.ts +3 -1
  41. package/dist/commands/index.d.ts.map +1 -1
  42. package/dist/commands/index.js +6 -1
  43. package/dist/commands/index.js.map +1 -1
  44. package/dist/commands/local.d.ts +30 -0
  45. package/dist/commands/local.d.ts.map +1 -0
  46. package/dist/commands/local.js +1520 -0
  47. package/dist/commands/local.js.map +1 -0
  48. package/dist/commands/public-tools.d.ts.map +1 -1
  49. package/dist/commands/public-tools.js +8 -4
  50. package/dist/commands/public-tools.js.map +1 -1
  51. package/dist/index.d.ts +2 -1
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +1 -1
  54. package/dist/index.js.map +1 -1
  55. package/dist/lib/config.d.ts +16 -1
  56. package/dist/lib/config.d.ts.map +1 -1
  57. package/dist/lib/config.js +36 -4
  58. package/dist/lib/config.js.map +1 -1
  59. package/dist/lib/format.d.ts.map +1 -1
  60. package/dist/lib/format.js +9 -0
  61. package/dist/lib/format.js.map +1 -1
  62. package/dist/lib/help.d.ts +1 -1
  63. package/dist/lib/help.d.ts.map +1 -1
  64. package/dist/lib/help.js +9 -0
  65. package/dist/lib/help.js.map +1 -1
  66. package/dist/lib/network.d.ts.map +1 -1
  67. package/dist/lib/network.js +2 -1
  68. package/dist/lib/network.js.map +1 -1
  69. package/dist/lib/one-client.d.ts +3 -2
  70. package/dist/lib/one-client.d.ts.map +1 -1
  71. package/dist/lib/one-client.js +46 -2
  72. package/dist/lib/one-client.js.map +1 -1
  73. package/dist/lib/security-client.d.ts +1 -1
  74. package/dist/lib/tui.d.ts +309 -0
  75. package/dist/lib/tui.d.ts.map +1 -0
  76. package/dist/lib/tui.js +847 -0
  77. package/dist/lib/tui.js.map +1 -0
  78. package/dist/local/cloudflare-checkup/cf/allowlist.d.ts +95 -0
  79. package/dist/local/cloudflare-checkup/cf/allowlist.d.ts.map +1 -0
  80. package/dist/local/cloudflare-checkup/cf/allowlist.js +184 -0
  81. package/dist/local/cloudflare-checkup/cf/allowlist.js.map +1 -0
  82. package/dist/local/cloudflare-checkup/cf/auth-lifecycle.d.ts +113 -0
  83. package/dist/local/cloudflare-checkup/cf/auth-lifecycle.d.ts.map +1 -0
  84. package/dist/local/cloudflare-checkup/cf/auth-lifecycle.js +313 -0
  85. package/dist/local/cloudflare-checkup/cf/auth-lifecycle.js.map +1 -0
  86. package/dist/local/cloudflare-checkup/cf/child-env.d.ts +32 -0
  87. package/dist/local/cloudflare-checkup/cf/child-env.d.ts.map +1 -0
  88. package/dist/local/cloudflare-checkup/cf/child-env.js +81 -0
  89. package/dist/local/cloudflare-checkup/cf/child-env.js.map +1 -0
  90. package/dist/local/cloudflare-checkup/cf/install.d.ts +106 -0
  91. package/dist/local/cloudflare-checkup/cf/install.d.ts.map +1 -0
  92. package/dist/local/cloudflare-checkup/cf/install.js +309 -0
  93. package/dist/local/cloudflare-checkup/cf/install.js.map +1 -0
  94. package/dist/local/cloudflare-checkup/cf/locate.d.ts +44 -0
  95. package/dist/local/cloudflare-checkup/cf/locate.d.ts.map +1 -0
  96. package/dist/local/cloudflare-checkup/cf/locate.js +228 -0
  97. package/dist/local/cloudflare-checkup/cf/locate.js.map +1 -0
  98. package/dist/local/cloudflare-checkup/cf/run-cf.d.ts +89 -0
  99. package/dist/local/cloudflare-checkup/cf/run-cf.d.ts.map +1 -0
  100. package/dist/local/cloudflare-checkup/cf/run-cf.js +275 -0
  101. package/dist/local/cloudflare-checkup/cf/run-cf.js.map +1 -0
  102. package/dist/local/cloudflare-checkup/collector.d.ts +48 -0
  103. package/dist/local/cloudflare-checkup/collector.d.ts.map +1 -0
  104. package/dist/local/cloudflare-checkup/collector.js +296 -0
  105. package/dist/local/cloudflare-checkup/collector.js.map +1 -0
  106. package/dist/local/cloudflare-checkup/contract.d.ts +2793 -0
  107. package/dist/local/cloudflare-checkup/contract.d.ts.map +1 -0
  108. package/dist/local/cloudflare-checkup/contract.js +1614 -0
  109. package/dist/local/cloudflare-checkup/contract.js.map +1 -0
  110. package/dist/local/cloudflare-checkup/email-verification.d.ts +125 -0
  111. package/dist/local/cloudflare-checkup/email-verification.d.ts.map +1 -0
  112. package/dist/local/cloudflare-checkup/email-verification.js +212 -0
  113. package/dist/local/cloudflare-checkup/email-verification.js.map +1 -0
  114. package/dist/local/cloudflare-checkup/errors.d.ts +28 -0
  115. package/dist/local/cloudflare-checkup/errors.d.ts.map +1 -0
  116. package/dist/local/cloudflare-checkup/errors.js +99 -0
  117. package/dist/local/cloudflare-checkup/errors.js.map +1 -0
  118. package/dist/local/cloudflare-checkup/output.d.ts +24 -0
  119. package/dist/local/cloudflare-checkup/output.d.ts.map +1 -0
  120. package/dist/local/cloudflare-checkup/output.js +89 -0
  121. package/dist/local/cloudflare-checkup/output.js.map +1 -0
  122. package/dist/local/cloudflare-checkup/prompts.d.ts +41 -0
  123. package/dist/local/cloudflare-checkup/prompts.d.ts.map +1 -0
  124. package/dist/local/cloudflare-checkup/prompts.js +140 -0
  125. package/dist/local/cloudflare-checkup/prompts.js.map +1 -0
  126. package/dist/local/cloudflare-checkup/rate-budget.d.ts +42 -0
  127. package/dist/local/cloudflare-checkup/rate-budget.d.ts.map +1 -0
  128. package/dist/local/cloudflare-checkup/rate-budget.js +80 -0
  129. package/dist/local/cloudflare-checkup/rate-budget.js.map +1 -0
  130. package/dist/local/cloudflare-checkup/snapshot-file.d.ts +53 -0
  131. package/dist/local/cloudflare-checkup/snapshot-file.d.ts.map +1 -0
  132. package/dist/local/cloudflare-checkup/snapshot-file.js +186 -0
  133. package/dist/local/cloudflare-checkup/snapshot-file.js.map +1 -0
  134. package/dist/local/cloudflare-checkup/submit-client.d.ts +98 -0
  135. package/dist/local/cloudflare-checkup/submit-client.d.ts.map +1 -0
  136. package/dist/local/cloudflare-checkup/submit-client.js +349 -0
  137. package/dist/local/cloudflare-checkup/submit-client.js.map +1 -0
  138. package/dist/local/cloudflare-checkup/terminal-ui.d.ts +171 -0
  139. package/dist/local/cloudflare-checkup/terminal-ui.d.ts.map +1 -0
  140. package/dist/local/cloudflare-checkup/terminal-ui.js +404 -0
  141. package/dist/local/cloudflare-checkup/terminal-ui.js.map +1 -0
  142. package/package.json +8 -4
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Stable error codes for `vigilbase cloudflare-checkup` (spec §F8).
3
+ *
4
+ * Every code matches `formatError`'s code pattern. Messages and hints are
5
+ * authored here; cf stderr and Vigilbase server text are never echoed. Hints
6
+ * point at the one command ("run the same command again", `--yes`,
7
+ * `--account-id`), not at the advanced subcommands. The browser
8
+ * troubleshooting accordion mirrors the code set.
9
+ */
10
+ import { CF_TOKEN_ENV } from './cf/child-env.js';
11
+ export const LOCAL_ERROR_CODES = [
12
+ // Environment and cf
13
+ 'NODE_UNSUPPORTED', 'CF_NOT_FOUND', 'CF_WRONG_BINARY', 'CF_UNSUPPORTED_VERSION', 'CF_ALLOWLIST_MISMATCH',
14
+ 'CF_INSTALL_FAILED', 'CF_AUTH_REQUIRED', 'CF_PERMISSION_DENIED', 'CF_RATE_LIMITED', 'CF_ERROR',
15
+ // Account
16
+ 'ACCOUNT_SELECTION_REQUIRED', 'ACCOUNT_NOT_VISIBLE', 'ACCOUNT_TOO_LARGE', 'ACCOUNT_MISMATCH',
17
+ // Files and snapshots
18
+ 'OUTPUT_EXISTS', 'SNAPSHOT_INVALID', 'SNAPSHOT_TOO_LARGE', 'SNAPSHOT_STALE', 'SNAPSHOT_SECRET_LIKE_VALUE',
19
+ // Email verification
20
+ 'EMAIL_INVALID', 'EMAIL_CODE_INVALID', 'VERIFICATION_INVALID', 'VERIFICATION_EXPIRED',
21
+ // Session
22
+ 'SESSION_INVALID', 'SESSION_EXPIRED', 'SESSION_USED', 'SESSION_BUSY', 'SESSION_CLOSED',
23
+ // Submission
24
+ 'SUBMIT_ORIGIN_UNTRUSTED', 'CONFIRMATION_REQUIRED', 'CLI_UPGRADE_REQUIRED', 'LOCAL_MODE_DISABLED',
25
+ 'VIGILBASE_RATE_LIMITED', 'VIGILBASE_CHALLENGED', 'SUBMIT_FAILED',
26
+ ];
27
+ const INSTALL_CF = '`npm install --global cf@1.0.0-beta.13`';
28
+ /** One fix per code; shown after the error and in `--json` as `hint`. */
29
+ export const LOCAL_ERROR_HINTS = {
30
+ NODE_UNSUPPORTED: 'Install Node.js 22.18 or newer from https://nodejs.org (cf runs under the same Node), then run the same command again.',
31
+ CF_NOT_FOUND: `Run the same command again in a terminal and let it install cf (add --yes when no terminal is available), or install it yourself with ${INSTALL_CF}.`,
32
+ CF_WRONG_BINARY: `Another program named cf (for example the Cloud Foundry CLI, or a pnpm or Volta shim) was found. Run the same command again without --cf-bin and let it install cf, or pass --cf-bin "$(npm root -g)/cf".`,
33
+ CF_UNSUPPORTED_VERSION: `Run the same command again without --cf-bin and let it install the tested cf 1.0.0-beta.13, or install it yourself with ${INSTALL_CF}.`,
34
+ // Without --cf-bin the one command offers the managed install itself; the user's own cf is left alone.
35
+ CF_ALLOWLIST_MISMATCH: 'This cf release renamed commands the checkup needs. Run the same command again without --cf-bin and let it install the tested cf 1.0.0-beta.13 for Vigilbase; your own cf is left alone.',
36
+ CF_INSTALL_FAILED: `Install cf yourself with ${INSTALL_CF}, then run the same command again.`,
37
+ CF_AUTH_REQUIRED: `Run the same command again in a terminal to sign in to Cloudflare with a read-only login, or set ${CF_TOKEN_ENV} in this shell first.`,
38
+ CF_PERMISSION_DENIED: 'Your Cloudflare login cannot read this account\'s zones. Check its permissions, then run the same command again.',
39
+ CF_RATE_LIMITED: 'Cloudflare paused your API access. Wait 5 minutes, then run the same command again; add --max-requests-per-5min 600 if it repeats.',
40
+ CF_ERROR: 'Run the same command again in a few minutes. If it persists, contact help@vigilbase.com.',
41
+ ACCOUNT_SELECTION_REQUIRED: 'Run the same command again in a terminal to choose the account, or add --account-id <ACCOUNT_ID> with one of the IDs listed.',
42
+ ACCOUNT_NOT_VISIBLE: 'Check that your Cloudflare user can read the account and its zones, then run the same command again.',
43
+ ACCOUNT_TOO_LARGE: 'Local collection supports up to 100 zones. Use the browser token mode on vigilbase.com instead.',
44
+ ACCOUNT_MISMATCH: 'This checkup is for a different Cloudflare account. Run the same command again without --account-id to start a new checkup.',
45
+ OUTPUT_EXISTS: 'Choose another --out path, or pass --overwrite to replace the file.',
46
+ SNAPSHOT_INVALID: 'The file is not a valid snapshot. Run the same command again to collect a fresh one.',
47
+ SNAPSHOT_TOO_LARGE: 'The snapshot is over the upload limit. Use the browser token mode on vigilbase.com instead.',
48
+ SNAPSHOT_STALE: 'Snapshots are accepted for 24 hours. Run the same command again to collect a fresh one.',
49
+ SNAPSHOT_SECRET_LIKE_VALUE: 'The snapshot contains a value that looks like a credential. Remove it from the Cloudflare rule description or name, then run the same command again.',
50
+ EMAIL_INVALID: 'Use your work email address (personal and disposable addresses are not accepted), then run the same command again.',
51
+ EMAIL_CODE_INVALID: 'Run the same command again to get a new code, and enter the 6 digits from the newest email.',
52
+ VERIFICATION_INVALID: 'Run the same command again to get a new code by email.',
53
+ VERIFICATION_EXPIRED: 'Run the same command again to get a new code by email, and enter it before the time shown.',
54
+ SESSION_INVALID: 'Run the same command again to verify your email and start a new checkup.',
55
+ SESSION_EXPIRED: 'Run the same command again to verify your email and start a new checkup.',
56
+ SESSION_USED: 'This checkup already has results. Run the same command again to start a new checkup.',
57
+ SESSION_BUSY: 'A snapshot for this checkup is still being processed. Wait for the results email, or run the same command again to start a new checkup.',
58
+ SESSION_CLOSED: 'This checkup was cancelled or has expired. Run the same command again to start a new one.',
59
+ SUBMIT_ORIGIN_UNTRUSTED: 'Upload only to https://vigilbase.com (or a loopback origin for local testing).',
60
+ CONFIRMATION_REQUIRED: 'Run the command in a terminal to confirm the upload, or add --yes.',
61
+ CLI_UPGRADE_REQUIRED: 'Run `npx @vigilbase/cli@latest cloudflare-checkup`, or upgrade with `npm install --global @vigilbase/cli@latest`.',
62
+ LOCAL_MODE_DISABLED: 'Local checkups are temporarily unavailable. Use the browser token mode on vigilbase.com, or try later.',
63
+ VIGILBASE_RATE_LIMITED: 'Too many requests to vigilbase.com. Wait as long as the error says (a few minutes if it says nothing), then run the same command again.',
64
+ VIGILBASE_CHALLENGED: 'vigilbase.com asked for a browser challenge. Try another network, or contact help@vigilbase.com.',
65
+ SUBMIT_FAILED: 'Run the same command again in a few minutes. If it persists, contact help@vigilbase.com.',
66
+ };
67
+ /**
68
+ * CF_AUTH_REQUIRED in env mode (`--cf-auth env`, or `auto` with the variable
69
+ * set): the browser sign-in is never offered while the token is used, so the
70
+ * hint names both ways out.
71
+ */
72
+ export const ENV_TOKEN_AUTH_HINT = `Set ${CF_TOKEN_ENV} in this shell to a valid read-only Cloudflare API token (read -rs ${CF_TOKEN_ENV} && export ${CF_TOKEN_ENV}) and run the same command again, or unset it (or use --cf-auth profile) to sign in with your browser instead.`;
73
+ /** CF_PERMISSION_DENIED in env mode: the token lacks a read permission; the browser sign-in is the other way out. */
74
+ export const ENV_TOKEN_PERMISSION_HINT = `The API token in ${CF_TOKEN_ENV} cannot read everything the checkup needs. Add the read permissions to it, or unset it (or use --cf-auth profile) to sign in with your browser instead, then run the same command again.`;
75
+ export class LocalCheckupError extends Error {
76
+ code;
77
+ hint;
78
+ /** HTTP status of the Cloudflare or Vigilbase response, when one caused the error. */
79
+ status;
80
+ retryAfterSec;
81
+ constructor(code, message, options = {}) {
82
+ super(message);
83
+ this.name = 'LocalCheckupError';
84
+ this.code = code;
85
+ this.hint = options.hint ?? LOCAL_ERROR_HINTS[code];
86
+ if (options.status !== undefined)
87
+ this.status = options.status;
88
+ if (options.retryAfterSec !== undefined)
89
+ this.retryAfterSec = options.retryAfterSec;
90
+ }
91
+ /** Mapped to exit code 2 by `runCli`. */
92
+ get isRateLimited() {
93
+ return this.code === 'CF_RATE_LIMITED' || this.code === 'VIGILBASE_RATE_LIMITED';
94
+ }
95
+ }
96
+ export function isLocalCheckupError(error) {
97
+ return error instanceof LocalCheckupError;
98
+ }
99
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { EntryCounts } from './snapshot-file.js';
2
+ /**
3
+ * Untrusted single-line text (account names from cf): controls and line
4
+ * breaks collapsed, length bounded. The terminal UI passes its `ellipsis`
5
+ * (`...` on an ASCII-only console).
6
+ */
7
+ export declare function displayText(value: string, max: number, ellipsis?: string): string;
8
+ /** `0123…cdef` (`0123...cdef` with the ASCII `ellipsis` of the terminal UI). */
9
+ export declare function maskId(id: string, ellipsis?: string): string;
10
+ /** `9f2c…a71e` */
11
+ export declare function shortSha(sha256: string): string;
12
+ export declare function formatBytes(bytes: number): string;
13
+ /** Local `HH:MM` for an ISO timestamp. */
14
+ export declare function formatClock(iso: string): string;
15
+ export declare function formatDuration(seconds: number): string;
16
+ /** `3 reads denied (HTTP 403) · 60 reads not collectable with cf` */
17
+ export declare function readsSummary(counts: EntryCounts, denied: number): string;
18
+ export type CountsProgress = {
19
+ update(text: string): void;
20
+ stop(): void;
21
+ };
22
+ /** A single updating stderr line, or nothing when progress is disabled. */
23
+ export declare function startCountsProgress(enabled: boolean, stream?: NodeJS.WritableStream): CountsProgress;
24
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/output.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAIrD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAG9E;AAED,gFAAgF;AAChF,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAEzD;AAED,kBAAkB;AAClB,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED,0CAA0C;AAC1C,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQxE;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,IAAI,IAAI,IAAI,CAAA;CACb,CAAA;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAE,MAAM,CAAC,cAA+B,GAAG,cAAc,CA0BpH"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Terminal formatting for local checkups. Progress shows counts only, never
3
+ * account or zone names, and is written to stderr. Every other line goes
4
+ * through the CLI writer, which strips terminal controls from untrusted text.
5
+ */
6
+ import { sanitizeTerminal } from '../../lib/format.js';
7
+ const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
8
+ /**
9
+ * Untrusted single-line text (account names from cf): controls and line
10
+ * breaks collapsed, length bounded. The terminal UI passes its `ellipsis`
11
+ * (`...` on an ASCII-only console).
12
+ */
13
+ export function displayText(value, max, ellipsis = '…') {
14
+ const flat = sanitizeTerminal(value.replace(/[\s\u0085\u2028\u2029]+/g, ' ')).trim();
15
+ return flat.length > max ? `${flat.slice(0, Math.max(0, max - ellipsis.length))}${ellipsis}` : flat;
16
+ }
17
+ /** `0123…cdef` (`0123...cdef` with the ASCII `ellipsis` of the terminal UI). */
18
+ export function maskId(id, ellipsis = '…') {
19
+ return id.length > 8 ? `${id.slice(0, 4)}${ellipsis}${id.slice(-4)}` : id;
20
+ }
21
+ /** `9f2c…a71e` */
22
+ export function shortSha(sha256) {
23
+ return `${sha256.slice(0, 4)}…${sha256.slice(-4)}`;
24
+ }
25
+ export function formatBytes(bytes) {
26
+ if (bytes < 1024)
27
+ return `${bytes} B`;
28
+ if (bytes < 1024 * 1024)
29
+ return `${Math.max(1, Math.round(bytes / 1024))} KB`;
30
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
31
+ }
32
+ /** Local `HH:MM` for an ISO timestamp. */
33
+ export function formatClock(iso) {
34
+ const date = new Date(iso);
35
+ if (Number.isNaN(date.getTime()))
36
+ return iso;
37
+ return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
38
+ }
39
+ export function formatDuration(seconds) {
40
+ if (seconds < 90)
41
+ return `~${Math.max(1, Math.round(seconds))} s`;
42
+ return `~${Math.round(seconds / 60)} min`;
43
+ }
44
+ /** `3 reads denied (HTTP 403) · 60 reads not collectable with cf` */
45
+ export function readsSummary(counts, denied) {
46
+ const parts = [];
47
+ if (denied > 0)
48
+ parts.push(`${denied} ${denied === 1 ? 'read' : 'reads'} denied (HTTP 403)`);
49
+ const otherHttp = counts.httpError - denied;
50
+ if (otherHttp > 0)
51
+ parts.push(`${otherHttp} ${otherHttp === 1 ? 'read' : 'reads'} failed with another HTTP error`);
52
+ if (counts.collectionFailed > 0)
53
+ parts.push(`${counts.collectionFailed} ${counts.collectionFailed === 1 ? 'read' : 'reads'} could not be collected`);
54
+ if (counts.notCollected > 0)
55
+ parts.push(`${counts.notCollected} reads not collectable with cf`);
56
+ return parts.join(' · ');
57
+ }
58
+ /** A single updating stderr line, or nothing when progress is disabled. */
59
+ export function startCountsProgress(enabled, stream = process.stderr) {
60
+ if (!enabled)
61
+ return { update: () => undefined, stop: () => undefined };
62
+ let text = '';
63
+ let frame = 0;
64
+ let closed = false;
65
+ let width = 0;
66
+ const draw = () => {
67
+ if (closed)
68
+ return;
69
+ const line = `${SPINNER[frame++ % SPINNER.length]} ${sanitizeTerminal(text).replace(/[\n\t]/g, ' ')}`;
70
+ width = Math.max(width, line.length);
71
+ stream.write(`\r${line.padEnd(width)}`);
72
+ };
73
+ const timer = setInterval(draw, 80);
74
+ timer.unref?.();
75
+ return {
76
+ update(next) {
77
+ text = next;
78
+ draw();
79
+ },
80
+ stop() {
81
+ if (closed)
82
+ return;
83
+ closed = true;
84
+ clearInterval(timer);
85
+ stream.write(`\r${' '.repeat(width)}\r`);
86
+ },
87
+ };
88
+ }
89
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /** One piped answer is at most this long (an email address is at most 254 bytes). */
2
+ export declare const MAX_ANSWER_BYTES = 256;
3
+ export type PromptIO = {
4
+ stdin?: NodeJS.ReadableStream;
5
+ stderr: NodeJS.WritableStream;
6
+ };
7
+ export declare function hasInteractiveInput(stdin: NodeJS.ReadableStream | undefined): boolean;
8
+ /**
9
+ * A visible one-line prompt on a TTY (account picker, confirmations): the
10
+ * trimmed answer, or null when the input ended (Ctrl-D) before one.
11
+ */
12
+ export declare function promptLine(io: PromptIO, label: string): Promise<string | null>;
13
+ /**
14
+ * One line of piped input, without consuming the next one: whatever follows
15
+ * the newline is pushed back onto the stream for the next prompt. Bytes past
16
+ * `MAX_ANSWER_BYTES` are dropped up to the newline, so an overlong line comes
17
+ * back too long and fails validation. Null at the end of the input.
18
+ */
19
+ export declare function readPipedLine(stdin: NodeJS.ReadableStream): Promise<string | null>;
20
+ /**
21
+ * A visible prompt for the email verification. On a terminal it is
22
+ * `promptLine`; without one the label still goes to stderr and the answer is
23
+ * one line of piped stdin. Null when the input ended without an answer.
24
+ */
25
+ export declare function promptAnswer(io: PromptIO, label: string): Promise<string | null>;
26
+ /**
27
+ * `[y/N]` upload confirmation: an explicit `y` is required. `--yes` (or its
28
+ * alias `--confirm`) answers yes; without a terminal and without them it is
29
+ * CONFIRMATION_REQUIRED.
30
+ */
31
+ export declare function confirmUpload(io: PromptIO, question: string, options: {
32
+ isConfirmed: boolean;
33
+ flag?: string;
34
+ }): Promise<boolean>;
35
+ /**
36
+ * `[Y/n]` question where Enter means yes (installing cf). The caller handles
37
+ * `--yes` and the no-terminal case; an input that ends before an answer is
38
+ * CONFIRMATION_REQUIRED.
39
+ */
40
+ export declare function confirmDefaultYes(io: PromptIO, question: string): Promise<boolean>;
41
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/prompts.ts"],"names":[],"mappings":"AAcA,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAEnC,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAA;IAC7B,MAAM,EAAE,MAAM,CAAC,cAAc,CAAA;CAC9B,CAAA;AAQD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG,SAAS,GAAG,OAAO,CAErF;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBpF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiClF;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOtF;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAWtI;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAIxF"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Prompts and confirmations of local checkups.
3
+ *
4
+ * Every prompt goes to stderr, so `--json` keeps stdout one JSON object. On a
5
+ * terminal, answers are typed at a visible prompt. Without one, only the email
6
+ * verification reads its answers (the work email without `--email`, and the
7
+ * emailed code) from piped stdin, one line each, so a script can write the code
8
+ * once it sees the prompt; every other question needs a flag (`--yes`,
9
+ * `--account-id`). What is read is never echoed in errors.
10
+ */
11
+ import { createInterface } from 'node:readline/promises';
12
+ import { LocalCheckupError } from './errors.js';
13
+ /** One piped answer is at most this long (an email address is at most 254 bytes). */
14
+ export const MAX_ANSWER_BYTES = 256;
15
+ function isTty(stream) {
16
+ return Boolean(stream && stream.isTTY);
17
+ }
18
+ export function hasInteractiveInput(stdin) {
19
+ return isTty(stdin);
20
+ }
21
+ /**
22
+ * A visible one-line prompt on a TTY (account picker, confirmations): the
23
+ * trimmed answer, or null when the input ended (Ctrl-D) before one.
24
+ */
25
+ export async function promptLine(io, label) {
26
+ if (!isTty(io.stdin)) {
27
+ throw new LocalCheckupError('CONFIRMATION_REQUIRED', 'No terminal is available for this prompt.', { hint: 'Run the command in a terminal, or pass the answer as a flag (--account-id, --yes).' });
28
+ }
29
+ if (io.stdin.readableEnded)
30
+ return null;
31
+ const rl = createInterface({ input: io.stdin, output: io.stderr, terminal: false });
32
+ // readline's question() never settles once the input ends; the interface's 'close' does.
33
+ const ended = new Promise((resolve) => rl.once('close', () => resolve(null)));
34
+ try {
35
+ const answer = await Promise.race([rl.question(label).catch(() => null), ended]);
36
+ if (answer !== null)
37
+ return answer.trim();
38
+ // Ctrl-D leaves the cursor on the prompt line.
39
+ io.stderr.write('\n');
40
+ return null;
41
+ }
42
+ finally {
43
+ rl.close();
44
+ }
45
+ }
46
+ /**
47
+ * One line of piped input, without consuming the next one: whatever follows
48
+ * the newline is pushed back onto the stream for the next prompt. Bytes past
49
+ * `MAX_ANSWER_BYTES` are dropped up to the newline, so an overlong line comes
50
+ * back too long and fails validation. Null at the end of the input.
51
+ */
52
+ export function readPipedLine(stdin) {
53
+ const stream = stdin;
54
+ if (stream.readableEnded)
55
+ return Promise.resolve(null);
56
+ return new Promise((resolve, reject) => {
57
+ let kept = Buffer.alloc(0);
58
+ let settled = false;
59
+ const finish = (error, line, rest) => {
60
+ if (settled)
61
+ return;
62
+ settled = true;
63
+ stream.removeListener('readable', onReadable);
64
+ stream.removeListener('end', onEnd);
65
+ stream.removeListener('error', onError);
66
+ if (rest && rest.byteLength > 0)
67
+ stream.unshift(rest);
68
+ if (error)
69
+ reject(error);
70
+ else
71
+ resolve(line === null ? null : line.toString('utf8').replace(/\r$/, ''));
72
+ };
73
+ const onReadable = () => {
74
+ let chunk;
75
+ while (!settled && (chunk = stream.read()) !== null) {
76
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
77
+ const newline = bytes.indexOf(0x0a);
78
+ const head = newline >= 0 ? bytes.subarray(0, newline) : bytes;
79
+ if (kept.byteLength <= MAX_ANSWER_BYTES)
80
+ kept = Buffer.concat([kept, head.subarray(0, MAX_ANSWER_BYTES + 1 - kept.byteLength)]);
81
+ if (newline >= 0)
82
+ finish(null, kept, bytes.subarray(newline + 1));
83
+ }
84
+ };
85
+ const onEnd = () => finish(null, kept.byteLength > 0 ? kept : null);
86
+ const onError = (error) => finish(error, null);
87
+ stream.on('readable', onReadable);
88
+ stream.on('end', onEnd);
89
+ stream.on('error', onError);
90
+ onReadable();
91
+ });
92
+ }
93
+ /**
94
+ * A visible prompt for the email verification. On a terminal it is
95
+ * `promptLine`; without one the label still goes to stderr and the answer is
96
+ * one line of piped stdin. Null when the input ended without an answer.
97
+ */
98
+ export async function promptAnswer(io, label) {
99
+ if (isTty(io.stdin))
100
+ return promptLine(io, label);
101
+ io.stderr.write(label);
102
+ const line = io.stdin ? await readPipedLine(io.stdin) : null;
103
+ // A piped answer is not echoed by a terminal; end the prompt line.
104
+ io.stderr.write('\n');
105
+ return line === null ? null : line.trim();
106
+ }
107
+ /**
108
+ * `[y/N]` upload confirmation: an explicit `y` is required. `--yes` (or its
109
+ * alias `--confirm`) answers yes; without a terminal and without them it is
110
+ * CONFIRMATION_REQUIRED.
111
+ */
112
+ export async function confirmUpload(io, question, options) {
113
+ if (options.isConfirmed) {
114
+ io.stderr.write(`${question} [y/N] y (${options.flag ?? '--yes'})\n`);
115
+ return true;
116
+ }
117
+ if (!isTty(io.stdin)) {
118
+ throw new LocalCheckupError('CONFIRMATION_REQUIRED', 'Uploading needs confirmation, and no terminal is available to ask.');
119
+ }
120
+ const answer = await promptLine(io, `${question} [y/N] `);
121
+ if (answer === null)
122
+ throw inputEnded('Uploading needs confirmation, and the input ended before an answer.');
123
+ return /^y(?:es)?$/i.test(answer);
124
+ }
125
+ /**
126
+ * `[Y/n]` question where Enter means yes (installing cf). The caller handles
127
+ * `--yes` and the no-terminal case; an input that ends before an answer is
128
+ * CONFIRMATION_REQUIRED.
129
+ */
130
+ export async function confirmDefaultYes(io, question) {
131
+ const answer = await promptLine(io, `${question} [Y/n] `);
132
+ if (answer === null)
133
+ throw inputEnded('The question needs an answer, and the input ended before one.');
134
+ return answer === '' || /^y(?:es)?$/i.test(answer);
135
+ }
136
+ /** Ctrl-D at a confirmation: nothing was confirmed. */
137
+ function inputEnded(message) {
138
+ return new LocalCheckupError('CONFIRMATION_REQUIRED', message, { hint: 'Run the same command again and answer the question, or add --yes.' });
139
+ }
140
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/prompts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Cloudflare request budget (spec §F5).
3
+ *
4
+ * Cloudflare allows 1,200 API requests per user per rolling 5 minutes, shared
5
+ * with the user's dashboard; going over blocks every API call for 5 minutes.
6
+ * The default spends at most 900 per rolling 5 minutes (configurable 100 to
7
+ * 1,100). A token bucket with capacity `burst` that refills at
8
+ * `(limit − burst) / 300 s` never admits more than `limit` calls in any
9
+ * 300-second window: at most `burst` from the full bucket plus the refill.
10
+ * Local `--version` and `--dry-run` calls are free.
11
+ */
12
+ export declare const DEFAULT_REQUESTS_PER_5MIN = 900;
13
+ export declare const MIN_REQUESTS_PER_5MIN = 100;
14
+ export declare const MAX_REQUESTS_PER_5MIN = 1100;
15
+ export declare const BUDGET_BURST = 8;
16
+ export declare const BUDGET_WINDOW_MS = 300000;
17
+ export type Clock = {
18
+ now(): number;
19
+ sleep(ms: number): Promise<void>;
20
+ };
21
+ export declare const systemClock: Clock;
22
+ export declare function parseRequestBudget(raw: string | undefined): number;
23
+ export declare class RequestBudget {
24
+ readonly limit: number;
25
+ private readonly clock;
26
+ readonly burst: number;
27
+ private tokens;
28
+ private updatedAt;
29
+ private readonly refillPerMs;
30
+ private queue;
31
+ constructor(limit?: number, clock?: Clock, burst?: number);
32
+ private refill;
33
+ /** Tokens available now (fractional). */
34
+ available(): number;
35
+ /** Wait for one request slot. Callers are served in order. */
36
+ acquire(): Promise<void>;
37
+ /** Seconds the bucket needs for `requests` calls, ignoring network latency. */
38
+ estimateSeconds(requests: number): number;
39
+ }
40
+ /** Seconds a full bucket needs to admit `requests` calls at `limit` per 5 minutes. */
41
+ export declare function estimateBudgetSeconds(limit: number, requests: number, burst?: number): number;
42
+ //# sourceMappingURL=rate-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-budget.d.ts","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/rate-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,yBAAyB,MAAM,CAAA;AAC5C,eAAO,MAAM,qBAAqB,MAAM,CAAA;AACxC,eAAO,MAAM,qBAAqB,OAAQ,CAAA;AAC1C,eAAO,MAAM,YAAY,IAAI,CAAA;AAC7B,eAAO,MAAM,gBAAgB,SAAU,CAAA;AAEvC,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,IAAI,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACjC,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,KAGzB,CAAA;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOlE;AAED,qBAAa,aAAa;IAMZ,QAAQ,CAAC,KAAK,EAAE,MAAM;IAA8B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAuB,QAAQ,CAAC,KAAK,EAAE,MAAM;IALnI,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,KAAK,CAAmC;gBAE3B,KAAK,GAAE,MAAkC,EAAmB,KAAK,GAAE,KAAmB,EAAW,KAAK,GAAE,MAAqB;IAOlJ,OAAO,CAAC,MAAM;IAMd,yCAAyC;IACzC,SAAS,IAAI,MAAM;IAKnB,8DAA8D;IAC9D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAaxB,+EAA+E;IAC/E,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAG1C;AAED,sFAAsF;AACtF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAqB,GAAG,MAAM,CAE3G"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Cloudflare request budget (spec §F5).
3
+ *
4
+ * Cloudflare allows 1,200 API requests per user per rolling 5 minutes, shared
5
+ * with the user's dashboard; going over blocks every API call for 5 minutes.
6
+ * The default spends at most 900 per rolling 5 minutes (configurable 100 to
7
+ * 1,100). A token bucket with capacity `burst` that refills at
8
+ * `(limit − burst) / 300 s` never admits more than `limit` calls in any
9
+ * 300-second window: at most `burst` from the full bucket plus the refill.
10
+ * Local `--version` and `--dry-run` calls are free.
11
+ */
12
+ export const DEFAULT_REQUESTS_PER_5MIN = 900;
13
+ export const MIN_REQUESTS_PER_5MIN = 100;
14
+ export const MAX_REQUESTS_PER_5MIN = 1_100;
15
+ export const BUDGET_BURST = 8;
16
+ export const BUDGET_WINDOW_MS = 300_000;
17
+ export const systemClock = {
18
+ now: () => Date.now(),
19
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
20
+ };
21
+ export function parseRequestBudget(raw) {
22
+ if (raw === undefined)
23
+ return DEFAULT_REQUESTS_PER_5MIN;
24
+ const value = Number(raw);
25
+ if (!/^\d+$/.test(raw) || !Number.isSafeInteger(value) || value < MIN_REQUESTS_PER_5MIN || value > MAX_REQUESTS_PER_5MIN) {
26
+ throw new Error(`--max-requests-per-5min must be an integer between ${MIN_REQUESTS_PER_5MIN} and ${MAX_REQUESTS_PER_5MIN}.`);
27
+ }
28
+ return value;
29
+ }
30
+ export class RequestBudget {
31
+ limit;
32
+ clock;
33
+ burst;
34
+ tokens;
35
+ updatedAt;
36
+ refillPerMs;
37
+ queue = Promise.resolve();
38
+ constructor(limit = DEFAULT_REQUESTS_PER_5MIN, clock = systemClock, burst = BUDGET_BURST) {
39
+ this.limit = limit;
40
+ this.clock = clock;
41
+ this.burst = burst;
42
+ if (!(limit > burst))
43
+ throw new Error('The request budget must exceed the burst size.');
44
+ this.tokens = burst;
45
+ this.updatedAt = clock.now();
46
+ this.refillPerMs = (limit - burst) / BUDGET_WINDOW_MS;
47
+ }
48
+ refill() {
49
+ const now = this.clock.now();
50
+ this.tokens = Math.min(this.burst, this.tokens + (now - this.updatedAt) * this.refillPerMs);
51
+ this.updatedAt = now;
52
+ }
53
+ /** Tokens available now (fractional). */
54
+ available() {
55
+ this.refill();
56
+ return this.tokens;
57
+ }
58
+ /** Wait for one request slot. Callers are served in order. */
59
+ acquire() {
60
+ const next = this.queue.then(async () => {
61
+ this.refill();
62
+ while (this.tokens < 1) {
63
+ await this.clock.sleep(Math.max(1, Math.ceil((1 - this.tokens) / this.refillPerMs)));
64
+ this.refill();
65
+ }
66
+ this.tokens -= 1;
67
+ });
68
+ this.queue = next.catch(() => undefined);
69
+ return next;
70
+ }
71
+ /** Seconds the bucket needs for `requests` calls, ignoring network latency. */
72
+ estimateSeconds(requests) {
73
+ return estimateBudgetSeconds(this.limit, requests, this.burst);
74
+ }
75
+ }
76
+ /** Seconds a full bucket needs to admit `requests` calls at `limit` per 5 minutes. */
77
+ export function estimateBudgetSeconds(limit, requests, burst = BUDGET_BURST) {
78
+ return Math.max(0, ((requests - burst) * BUDGET_WINDOW_MS) / (limit - burst) / 1000);
79
+ }
80
+ //# sourceMappingURL=rate-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-budget.js","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/rate-budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { type CloudflareCheckupSnapshotV1, type SnapshotEntry } from './contract.js';
2
+ import { LocalCheckupError } from './errors.js';
3
+ export declare function sha256Hex(bytes: Uint8Array | string): string;
4
+ /** Write the snapshot; refuses an existing file unless `overwrite` (atomic rename). */
5
+ export declare function writeSnapshotFile(path: string, text: string, options: {
6
+ overwrite: boolean;
7
+ }): Promise<{
8
+ bytes: number;
9
+ sha256: string;
10
+ }>;
11
+ export type LoadedSnapshot = {
12
+ path: string;
13
+ bytes: Buffer;
14
+ sha256: string;
15
+ snapshot: CloudflareCheckupSnapshotV1;
16
+ };
17
+ /** Map a failed contract parse to the CLI error (no values, issue codes only). */
18
+ export declare function snapshotParseError(issues: ReadonlyArray<{
19
+ code?: string;
20
+ message?: string;
21
+ path?: ReadonlyArray<PropertyKey>;
22
+ params?: unknown;
23
+ }>): LocalCheckupError;
24
+ /** Read, hash and validate a snapshot file against the vendored contract. */
25
+ export declare function loadSnapshotFile(path: string): Promise<LoadedSnapshot>;
26
+ export type EntryCounts = {
27
+ total: number;
28
+ ok: number;
29
+ httpError: number;
30
+ notCollected: number;
31
+ collectionFailed: number;
32
+ };
33
+ export declare function countEntries(entries: readonly SnapshotEntry[]): EntryCounts;
34
+ export type EntryKindCounts = Record<string, {
35
+ total: number;
36
+ ok: number;
37
+ httpError: number;
38
+ notCollected: number;
39
+ collectionFailed: number;
40
+ }>;
41
+ export declare function countEntriesByKind(entries: readonly SnapshotEntry[]): EntryKindCounts;
42
+ /** Counts of every free-text or identifying category the snapshot carries (`inspect`). */
43
+ export type DataCategories = {
44
+ memberEmails: number;
45
+ accessRuleValues: number;
46
+ dnsHostnames: number;
47
+ pseudonymizedIps: number;
48
+ ruleDescriptions: number;
49
+ };
50
+ export declare function dataCategories(snapshot: CloudflareCheckupSnapshotV1): DataCategories;
51
+ export declare function zoneCount(snapshot: CloudflareCheckupSnapshotV1): number;
52
+ export declare function accountName(snapshot: CloudflareCheckupSnapshotV1): string | null;
53
+ //# sourceMappingURL=snapshot-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-file.d.ts","sourceRoot":"","sources":["../../../src/local/cloudflare-checkup/snapshot-file.ts"],"names":[],"mappings":"AAcA,OAAO,EAOL,KAAK,2BAA2B,EAChC,KAAK,aAAa,EACnB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE/C,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAE5D;AAiCD,uFAAuF;AACvF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAsB/I;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,2BAA2B,CAAA;CACtC,CAAA;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,iBAAiB,CAOrK;AAED,6EAA6E;AAC7E,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAkB5E;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1H,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,WAAW,CAU3E;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAE9I,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,eAAe,CAarF;AAED,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,2BAA2B,GAAG,cAAc,CA4BpF;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM,CAGvE;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM,GAAG,IAAI,CAGhF"}