@juxtapose/core 0.4.0 → 0.5.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.
- package/dist/agent/handoff.d.ts +8 -1
- package/dist/agent/handoff.js +75 -7
- package/dist/agent/handoff.js.map +1 -1
- package/dist/analysis/affected.d.ts +37 -0
- package/dist/analysis/affected.js +97 -22
- package/dist/analysis/affected.js.map +1 -1
- package/dist/analysis/cause.d.ts +32 -0
- package/dist/analysis/cause.js +187 -0
- package/dist/analysis/cause.js.map +1 -0
- package/dist/baseline/approve.d.ts +24 -0
- package/dist/baseline/approve.js +54 -0
- package/dist/baseline/approve.js.map +1 -0
- package/dist/baseline/git-store.d.ts +4 -0
- package/dist/baseline/git-store.js +22 -0
- package/dist/baseline/git-store.js.map +1 -1
- package/dist/browser/acquire.d.ts +11 -0
- package/dist/browser/acquire.js +15 -0
- package/dist/browser/acquire.js.map +1 -0
- package/dist/browser/browser.d.ts +53 -0
- package/dist/browser/browser.js +122 -0
- package/dist/browser/browser.js.map +1 -0
- package/dist/browser/cdp.d.ts +81 -0
- package/dist/browser/cdp.js +230 -0
- package/dist/browser/cdp.js.map +1 -0
- package/dist/browser/index.d.ts +9 -0
- package/dist/browser/index.js +10 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/install.d.ts +33 -0
- package/dist/browser/install.js +167 -0
- package/dist/browser/install.js.map +1 -0
- package/dist/browser/launch.d.ts +37 -0
- package/dist/browser/launch.js +265 -0
- package/dist/browser/launch.js.map +1 -0
- package/dist/browser/page.d.ts +125 -0
- package/dist/browser/page.js +564 -0
- package/dist/browser/page.js.map +1 -0
- package/dist/browser/pins.d.ts +12 -0
- package/dist/browser/pins.js +57 -0
- package/dist/browser/pins.js.map +1 -0
- package/dist/browser/resolve.d.ts +25 -0
- package/dist/browser/resolve.js +115 -0
- package/dist/browser/resolve.js.map +1 -0
- package/dist/browser/selectors.d.ts +10 -0
- package/dist/browser/selectors.js +60 -0
- package/dist/browser/selectors.js.map +1 -0
- package/dist/browser/transport.d.ts +39 -0
- package/dist/browser/transport.js +99 -0
- package/dist/browser/transport.js.map +1 -0
- package/dist/browser/zip.d.ts +27 -0
- package/dist/browser/zip.js +241 -0
- package/dist/browser/zip.js.map +1 -0
- package/dist/capture/capture.d.ts +7 -1
- package/dist/capture/capture.js +25 -8
- package/dist/capture/capture.js.map +1 -1
- package/dist/capture/env.d.ts +1 -1
- package/dist/capture/launch.d.ts +19 -1
- package/dist/capture/launch.js +91 -1
- package/dist/capture/launch.js.map +1 -1
- package/dist/capture/pool.d.ts +1 -1
- package/dist/capture/pool.js +41 -8
- package/dist/capture/pool.js.map +1 -1
- package/dist/capture/settle.d.ts +1 -1
- package/dist/capture/settle.js +2 -0
- package/dist/capture/settle.js.map +1 -1
- package/dist/capture/snap.d.ts +43 -0
- package/dist/capture/snap.js +103 -0
- package/dist/capture/snap.js.map +1 -0
- package/dist/capture/structure.d.ts +77 -0
- package/dist/capture/structure.js +498 -0
- package/dist/capture/structure.js.map +1 -0
- package/dist/diff/compare.d.ts +19 -0
- package/dist/diff/compare.js +19 -0
- package/dist/diff/compare.js.map +1 -0
- package/dist/diff/crops.d.ts +26 -0
- package/dist/diff/crops.js +92 -0
- package/dist/diff/crops.js.map +1 -0
- package/dist/diff/structural/classify.d.ts +29 -0
- package/dist/diff/structural/classify.js +113 -0
- package/dist/diff/structural/classify.js.map +1 -0
- package/dist/diff/structural/coverage.d.ts +11 -0
- package/dist/diff/structural/coverage.js +37 -0
- package/dist/diff/structural/coverage.js.map +1 -0
- package/dist/diff/structural/deltas.d.ts +29 -0
- package/dist/diff/structural/deltas.js +218 -0
- package/dist/diff/structural/deltas.js.map +1 -0
- package/dist/diff/structural/disambiguate.d.ts +3 -0
- package/dist/diff/structural/disambiguate.js +89 -0
- package/dist/diff/structural/disambiguate.js.map +1 -0
- package/dist/diff/structural/label.d.ts +15 -0
- package/dist/diff/structural/label.js +64 -0
- package/dist/diff/structural/label.js.map +1 -0
- package/dist/diff/structural/match.d.ts +13 -0
- package/dist/diff/structural/match.js +135 -0
- package/dist/diff/structural/match.js.map +1 -0
- package/dist/diff/structural/shift.d.ts +2 -0
- package/dist/diff/structural/shift.js +144 -0
- package/dist/diff/structural/shift.js.map +1 -0
- package/dist/diff/structural/summary.d.ts +31 -0
- package/dist/diff/structural/summary.js +420 -0
- package/dist/diff/structural/summary.js.map +1 -0
- package/dist/diff/structural.d.ts +40 -0
- package/dist/diff/structural.js +219 -0
- package/dist/diff/structural.js.map +1 -0
- package/dist/index.d.ts +25 -3
- package/dist/index.js +29 -2
- package/dist/index.js.map +1 -1
- package/dist/platform.d.ts +1 -1
- package/dist/platforms/urls.d.ts +3 -0
- package/dist/platforms/urls.js +89 -0
- package/dist/platforms/urls.js.map +1 -0
- package/dist/report/comment.js +9 -3
- package/dist/report/comment.js.map +1 -1
- package/dist/report/format.d.ts +18 -0
- package/dist/report/format.js +20 -0
- package/dist/report/format.js.map +1 -1
- package/dist/report/html.js +2 -2
- package/dist/report/html.js.map +1 -1
- package/dist/run/groups.d.ts +2 -0
- package/dist/run/groups.js +45 -0
- package/dist/run/groups.js.map +1 -0
- package/dist/run/run.d.ts +6 -2
- package/dist/run/run.js +74 -6
- package/dist/run/run.js.map +1 -1
- package/dist/shell-quote.d.ts +2 -0
- package/dist/shell-quote.js +10 -0
- package/dist/shell-quote.js.map +1 -0
- package/dist/types.d.ts +199 -1
- package/dist/url-platform.d.ts +2 -2
- package/dist/url-platform.js +2 -2
- package/dist/url-platform.js.map +1 -1
- package/package.json +5 -10
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Why did this story change? The cheap link only: the story's import
|
|
2
|
+
// closure — a forward walk over the same Vite manifest `affected.ts` walks
|
|
3
|
+
// backwards — intersected with the files changed since `--since`, nearest
|
|
4
|
+
// first. `none-in-closure` beside `render-drift` is the strongest "this is
|
|
5
|
+
// not your code" the tool can give. Matched CSS rules and source lines are
|
|
6
|
+
// later rows.
|
|
7
|
+
//
|
|
8
|
+
// "Not your code" is said only after a full trace, and the manifest is
|
|
9
|
+
// chunk-level, so a full trace needs two things:
|
|
10
|
+
//
|
|
11
|
+
// - Every node the walk reaches has its own manifest entry with a `src`. A
|
|
12
|
+
// Storybook build bundles components into chunks that have none, so a
|
|
13
|
+
// story's closure usually ends in an unresolved node; an `imports[]` key
|
|
14
|
+
// with no entry at all is the same. A changed file found before that point
|
|
15
|
+
// is a hit, but no hit is `unknown`. The first draft said "not your code"
|
|
16
|
+
// for a component edit on examples/storybook, the worst answer the
|
|
17
|
+
// feature can give.
|
|
18
|
+
// - Every changed file is some entry's `src`. A module Rollup inlined into
|
|
19
|
+
// a chunk has no entry of its own, so a changed file the manifest never
|
|
20
|
+
// names could sit inside any chunk, this story's included. That holds for
|
|
21
|
+
// far more than code: JSON, SVG, GraphQL, `?raw` text, images and .mdx are
|
|
22
|
+
// all importable. So the exemption is an allowlist of files no bundler
|
|
23
|
+
// imports (prose docs, licences, git and editor dotfiles, `.github/`), and
|
|
24
|
+
// anything else unnamed blocks the claim. A list of bundled extensions
|
|
25
|
+
// failed open: every importable type it missed was a false "not yours".
|
|
26
|
+
//
|
|
27
|
+
// Even then the claim is about the traced imports, not about every byte the
|
|
28
|
+
// story renders (a stylesheet linked from preview-head, a public asset), so
|
|
29
|
+
// the wording says "likely".
|
|
30
|
+
//
|
|
31
|
+
// Nothing here may fail a story. `prepareCause` reads git and the manifest
|
|
32
|
+
// on the first `causeFor` call, once, inside try/catch; that call happens
|
|
33
|
+
// only in the fail branch of `judge()`, so a green run reads neither.
|
|
34
|
+
import { realpathSync } from 'node:fs';
|
|
35
|
+
import path from 'node:path';
|
|
36
|
+
import { compareCodeUnits } from '../diff/structural/deltas.js';
|
|
37
|
+
import { MAX_CAUSE_FILES } from '../diff/structural.js';
|
|
38
|
+
import { gitChangedFiles, gitTopLevel, isConfigChange, isLockfileChange, isTsconfigChange, keyToSrc, loadViteManifest, toPosixRelative, } from './affected.js';
|
|
39
|
+
const UNKNOWN = { kind: 'unknown', files: [] };
|
|
40
|
+
/** The index from already-loaded inputs. Pure. */
|
|
41
|
+
export function buildCauseIndex(src) {
|
|
42
|
+
const graph = src.manifest ? buildForwardGraph(src.manifest) : null;
|
|
43
|
+
return {
|
|
44
|
+
causeFor: async (componentPath) => causeOf(src, graph, componentPath),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** The index for `jux run --since`. Lazy and memoized, so the manifest and
|
|
48
|
+
* git are read once, and only if some story fails. */
|
|
49
|
+
export function prepareCause(opts) {
|
|
50
|
+
let loading;
|
|
51
|
+
const load = async () => buildCauseIndex({
|
|
52
|
+
projectRoot: opts.projectRoot,
|
|
53
|
+
configDirs: opts.configDirs,
|
|
54
|
+
manifest: await orNull(() => opts.buildDir ? loadViteManifest(opts.buildDir) : Promise.resolve(null)),
|
|
55
|
+
changedFiles: await orNull(async () => projectRelative(gitChangedFiles(opts.sinceCommit, opts.projectRoot), gitTopLevel(opts.projectRoot), opts.projectRoot)),
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
causeFor: async (componentPath) => {
|
|
59
|
+
try {
|
|
60
|
+
loading ??= load();
|
|
61
|
+
return await (await loading).causeFor(componentPath);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return UNKNOWN;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function orNull(fn) {
|
|
70
|
+
try {
|
|
71
|
+
return await fn();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Git prints paths relative to the repository top level; the manifest's
|
|
78
|
+
* `src` is relative to the project root. In a monorepo these differ
|
|
79
|
+
* (`examples/storybook/stories/X.jsx` vs `stories/X.jsx`), and comparing
|
|
80
|
+
* them unmapped made every story `none-in-closure`. A file outside the
|
|
81
|
+
* project maps to a `../` path, which is still what the manifest would hold
|
|
82
|
+
* for it.
|
|
83
|
+
*
|
|
84
|
+
* Git prints its top level with symlinks resolved, so the project root is
|
|
85
|
+
* resolved too: on macOS the temp dir `/var/folders/…` is
|
|
86
|
+
* `/private/var/folders/…` to git, and relating the two unresolved paths
|
|
87
|
+
* gave `../../../../private/var/…` for every file, which matched nothing
|
|
88
|
+
* and made a component edit `none-in-closure`. */
|
|
89
|
+
function projectRelative(files, topLevel, projectRoot) {
|
|
90
|
+
if (files === null || topLevel === null)
|
|
91
|
+
return null;
|
|
92
|
+
const root = realpathSync(projectRoot);
|
|
93
|
+
return files.map((repoPath) => ({
|
|
94
|
+
path: toPosixRelative(root, path.join(topLevel, repoPath)),
|
|
95
|
+
repoPath,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
/** Files no bundler imports. `.mdx` is not one: it compiles to a module. */
|
|
99
|
+
const NEVER_BUNDLED_EXT = /\.(?:md|markdown|mdown|rst|adoc)$/i;
|
|
100
|
+
const NEVER_BUNDLED_NAME = /^(?:LICENSE.*|CHANGELOG.*|AUTHORS.*|CODEOWNERS|\.gitignore|\.gitattributes|\.editorconfig)$/;
|
|
101
|
+
function neverBundled(f) {
|
|
102
|
+
const name = f.path.slice(f.path.lastIndexOf('/') + 1);
|
|
103
|
+
return (NEVER_BUNDLED_EXT.test(name) ||
|
|
104
|
+
NEVER_BUNDLED_NAME.test(name) ||
|
|
105
|
+
f.repoPath.startsWith('.github/'));
|
|
106
|
+
}
|
|
107
|
+
/** Reaches every story: a root lockfile or tsconfig, or a workbench config
|
|
108
|
+
* dir. Checked in both forms, since a monorepo's root files are only
|
|
109
|
+
* recognisable in git's. */
|
|
110
|
+
function isGlobalChange(f, configDirs) {
|
|
111
|
+
return [f.path, f.repoPath].some((p) => isLockfileChange(p) || isTsconfigChange(p) || isConfigChange(p, configDirs));
|
|
112
|
+
}
|
|
113
|
+
function causeOf(src, graph, componentPath) {
|
|
114
|
+
if (src.changedFiles === null)
|
|
115
|
+
return UNKNOWN;
|
|
116
|
+
// Same rule as resolveAffected: these reach every story, so the closure
|
|
117
|
+
// is beside the point.
|
|
118
|
+
const global = src.changedFiles
|
|
119
|
+
.filter((f) => isGlobalChange(f, src.configDirs))
|
|
120
|
+
.map((f) => f.path)
|
|
121
|
+
.sort(compareCodeUnits);
|
|
122
|
+
if (global.length > 0) {
|
|
123
|
+
return {
|
|
124
|
+
kind: 'config',
|
|
125
|
+
files: global.slice(0, MAX_CAUSE_FILES).map((path) => ({ path, distance: 0 })),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (!graph || componentPath === '')
|
|
129
|
+
return UNKNOWN;
|
|
130
|
+
const start = toPosixRelative(src.projectRoot, componentPath);
|
|
131
|
+
// Not in the graph (urls platform, a story outside the build): the
|
|
132
|
+
// closure was never traced, so "none of your files" would be a guess.
|
|
133
|
+
if (!graph.edges.has(start))
|
|
134
|
+
return UNKNOWN;
|
|
135
|
+
const reach = closure(graph.edges, start);
|
|
136
|
+
const changed = new Set(src.changedFiles.map((f) => f.path));
|
|
137
|
+
const files = [...reach]
|
|
138
|
+
.filter(([file]) => changed.has(file))
|
|
139
|
+
.map(([path, distance]) => ({ path, distance }))
|
|
140
|
+
.sort((x, y) => x.distance - y.distance || compareCodeUnits(x.path, y.path))
|
|
141
|
+
.slice(0, MAX_CAUSE_FILES);
|
|
142
|
+
// Fully traced: every node on the way had a src to look through, and no
|
|
143
|
+
// changed module could be hiding inlined in a chunk. A hit without it is
|
|
144
|
+
// still a hit, but not the whole answer: on examples/storybook a token edit
|
|
145
|
+
// bundled into the component chunk, beside a label edit in the story,
|
|
146
|
+
// named only the story file, for stories the token had changed.
|
|
147
|
+
const traced = [...reach.keys()].every((node) => graph.edges.has(node)) &&
|
|
148
|
+
src.changedFiles.every((f) => neverBundled(f) || graph.edges.has(f.path));
|
|
149
|
+
if (files.length > 0)
|
|
150
|
+
return traced
|
|
151
|
+
? { kind: 'in-closure', files }
|
|
152
|
+
: { kind: 'in-closure', files, partial: true };
|
|
153
|
+
return traced ? { kind: 'none-in-closure', files: [] } : UNKNOWN;
|
|
154
|
+
}
|
|
155
|
+
/** Edges resolve through the same key → src map affected.ts's reverse graph
|
|
156
|
+
* uses. A key with no src (a bundled chunk) or no entry at all stays a bare
|
|
157
|
+
* key: reachable, never a key of `edges`. Entries that share a src (one
|
|
158
|
+
* module emitted twice) merge their edges; overwriting dropped the first
|
|
159
|
+
* entry's imports and could make a hit look like `none-in-closure`. */
|
|
160
|
+
function buildForwardGraph(manifest) {
|
|
161
|
+
const srcOf = keyToSrc(manifest);
|
|
162
|
+
const edges = new Map();
|
|
163
|
+
for (const entry of Object.values(manifest)) {
|
|
164
|
+
if (!entry.src)
|
|
165
|
+
continue;
|
|
166
|
+
const out = [...(entry.imports ?? []), ...(entry.dynamicImports ?? [])].map((k) => srcOf.get(k) ?? k);
|
|
167
|
+
edges.set(entry.src, [...(edges.get(entry.src) ?? []), ...out]);
|
|
168
|
+
}
|
|
169
|
+
return { edges };
|
|
170
|
+
}
|
|
171
|
+
/** BFS distance from `start` to everything it reaches, `start` at 0. */
|
|
172
|
+
function closure(edges, start) {
|
|
173
|
+
const dist = new Map([[start, 0]]);
|
|
174
|
+
const queue = [start];
|
|
175
|
+
for (let k = 0; k < queue.length; k++) {
|
|
176
|
+
const file = queue[k];
|
|
177
|
+
const d = dist.get(file);
|
|
178
|
+
for (const next of edges.get(file) ?? []) {
|
|
179
|
+
if (dist.has(next))
|
|
180
|
+
continue;
|
|
181
|
+
dist.set(next, d + 1);
|
|
182
|
+
queue.push(next);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return dist;
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=cause.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cause.js","sourceRoot":"","sources":["../../src/analysis/cause.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ApprovalMeta, BaselineStore } from '../types.js';
|
|
2
|
+
export interface RunStructure {
|
|
3
|
+
gz: Buffer;
|
|
4
|
+
structureHash: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The structure sidecar written beside a run capture (`<x>.webp` →
|
|
8
|
+
* `<x>.structure.json.gz`), or null when there is none.
|
|
9
|
+
*
|
|
10
|
+
* Structure explains a diff, it never gates one: a corrupt sidecar is
|
|
11
|
+
* treated as absent so the image still gets approved.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readRunStructure(imagePath: string): Promise<RunStructure | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Write `image` as the baseline for `storyId`, and the run's structure sidecar
|
|
16
|
+
* beside it when the store can hold one.
|
|
17
|
+
*
|
|
18
|
+
* Throws only if `store.put` does. A sidecar that fails to write is returned
|
|
19
|
+
* as `structureError`, never thrown: the image is already approved by then,
|
|
20
|
+
* and structure must never fail a story.
|
|
21
|
+
*/
|
|
22
|
+
export declare function approveCapture(store: BaselineStore, storyId: string, image: Buffer, meta: ApprovalMeta, imagePath: string): Promise<{
|
|
23
|
+
structureError?: string;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Promoting a run's capture to a baseline, with its structure sidecar.
|
|
2
|
+
//
|
|
3
|
+
// One helper because there are three approval paths — `jux approve`,
|
|
4
|
+
// `jux init` and the review server behind the Storybook panel — and they
|
|
5
|
+
// disagreed: only `jux approve` kept the sidecar, so every baseline `init`
|
|
6
|
+
// bootstrapped, and every panel approval, silently dropped its structure.
|
|
7
|
+
import { readFile } from 'node:fs/promises';
|
|
8
|
+
import { decodeStructure } from '../capture/structure.js';
|
|
9
|
+
/**
|
|
10
|
+
* The structure sidecar written beside a run capture (`<x>.webp` →
|
|
11
|
+
* `<x>.structure.json.gz`), or null when there is none.
|
|
12
|
+
*
|
|
13
|
+
* Structure explains a diff, it never gates one: a corrupt sidecar is
|
|
14
|
+
* treated as absent so the image still gets approved.
|
|
15
|
+
*/
|
|
16
|
+
export async function readRunStructure(imagePath) {
|
|
17
|
+
const gz = await readFile(imagePath.replace(/\.webp$/, '.structure.json.gz')).catch(() => null);
|
|
18
|
+
if (!gz)
|
|
19
|
+
return null;
|
|
20
|
+
try {
|
|
21
|
+
const { structureHash } = decodeStructure(gz);
|
|
22
|
+
return typeof structureHash === 'string' ? { gz, structureHash } : null;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Write `image` as the baseline for `storyId`, and the run's structure sidecar
|
|
30
|
+
* beside it when the store can hold one.
|
|
31
|
+
*
|
|
32
|
+
* Throws only if `store.put` does. A sidecar that fails to write is returned
|
|
33
|
+
* as `structureError`, never thrown: the image is already approved by then,
|
|
34
|
+
* and structure must never fail a story.
|
|
35
|
+
*/
|
|
36
|
+
export async function approveCapture(store, storyId, image, meta, imagePath) {
|
|
37
|
+
// A hash in the manifest with nowhere to keep its sidecar would claim a
|
|
38
|
+
// structure no one can read, so a store without putStructure gets neither.
|
|
39
|
+
const structure = store.putStructure ? await readRunStructure(imagePath) : null;
|
|
40
|
+
await store.put(storyId, image, {
|
|
41
|
+
...meta,
|
|
42
|
+
...(structure ? { structureHash: structure.structureHash } : {}),
|
|
43
|
+
});
|
|
44
|
+
if (!structure)
|
|
45
|
+
return {};
|
|
46
|
+
try {
|
|
47
|
+
await store.putStructure(storyId, structure.gz);
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return { structureError: err.message };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=approve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approve.js","sourceRoot":"","sources":["../../src/baseline/approve.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,qEAAqE;AACrE,yEAAyE;AACzE,2EAA2E;AAC3E,0EAA0E;AAE1E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAQ1D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IACtD,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,CACjF,GAAG,EAAE,CAAC,IAAI,CACX,CAAC;IACF,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,EAAE,aAAa,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;QAC9C,OAAO,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAoB,EACpB,OAAe,EACf,KAAa,EACb,IAAkB,EAClB,SAAiB;IAEjB,wEAAwE;IACxE,2EAA2E;IAC3E,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChF,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE;QAC9B,GAAG,IAAI;QACP,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC,CAAC;IACH,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,YAAa,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;QACjD,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,cAAc,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -9,6 +9,10 @@ export declare class GitBaselineStore implements BaselineStore {
|
|
|
9
9
|
private readonly manifestPath;
|
|
10
10
|
constructor(opts: GitStoreOptions);
|
|
11
11
|
private imagePath;
|
|
12
|
+
private structurePath;
|
|
13
|
+
locate(storyId: string): string;
|
|
14
|
+
putStructure(storyId: string, gz: Buffer): Promise<void>;
|
|
15
|
+
getStructure(storyId: string): Promise<Buffer | null>;
|
|
12
16
|
get(storyId: string): Promise<Buffer | null>;
|
|
13
17
|
put(storyId: string, image: Buffer, meta: ApprovalMeta): Promise<void>;
|
|
14
18
|
remove(storyId: string): Promise<void>;
|
|
@@ -29,6 +29,24 @@ export class GitBaselineStore {
|
|
|
29
29
|
imagePath(storyId) {
|
|
30
30
|
return path.join(this.imageDir, `${encodeStoryId(storyId)}.webp`);
|
|
31
31
|
}
|
|
32
|
+
structurePath(storyId) {
|
|
33
|
+
return path.join(this.imageDir, `${encodeStoryId(storyId)}.structure.json.gz`);
|
|
34
|
+
}
|
|
35
|
+
locate(storyId) {
|
|
36
|
+
return this.imagePath(storyId);
|
|
37
|
+
}
|
|
38
|
+
async putStructure(storyId, gz) {
|
|
39
|
+
await mkdir(this.imageDir, { recursive: true });
|
|
40
|
+
await writeFile(this.structurePath(storyId), gz);
|
|
41
|
+
}
|
|
42
|
+
async getStructure(storyId) {
|
|
43
|
+
try {
|
|
44
|
+
return await readFile(this.structurePath(storyId));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
32
50
|
async get(storyId) {
|
|
33
51
|
try {
|
|
34
52
|
return await readFile(this.imagePath(storyId));
|
|
@@ -39,6 +57,9 @@ export class GitBaselineStore {
|
|
|
39
57
|
}
|
|
40
58
|
async put(storyId, image, meta) {
|
|
41
59
|
await mkdir(this.imageDir, { recursive: true });
|
|
60
|
+
// A previous baseline's sidecar must not outlive its pixels: a capture
|
|
61
|
+
// approved without structure would otherwise inherit the old one.
|
|
62
|
+
await rm(this.structurePath(storyId), { force: true });
|
|
42
63
|
await writeFile(this.imagePath(storyId), image);
|
|
43
64
|
const manifest = await this.readManifest();
|
|
44
65
|
manifest.baselines[storyId] = { ...meta, hash: hashImage(image) };
|
|
@@ -46,6 +67,7 @@ export class GitBaselineStore {
|
|
|
46
67
|
}
|
|
47
68
|
async remove(storyId) {
|
|
48
69
|
await rm(this.imagePath(storyId), { force: true });
|
|
70
|
+
await rm(this.structurePath(storyId), { force: true });
|
|
49
71
|
const manifest = await this.readManifest();
|
|
50
72
|
delete manifest.baselines[storyId];
|
|
51
73
|
await this.writeManifest(manifest);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-store.js","sourceRoot":"","sources":["../../src/baseline/git-store.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"git-store.js","sourceRoot":"","sources":["../../src/baseline/git-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Browser } from './browser.js';
|
|
2
|
+
import type { SpawnFn } from './launch.js';
|
|
3
|
+
export interface AcquireOptions {
|
|
4
|
+
/** `--chrome <path>`; wins over JUX_CHROME and the caches. */
|
|
5
|
+
chrome?: string;
|
|
6
|
+
env?: NodeJS.ProcessEnv;
|
|
7
|
+
spawn?: SpawnFn;
|
|
8
|
+
/** PR 2: `--no-daemon`. Accepted now so callers need no change later. */
|
|
9
|
+
noDaemon?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function acquireBrowser(opts?: AcquireOptions): Promise<Browser>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// packages/core/src/browser/acquire.ts
|
|
2
|
+
//
|
|
3
|
+
// The one place that decides where a Browser comes from. Every command and
|
|
4
|
+
// the review server call this; PR 2 adds the warm daemon here and nowhere
|
|
5
|
+
// else, so no caller changes when the policy does.
|
|
6
|
+
import { Browser } from './browser.js';
|
|
7
|
+
import { noBrowserMessage, resolveChrome } from './resolve.js';
|
|
8
|
+
export async function acquireBrowser(opts = {}) {
|
|
9
|
+
const env = opts.env ?? process.env;
|
|
10
|
+
const resolved = resolveChrome({ flag: opts.chrome, env });
|
|
11
|
+
if (!resolved)
|
|
12
|
+
throw new Error(noBrowserMessage());
|
|
13
|
+
return Browser.launch({ executablePath: resolved.path, spawn: opts.spawn });
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=acquire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acquire.js","sourceRoot":"","sources":["../../src/browser/acquire.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,mDAAmD;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAW/D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB,EAAE;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACnD,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Viewport } from '../types.js';
|
|
2
|
+
import { CdpConnection } from './cdp.js';
|
|
3
|
+
import type { SpawnFn } from './launch.js';
|
|
4
|
+
import { type Page } from './page.js';
|
|
5
|
+
/**
|
|
6
|
+
* The browser process is gone (killed, crashed, or closed under us). Every
|
|
7
|
+
* story still queued fails with this one error rather than with N cascading
|
|
8
|
+
* TargetClosedErrors that each look like a story problem.
|
|
9
|
+
*/
|
|
10
|
+
export declare class BrowserDiedError extends Error {
|
|
11
|
+
constructor(cause?: unknown);
|
|
12
|
+
}
|
|
13
|
+
export interface ContextOptions {
|
|
14
|
+
viewport: Viewport;
|
|
15
|
+
/** `serviceWorkers: 'block'` in Playwright terms: an init script that stubs registration. */
|
|
16
|
+
blockServiceWorkers?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class BrowserContext {
|
|
19
|
+
private readonly connection;
|
|
20
|
+
readonly id: string;
|
|
21
|
+
private readonly opts;
|
|
22
|
+
private readonly os;
|
|
23
|
+
private closed;
|
|
24
|
+
private readonly pages;
|
|
25
|
+
constructor(connection: CdpConnection, id: string, opts: ContextOptions, os: NodeJS.Platform);
|
|
26
|
+
newPage(): Promise<Page>;
|
|
27
|
+
/** Storage.clearCookies, as Playwright's clearCookies (coreBundle.js L38394). */
|
|
28
|
+
clearCookies(): Promise<void>;
|
|
29
|
+
/** Disposing the context closes its targets; their listeners go with them. */
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare class Browser {
|
|
33
|
+
private readonly connection;
|
|
34
|
+
private readonly productVersion;
|
|
35
|
+
private readonly closeFn;
|
|
36
|
+
private readonly os;
|
|
37
|
+
private constructor();
|
|
38
|
+
static launch(opts: {
|
|
39
|
+
executablePath: string;
|
|
40
|
+
args?: string[];
|
|
41
|
+
spawn?: SpawnFn;
|
|
42
|
+
}): Promise<Browser>;
|
|
43
|
+
/** PR 2: a connection owned by someone else (the daemon). */
|
|
44
|
+
static fromConnection(connection: CdpConnection, opts: {
|
|
45
|
+
version: string;
|
|
46
|
+
close: () => Promise<void>;
|
|
47
|
+
}): Browser;
|
|
48
|
+
/** `151.0.7922.34` — the string Playwright's `browser.version()` returned, so CaptureEnv compares equal. */
|
|
49
|
+
version(): string;
|
|
50
|
+
isConnected(): boolean;
|
|
51
|
+
newContext(opts: ContextOptions): Promise<BrowserContext>;
|
|
52
|
+
close(): Promise<void>;
|
|
53
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// packages/core/src/browser/browser.ts
|
|
2
|
+
//
|
|
3
|
+
// Browser = one CDP connection (pipe now, daemon socket in PR 2).
|
|
4
|
+
// BrowserContext = Target.createBrowserContext, one per pool worker, so
|
|
5
|
+
// concurrently rendering stories never share storage or service workers
|
|
6
|
+
// (pool.ts measured isolation at ~0% cost).
|
|
7
|
+
import { CdpConnection } from './cdp.js';
|
|
8
|
+
import { CdpPage } from './page.js';
|
|
9
|
+
/**
|
|
10
|
+
* The browser process is gone (killed, crashed, or closed under us). Every
|
|
11
|
+
* story still queued fails with this one error rather than with N cascading
|
|
12
|
+
* TargetClosedErrors that each look like a story problem.
|
|
13
|
+
*/
|
|
14
|
+
export class BrowserDiedError extends Error {
|
|
15
|
+
constructor(cause) {
|
|
16
|
+
super('jux: the browser died mid-run; the remaining stories were not captured', cause === undefined ? undefined : { cause });
|
|
17
|
+
this.name = 'BrowserDiedError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class BrowserContext {
|
|
21
|
+
connection;
|
|
22
|
+
id;
|
|
23
|
+
opts;
|
|
24
|
+
os;
|
|
25
|
+
closed = false;
|
|
26
|
+
pages = new Set();
|
|
27
|
+
constructor(connection, id, opts, os) {
|
|
28
|
+
this.connection = connection;
|
|
29
|
+
this.id = id;
|
|
30
|
+
this.opts = opts;
|
|
31
|
+
this.os = os;
|
|
32
|
+
}
|
|
33
|
+
async newPage() {
|
|
34
|
+
const { targetId } = await this.connection.send('Target.createTarget', {
|
|
35
|
+
url: 'about:blank',
|
|
36
|
+
browserContextId: this.id,
|
|
37
|
+
});
|
|
38
|
+
let page;
|
|
39
|
+
try {
|
|
40
|
+
const { sessionId } = await this.connection.send('Target.attachToTarget', { targetId, flatten: true });
|
|
41
|
+
page = await CdpPage.create(this.connection, targetId, sessionId, {
|
|
42
|
+
viewport: this.opts.viewport,
|
|
43
|
+
blockServiceWorkers: this.opts.blockServiceWorkers === true,
|
|
44
|
+
os: this.os,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
// A target nobody drives is a leak until the context closes; close it now.
|
|
49
|
+
await this.connection.send('Target.closeTarget', { targetId }).catch(() => { });
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
52
|
+
this.pages.add(page);
|
|
53
|
+
return page;
|
|
54
|
+
}
|
|
55
|
+
/** Storage.clearCookies, as Playwright's clearCookies (coreBundle.js L38394). */
|
|
56
|
+
async clearCookies() {
|
|
57
|
+
await this.connection.send('Storage.clearCookies', { browserContextId: this.id });
|
|
58
|
+
}
|
|
59
|
+
/** Disposing the context closes its targets; their listeners go with them. */
|
|
60
|
+
async close() {
|
|
61
|
+
if (this.closed)
|
|
62
|
+
return;
|
|
63
|
+
this.closed = true;
|
|
64
|
+
for (const page of this.pages)
|
|
65
|
+
page.dispose();
|
|
66
|
+
this.pages.clear();
|
|
67
|
+
await this.connection
|
|
68
|
+
.send('Target.disposeBrowserContext', { browserContextId: this.id })
|
|
69
|
+
.catch(() => { });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export class Browser {
|
|
73
|
+
connection;
|
|
74
|
+
productVersion;
|
|
75
|
+
closeFn;
|
|
76
|
+
os;
|
|
77
|
+
constructor(connection, productVersion, closeFn, os) {
|
|
78
|
+
this.connection = connection;
|
|
79
|
+
this.productVersion = productVersion;
|
|
80
|
+
this.closeFn = closeFn;
|
|
81
|
+
this.os = os;
|
|
82
|
+
}
|
|
83
|
+
static async launch(opts) {
|
|
84
|
+
// Lazy: the launcher is the only module that spawns Chrome, and `jux diff`
|
|
85
|
+
// (which imports core for its pixel code) must never load it. The
|
|
86
|
+
// no-browser probe in scripts/check-diff.mjs holds that line.
|
|
87
|
+
const { launchChrome } = await import('./launch.js');
|
|
88
|
+
const launched = await launchChrome(opts);
|
|
89
|
+
try {
|
|
90
|
+
const { product } = await launched.connection.send('Browser.getVersion');
|
|
91
|
+
return new Browser(launched.connection, stripProduct(product), launched.close, process.platform);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
await launched.close();
|
|
95
|
+
throw e;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** PR 2: a connection owned by someone else (the daemon). */
|
|
99
|
+
static fromConnection(connection, opts) {
|
|
100
|
+
return new Browser(connection, stripProduct(opts.version), opts.close, process.platform);
|
|
101
|
+
}
|
|
102
|
+
/** `151.0.7922.34` — the string Playwright's `browser.version()` returned, so CaptureEnv compares equal. */
|
|
103
|
+
version() {
|
|
104
|
+
return this.productVersion;
|
|
105
|
+
}
|
|
106
|
+
isConnected() {
|
|
107
|
+
return !this.connection.closed;
|
|
108
|
+
}
|
|
109
|
+
async newContext(opts) {
|
|
110
|
+
const { browserContextId } = await this.connection.send('Target.createBrowserContext', {
|
|
111
|
+
disposeOnDetach: true,
|
|
112
|
+
});
|
|
113
|
+
return new BrowserContext(this.connection, browserContextId, opts, this.os);
|
|
114
|
+
}
|
|
115
|
+
async close() {
|
|
116
|
+
await this.closeFn();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function stripProduct(product) {
|
|
120
|
+
return product.replace(/^[A-Za-z]+\//, '');
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/browser/browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Transport } from './transport.js';
|
|
2
|
+
export interface RawMessage {
|
|
3
|
+
id?: number;
|
|
4
|
+
method?: string;
|
|
5
|
+
params?: unknown;
|
|
6
|
+
result?: unknown;
|
|
7
|
+
error?: {
|
|
8
|
+
code: number;
|
|
9
|
+
message: string;
|
|
10
|
+
};
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const SEND_TIMEOUT_MS = 30000;
|
|
14
|
+
export declare class CdpError extends Error {
|
|
15
|
+
readonly code: number;
|
|
16
|
+
constructor(code: number, method: string, message: string);
|
|
17
|
+
}
|
|
18
|
+
export declare class TargetClosedError extends Error {
|
|
19
|
+
constructor(reason?: string, method?: string);
|
|
20
|
+
}
|
|
21
|
+
export declare class SendTimeoutError extends Error {
|
|
22
|
+
constructor(method: string, timeout: number);
|
|
23
|
+
}
|
|
24
|
+
type Handler = (params: unknown, sessionId?: string) => void;
|
|
25
|
+
export declare class CdpConnection {
|
|
26
|
+
private readonly transport;
|
|
27
|
+
private lastId;
|
|
28
|
+
private readonly pending;
|
|
29
|
+
/** key = `${sessionId ?? ''}\n${method}` */
|
|
30
|
+
private readonly handlers;
|
|
31
|
+
private readonly closeWaiters;
|
|
32
|
+
private _closed;
|
|
33
|
+
private closeReason;
|
|
34
|
+
onClose: ((reason?: string) => void) | null;
|
|
35
|
+
/** Every parsed frame, before routing. The PR 2 supervisor proxies from here. */
|
|
36
|
+
onRaw: ((m: RawMessage) => void) | null;
|
|
37
|
+
/**
|
|
38
|
+
* A throwing event handler or onRaw must not escape into the stream's data
|
|
39
|
+
* event (an uncaught exception would kill the daemon) nor skip the rest of
|
|
40
|
+
* the chunk. Default: one line on stderr.
|
|
41
|
+
*/
|
|
42
|
+
onError: (error: unknown, where: 'handler' | 'onRaw') => void;
|
|
43
|
+
constructor(transport: Transport);
|
|
44
|
+
get closed(): boolean;
|
|
45
|
+
get pendingCount(): number;
|
|
46
|
+
/** Number of distinct (session, method) handler keys; empty sets are pruned. */
|
|
47
|
+
get handlerKeyCount(): number;
|
|
48
|
+
/** Total registered handlers, summed over every key; a leak test's yardstick. */
|
|
49
|
+
get handlerCount(): number;
|
|
50
|
+
/**
|
|
51
|
+
* Call `listener` once when the connection closes (at once if it already
|
|
52
|
+
* has); returns the unsubscribe. Pages use it to fail in-flight work fast
|
|
53
|
+
* instead of waiting out each send's timeout.
|
|
54
|
+
*/
|
|
55
|
+
onClosed(listener: (e: Error) => void): () => void;
|
|
56
|
+
allocateId(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Throws TargetClosedError once the connection is closed, so a proxying
|
|
59
|
+
* caller (the PR 2 supervisor) learns its client message was not delivered
|
|
60
|
+
* instead of waiting for a reply that cannot come.
|
|
61
|
+
*/
|
|
62
|
+
sendRaw(message: RawMessage & {
|
|
63
|
+
id: number;
|
|
64
|
+
method: string;
|
|
65
|
+
}): void;
|
|
66
|
+
send<T = unknown>(method: string, params?: object, sessionId?: string, opts?: {
|
|
67
|
+
timeout?: number;
|
|
68
|
+
}): Promise<T>;
|
|
69
|
+
on(method: string, handler: Handler, sessionId?: string): () => void;
|
|
70
|
+
/**
|
|
71
|
+
* Without a sessionId this listens on the browser session only, where
|
|
72
|
+
* session-scoped events never arrive; pass the page's sessionId for page
|
|
73
|
+
* events.
|
|
74
|
+
*/
|
|
75
|
+
once<P = unknown>(method: string, sessionId?: string, predicate?: (p: P) => boolean): Promise<P>;
|
|
76
|
+
close(): void;
|
|
77
|
+
private dispatch;
|
|
78
|
+
private runHandlers;
|
|
79
|
+
private handleClose;
|
|
80
|
+
}
|
|
81
|
+
export {};
|