dungbeetle 0.1.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 (116) hide show
  1. package/LICENSE +105 -0
  2. package/NOTICE +19 -0
  3. package/README.md +139 -0
  4. package/dist/api/capture.d.ts +24 -0
  5. package/dist/api/capture.js +61 -0
  6. package/dist/baselines.d.ts +7 -0
  7. package/dist/baselines.js +38 -0
  8. package/dist/brand.d.ts +2 -0
  9. package/dist/brand.js +9 -0
  10. package/dist/capture.d.ts +15 -0
  11. package/dist/capture.js +7 -0
  12. package/dist/captures/api.d.ts +2 -0
  13. package/dist/captures/api.js +114 -0
  14. package/dist/captures/check.d.ts +2 -0
  15. package/dist/captures/check.js +116 -0
  16. package/dist/captures/desktop.d.ts +2 -0
  17. package/dist/captures/desktop.js +97 -0
  18. package/dist/captures/game.d.ts +4 -0
  19. package/dist/captures/game.js +266 -0
  20. package/dist/captures/performance.d.ts +2 -0
  21. package/dist/captures/performance.js +47 -0
  22. package/dist/captures/registry.d.ts +4 -0
  23. package/dist/captures/registry.js +23 -0
  24. package/dist/captures/terminal.d.ts +2 -0
  25. package/dist/captures/terminal.js +65 -0
  26. package/dist/captures/types.d.ts +18 -0
  27. package/dist/captures/types.js +1 -0
  28. package/dist/captures/web.d.ts +3 -0
  29. package/dist/captures/web.js +248 -0
  30. package/dist/check/capture.d.ts +15 -0
  31. package/dist/check/capture.js +76 -0
  32. package/dist/check/junit.d.ts +9 -0
  33. package/dist/check/junit.js +51 -0
  34. package/dist/check/laravel.d.ts +2 -0
  35. package/dist/check/laravel.js +44 -0
  36. package/dist/check/parsers.d.ts +12 -0
  37. package/dist/check/parsers.js +278 -0
  38. package/dist/check/schema.d.ts +2 -0
  39. package/dist/check/schema.js +114 -0
  40. package/dist/cloud.d.ts +42 -0
  41. package/dist/cloud.js +334 -0
  42. package/dist/compare/shared.d.ts +42 -0
  43. package/dist/compare/shared.js +115 -0
  44. package/dist/compare.d.ts +3 -0
  45. package/dist/compare.js +33 -0
  46. package/dist/config.d.ts +146 -0
  47. package/dist/config.js +382 -0
  48. package/dist/desktop/a11y.d.ts +18 -0
  49. package/dist/desktop/a11y.js +74 -0
  50. package/dist/desktop/capture.d.ts +13 -0
  51. package/dist/desktop/capture.js +80 -0
  52. package/dist/desktop/macos.d.ts +8 -0
  53. package/dist/desktop/macos.js +98 -0
  54. package/dist/desktop/ocr.d.ts +17 -0
  55. package/dist/desktop/ocr.js +99 -0
  56. package/dist/diff/lcs.d.ts +5 -0
  57. package/dist/diff/lcs.js +42 -0
  58. package/dist/diff/numeric.d.ts +6 -0
  59. package/dist/diff/numeric.js +24 -0
  60. package/dist/diff/pixel.d.ts +23 -0
  61. package/dist/diff/pixel.js +97 -0
  62. package/dist/diff/structural.d.ts +11 -0
  63. package/dist/diff/structural.js +38 -0
  64. package/dist/diff/text.d.ts +7 -0
  65. package/dist/diff/text.js +64 -0
  66. package/dist/diff/tree.d.ts +46 -0
  67. package/dist/diff/tree.js +188 -0
  68. package/dist/doctor.d.ts +18 -0
  69. package/dist/doctor.js +57 -0
  70. package/dist/game/capture.d.ts +24 -0
  71. package/dist/game/capture.js +51 -0
  72. package/dist/game/protocol.d.ts +30 -0
  73. package/dist/game/protocol.js +146 -0
  74. package/dist/game/walkthrough.d.ts +45 -0
  75. package/dist/game/walkthrough.js +85 -0
  76. package/dist/guards.d.ts +2 -0
  77. package/dist/guards.js +15 -0
  78. package/dist/index.d.ts +2 -0
  79. package/dist/index.js +504 -0
  80. package/dist/json.d.ts +2 -0
  81. package/dist/json.js +40 -0
  82. package/dist/lifecycle.d.ts +14 -0
  83. package/dist/lifecycle.js +190 -0
  84. package/dist/normalization.d.ts +4 -0
  85. package/dist/normalization.js +27 -0
  86. package/dist/perf/ab.d.ts +6 -0
  87. package/dist/perf/ab.js +89 -0
  88. package/dist/perf/autocannon.d.ts +6 -0
  89. package/dist/perf/autocannon.js +101 -0
  90. package/dist/perf/capture.d.ts +7 -0
  91. package/dist/perf/capture.js +6 -0
  92. package/dist/perf/k6.d.ts +9 -0
  93. package/dist/perf/k6.js +44 -0
  94. package/dist/perf/parsers.d.ts +15 -0
  95. package/dist/perf/parsers.js +69 -0
  96. package/dist/perf/run.d.ts +8 -0
  97. package/dist/perf/run.js +45 -0
  98. package/dist/perf/toolOutput.d.ts +3 -0
  99. package/dist/perf/toolOutput.js +24 -0
  100. package/dist/reporters.d.ts +11 -0
  101. package/dist/reporters.js +314 -0
  102. package/dist/runner.d.ts +48 -0
  103. package/dist/runner.js +352 -0
  104. package/dist/snapshot.d.ts +48 -0
  105. package/dist/snapshot.js +37 -0
  106. package/dist/terminal/ansi.d.ts +21 -0
  107. package/dist/terminal/ansi.js +144 -0
  108. package/dist/terminal/capture.d.ts +30 -0
  109. package/dist/terminal/capture.js +91 -0
  110. package/dist/tty.d.ts +72 -0
  111. package/dist/tty.js +175 -0
  112. package/dist/web/domSnapshot.d.ts +27 -0
  113. package/dist/web/domSnapshot.js +55 -0
  114. package/dist/web/playwrightCapture.d.ts +16 -0
  115. package/dist/web/playwrightCapture.js +64 -0
  116. package/package.json +79 -0
@@ -0,0 +1,278 @@
1
+ // Tool-parser registry for the check kind.
2
+ //
3
+ // A check target runs a tool that reports on the shape of an application
4
+ // (routes, scheduled jobs, environment) and snapshots the normalized result.
5
+ // Each parser turns one tool's JSON output into a stable **keyed record** —
6
+ // entries keyed by identity (e.g. "GET|HEAD /users") rather than array index —
7
+ // so the structural diff names exactly the added/removed/changed entry instead
8
+ // of reporting every index shift. Adding a tool is one parser object plus one
9
+ // registry line here.
10
+ import { isRecord } from "../guards.js";
11
+ import { parseJUnit } from "./junit.js";
12
+ import { parseSchemaDump } from "./schema.js";
13
+ // Tool output is attacker-controlled in CI (a hostile PR names a test class or
14
+ // source file). Reject the keys that would let `obj[key] ??= {}` reach back
15
+ // into Object.prototype and pollute it globally.
16
+ function isUnsafeKey(key) {
17
+ return key === "__proto__" || key === "constructor" || key === "prototype";
18
+ }
19
+ // Accumulator whose keys come from attacker-controlled tool output. A plain `{}`
20
+ // inherits Object.prototype members (toString, valueOf, hasOwnProperty, …), so a
21
+ // suite/file/message named `toString` makes `obj[key]` resolve to the inherited
22
+ // function — non-nullish — and `obj[key] ??= {}` then skips the assignment and
23
+ // writes onto the shared prototype instead of the snapshot, silently dropping the
24
+ // entry. A null-prototype object has no inherited keys, so every key behaves as an
25
+ // own key and `isUnsafeKey` above is pure defense-in-depth.
26
+ function emptyRecord() {
27
+ return Object.create(null);
28
+ }
29
+ function invalidOutput(tool, expected) {
30
+ return new Error(`Invalid ${tool} output: expected ${expected}.`);
31
+ }
32
+ // `route:list --json`: an array of {domain, method, uri, name, action,
33
+ // middleware, path}. Keyed by "method uri". The `path` line number is dropped
34
+ // (it churns on unrelated edits); the file is kept to localize a change.
35
+ const laravelRoutes = {
36
+ tool: "laravel-routes",
37
+ defaultCommand: "php artisan route:list --json",
38
+ normalize(raw) {
39
+ if (!Array.isArray(raw)) {
40
+ throw invalidOutput(this.tool, "a JSON array of routes");
41
+ }
42
+ const routes = {};
43
+ for (const entry of raw) {
44
+ if (!isRecord(entry)) {
45
+ continue;
46
+ }
47
+ const key = `${typeof entry.method === "string" ? entry.method : "?"} ${typeof entry.uri === "string" ? entry.uri : "?"}`;
48
+ routes[key] = {
49
+ name: entry.name ?? null,
50
+ action: entry.action ?? null,
51
+ middleware: entry.middleware ?? [],
52
+ ...(entry.domain ? { domain: entry.domain } : {}),
53
+ ...(typeof entry.path === "string" ? { path: entry.path.replace(/:\d+$/, "") } : {})
54
+ };
55
+ }
56
+ return routes;
57
+ }
58
+ };
59
+ // `about --json`: a record of sections. Values embed absolute project paths
60
+ // (sometimes case-folded, e.g. the storage-link status keys), so occurrences of
61
+ // the project directory are replaced with "<project>" to keep snapshots
62
+ // machine-portable. Version fields are kept on purpose — that drift is signal.
63
+ // `cache.views` is dropped: view compilation happens as a side effect of merely
64
+ // rendering (running the test suite compiles Blade views), so unlike the
65
+ // deliberate config/route/event caches it flips run-to-run and would make an
66
+ // `about` target flaky whenever a `tests` target runs beside it.
67
+ const laravelAbout = {
68
+ tool: "laravel-about",
69
+ defaultCommand: "php artisan about --json",
70
+ normalize(raw, { cwd }) {
71
+ if (!isRecord(raw)) {
72
+ throw invalidOutput(this.tool, "a JSON object of sections");
73
+ }
74
+ const data = stripProjectDir(raw, cwd);
75
+ const cache = data.cache;
76
+ if (isRecord(cache)) {
77
+ const { views: _views, ...stable } = cache;
78
+ data.cache = stable;
79
+ }
80
+ return data;
81
+ }
82
+ };
83
+ // `schedule:list --json` (Laravel ≥ 12): an array of scheduled entries. Keyed
84
+ // by "expression command" — a cron change reads as remove+add, which is the
85
+ // loudness a schedule change deserves. `next_due_date(_human)` vary with the
86
+ // wall clock and are dropped.
87
+ const laravelSchedule = {
88
+ tool: "laravel-schedule",
89
+ defaultCommand: "php artisan schedule:list --json",
90
+ normalize(raw) {
91
+ if (!Array.isArray(raw)) {
92
+ throw invalidOutput(this.tool, "a JSON array of schedule entries");
93
+ }
94
+ const entries = {};
95
+ for (const entry of raw) {
96
+ if (!isRecord(entry)) {
97
+ continue;
98
+ }
99
+ const key = `${typeof entry.expression === "string" ? entry.expression : "?"} ${typeof entry.command === "string" ? entry.command : "?"}`;
100
+ const { next_due_date: _due, next_due_date_human: _human, ...stable } = entry;
101
+ entries[key] = stable;
102
+ }
103
+ return entries;
104
+ }
105
+ };
106
+ // PHPStan / Larastan `--error-format=json` (Larastan is PHPStan with Laravel
107
+ // extensions — same output). PHPStan emits two shapes: the classic
108
+ // `{totals, files: {path: {messages: […]}}}` and, when it detects an AI-agent
109
+ // environment, `{error_details: {path: […]}}`. Both normalize to the same
110
+ // keyed record so the snapshot doesn't depend on who ran the capture. Entries
111
+ // are keyed by message per file with a count — PHPStan's own baseline identity —
112
+ // and line numbers are dropped (they churn on unrelated edits).
113
+ const phpstan = {
114
+ tool: "phpstan",
115
+ defaultCommand: "vendor/bin/phpstan analyse --error-format=json --no-progress",
116
+ toleratesNonZeroExit: true,
117
+ normalize(raw, { cwd }) {
118
+ if (!isRecord(raw) || !(isRecord(raw.totals) || raw.tool === "phpstan")) {
119
+ throw invalidOutput(this.tool, "PHPStan JSON error output");
120
+ }
121
+ const data = emptyRecord();
122
+ const add = (file, message, identifier) => {
123
+ if (typeof message !== "string") {
124
+ return;
125
+ }
126
+ const relative = file.startsWith(`${cwd}/`) ? file.slice(cwd.length + 1) : file;
127
+ if (isUnsafeKey(relative) || isUnsafeKey(message)) {
128
+ return;
129
+ }
130
+ data[relative] ??= emptyRecord();
131
+ const entries = data[relative];
132
+ const entry = entries[message] ?? {
133
+ identifier: typeof identifier === "string" ? identifier : null,
134
+ count: 0
135
+ };
136
+ entry.count += 1;
137
+ entries[message] = entry;
138
+ };
139
+ // Classic shape ({} or [] when empty — PHP arrays serialize both ways).
140
+ if (isRecord(raw.files)) {
141
+ for (const [file, info] of Object.entries(raw.files)) {
142
+ if (isRecord(info) && Array.isArray(info.messages)) {
143
+ for (const message of info.messages) {
144
+ if (isRecord(message)) {
145
+ add(file, message.message, message.identifier);
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ // Agent shape.
152
+ if (isRecord(raw.error_details)) {
153
+ for (const [file, messages] of Object.entries(raw.error_details)) {
154
+ if (Array.isArray(messages)) {
155
+ for (const message of messages) {
156
+ if (isRecord(message)) {
157
+ add(file, message.message, message.identifier);
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ // Non-file errors (config problems, unparsable files).
164
+ if (Array.isArray(raw.errors)) {
165
+ for (const message of raw.errors) {
166
+ add("(general)", message, null);
167
+ }
168
+ }
169
+ return data;
170
+ }
171
+ };
172
+ // Pest / PHPUnit via the JUnit XML report (`--log-junit`) — one normalizer
173
+ // covers both runners (Pest runs on the PHPUnit core and emits the same
174
+ // report; only the default binary differs). Keyed suite → case → {status,
175
+ // type?, message?}; `time`/`assertions` are dropped (run-varying), messages
176
+ // keep the assertion text with project paths relativized.
177
+ const JUNIT_ARTIFACT = ".dungbeetle-junit.xml";
178
+ function normalizeJUnit(raw, { cwd }) {
179
+ const suites = emptyRecord();
180
+ for (const testCase of parseJUnit(String(raw))) {
181
+ if (isUnsafeKey(testCase.suite) || isUnsafeKey(testCase.name)) {
182
+ continue;
183
+ }
184
+ suites[testCase.suite] ??= emptyRecord();
185
+ const suite = suites[testCase.suite];
186
+ suite[testCase.name] = {
187
+ status: testCase.status,
188
+ ...(testCase.type ? { type: testCase.type } : {}),
189
+ ...(testCase.message ? { message: stripProjectDir(testCase.message, cwd) } : {})
190
+ };
191
+ }
192
+ return suites;
193
+ }
194
+ const phpunit = {
195
+ tool: "phpunit",
196
+ defaultCommand: `vendor/bin/phpunit --log-junit ${JUNIT_ARTIFACT}`,
197
+ defaultOutput: JUNIT_ARTIFACT,
198
+ format: "text",
199
+ toleratesNonZeroExit: true,
200
+ normalize: normalizeJUnit
201
+ };
202
+ const pest = {
203
+ tool: "pest",
204
+ defaultCommand: `vendor/bin/pest --log-junit ${JUNIT_ARTIFACT}`,
205
+ defaultOutput: JUNIT_ARTIFACT,
206
+ format: "text",
207
+ toleratesNonZeroExit: true,
208
+ normalize: normalizeJUnit
209
+ };
210
+ // Pint `--test --format=json`. Like PHPStan, Pint emits two shapes: the
211
+ // classic PHP-CS-Fixer report `{about, files: [{name, appliedFixers}]}` and an
212
+ // AI-agent shape `{tool: "pint", result, files: [{path, fixers}]}` (where even
213
+ // a failing run exits 0). Both normalize to file → sorted fixer names — the
214
+ // one field the shapes agree on — so snapshots stay environment-independent.
215
+ // The classic shape's per-file diff text is deliberately dropped for the same
216
+ // reason; the review UI can regenerate diffs when it needs them.
217
+ const pint = {
218
+ tool: "pint",
219
+ defaultCommand: "vendor/bin/pint --test --format=json -v",
220
+ toleratesNonZeroExit: true,
221
+ normalize(raw) {
222
+ if (!isRecord(raw) || !(raw.tool === "pint" || typeof raw.about === "string")) {
223
+ throw invalidOutput(this.tool, "Pint JSON output");
224
+ }
225
+ const data = {};
226
+ for (const file of Array.isArray(raw.files) ? raw.files : []) {
227
+ if (!isRecord(file)) {
228
+ continue;
229
+ }
230
+ const filePath = file.path ?? file.name;
231
+ if (typeof filePath !== "string" || isUnsafeKey(filePath)) {
232
+ continue;
233
+ }
234
+ const fixers = file.fixers ?? file.appliedFixers;
235
+ data[filePath] = Array.isArray(fixers) ? [...fixers].sort() : true;
236
+ }
237
+ return data;
238
+ }
239
+ };
240
+ // `schema:dump` writes DDL to database/schema/{connection}-schema.sql. The
241
+ // default output assumes sqlite (Laravel's default connection since 11); other
242
+ // connections override `output` with their dump path. Dropped columns and type
243
+ // changes diff as one named entry per table (see src/check/schema.ts).
244
+ const laravelSchema = {
245
+ tool: "laravel-schema",
246
+ defaultCommand: "php artisan schema:dump",
247
+ defaultOutput: "database/schema/sqlite-schema.sql",
248
+ format: "text",
249
+ normalize(raw) {
250
+ return parseSchemaDump(String(raw));
251
+ }
252
+ };
253
+ function stripProjectDir(value, cwd) {
254
+ const pattern = new RegExp(cwd.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
255
+ const strip = (node) => {
256
+ if (typeof node === "string") {
257
+ return node.replace(pattern, "<project>");
258
+ }
259
+ if (Array.isArray(node)) {
260
+ return node.map(strip);
261
+ }
262
+ if (isRecord(node)) {
263
+ return Object.fromEntries(Object.entries(node).map(([key, entry]) => [strip(key), strip(entry)]));
264
+ }
265
+ return node;
266
+ };
267
+ return strip(value);
268
+ }
269
+ export const checkParsers = {
270
+ "laravel-routes": laravelRoutes,
271
+ "laravel-about": laravelAbout,
272
+ "laravel-schedule": laravelSchedule,
273
+ "laravel-schema": laravelSchema,
274
+ phpstan,
275
+ phpunit,
276
+ pest,
277
+ pint
278
+ };
@@ -0,0 +1,2 @@
1
+ export type SchemaData = Record<string, unknown>;
2
+ export declare function parseSchemaDump(sql: string): SchemaData;
@@ -0,0 +1,114 @@
1
+ // SQL-dump extraction for the laravel-schema check parser.
2
+ //
3
+ // Not a SQL parser — it targets the DDL Laravel's `schema:dump` writes
4
+ // (sqlite today, mysqldump-style guardedly): CREATE TABLE bodies, CREATE INDEX
5
+ // statements, and the migrations-table INSERTs. Everything is normalized into
6
+ // the check kind's keyed-record shape:
7
+ //
8
+ // { users: { id: "integer primary key autoincrement not null",
9
+ // "(index) users_email_unique": "unique (email)",
10
+ // "(constraint) primary key(email)": true },
11
+ // "(migrations)": { "0001_01_01_000000_create_users_table": true } }
12
+ //
13
+ // so a dropped column or changed type diffs as one named entry per table.
14
+ const CONSTRAINT_KEYWORDS = /^(primary\s+key|foreign\s+key|unique|constraint|check|key)\b/i;
15
+ function unquote(identifier) {
16
+ return identifier.replace(/^[`"[]|[`"\]]$/g, "");
17
+ }
18
+ function collapse(text) {
19
+ return text.replace(/\s+/g, " ").trim();
20
+ }
21
+ // Split a CREATE TABLE body on top-level commas (paren-depth aware).
22
+ function splitColumns(body) {
23
+ const parts = [];
24
+ let depth = 0;
25
+ let current = "";
26
+ for (const char of body) {
27
+ if (char === "(") {
28
+ depth += 1;
29
+ }
30
+ else if (char === ")") {
31
+ depth -= 1;
32
+ }
33
+ if (char === "," && depth === 0) {
34
+ parts.push(current);
35
+ current = "";
36
+ }
37
+ else {
38
+ current += char;
39
+ }
40
+ }
41
+ if (current.trim()) {
42
+ parts.push(current);
43
+ }
44
+ return parts;
45
+ }
46
+ // Accumulate lines into statements ending with ";", dropping comment lines.
47
+ function statements(sql) {
48
+ const result = [];
49
+ let current = "";
50
+ for (const line of sql.split("\n")) {
51
+ const trimmed = line.trim();
52
+ if (trimmed.startsWith("--") || trimmed.startsWith("/*") || trimmed === "") {
53
+ continue;
54
+ }
55
+ current += `${line}\n`;
56
+ if (trimmed.endsWith(";")) {
57
+ result.push(current.trim().replace(/;$/, ""));
58
+ current = "";
59
+ }
60
+ }
61
+ return result;
62
+ }
63
+ export function parseSchemaDump(sql) {
64
+ const data = {};
65
+ const table = (name) => {
66
+ data[name] ??= {};
67
+ return data[name];
68
+ };
69
+ let sawDdl = false;
70
+ for (const statement of statements(sql)) {
71
+ const createTable = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([`"]?\w+[`"]?)\s*\(([\s\S]*)\)[^)]*$/i.exec(statement);
72
+ if (createTable) {
73
+ sawDdl = true;
74
+ const name = unquote(createTable[1]);
75
+ if (name === "sqlite_sequence") {
76
+ continue;
77
+ }
78
+ const entry = table(name);
79
+ for (const part of splitColumns(createTable[2])) {
80
+ const text = collapse(part);
81
+ if (!text) {
82
+ continue;
83
+ }
84
+ if (CONSTRAINT_KEYWORDS.test(text)) {
85
+ entry[`(constraint) ${text}`] = true;
86
+ }
87
+ else {
88
+ const [identifier, ...definition] = text.split(" ");
89
+ entry[unquote(identifier)] = definition.join(" ");
90
+ }
91
+ }
92
+ continue;
93
+ }
94
+ const createIndex = /^CREATE\s+(UNIQUE\s+)?INDEX\s+([`"]?\w+[`"]?)\s+ON\s+([`"]?\w+[`"]?)\s*\(([\s\S]*)\)$/i.exec(statement);
95
+ if (createIndex) {
96
+ sawDdl = true;
97
+ const [, unique, indexName, tableName, columns] = createIndex;
98
+ table(unquote(tableName))[`(index) ${unquote(indexName)}`] =
99
+ `${unique ? "unique " : ""}(${collapse(columns).replace(/[`"]/g, "")})`;
100
+ continue;
101
+ }
102
+ // Migration rows: the name is schema signal, the id/batch churn.
103
+ if (/^INSERT\s+INTO\s+[`"]?migrations[`"]?/i.test(statement)) {
104
+ for (const row of statement.matchAll(/\(\s*\d+\s*,\s*'([^']+)'\s*,\s*\d+\s*\)/g)) {
105
+ table("(migrations)")[row[1]] = true;
106
+ }
107
+ }
108
+ // Anything else (PRAGMA, SET, other inserts) carries no schema shape.
109
+ }
110
+ if (!sawDdl) {
111
+ throw new Error("Invalid schema dump: no CREATE TABLE statements found.");
112
+ }
113
+ return data;
114
+ }
@@ -0,0 +1,42 @@
1
+ export type ClientCredentials = {
2
+ clientId: string;
3
+ clientSecret: string;
4
+ };
5
+ export type PushOptions = ClientCredentials & {
6
+ serverUrl: string;
7
+ reportPath: string;
8
+ branch?: string;
9
+ commit?: string;
10
+ };
11
+ export type PushedRun = {
12
+ id: string;
13
+ repositoryId: string;
14
+ status: string;
15
+ counts: Record<string, number>;
16
+ url: string;
17
+ };
18
+ export declare function pushReport(options: PushOptions): Promise<PushedRun>;
19
+ export type BaselineSource = {
20
+ target: string;
21
+ kind: string;
22
+ snapshotPath: string;
23
+ screenshotPath?: string;
24
+ };
25
+ export type PushBaselinesOptions = ClientCredentials & {
26
+ serverUrl: string;
27
+ baselines: BaselineSource[];
28
+ };
29
+ export type UploadedBaseline = {
30
+ target: string;
31
+ version: number;
32
+ deduped: boolean;
33
+ };
34
+ export declare function pushBaselines(options: PushBaselinesOptions): Promise<UploadedBaseline[]>;
35
+ export type AnonPushResult = {
36
+ id: string;
37
+ url: string;
38
+ };
39
+ export declare function pushAnonReport(options: {
40
+ serverUrl: string;
41
+ report: unknown;
42
+ }): Promise<AnonPushResult>;