fast-replay 0.1.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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -0
  3. package/dist/api.d.ts +65 -0
  4. package/dist/api.js +78 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/browser.d.ts +67 -0
  7. package/dist/browser.js +77 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/cli/format.d.ts +12 -0
  10. package/dist/cli/format.js +55 -0
  11. package/dist/cli/format.js.map +1 -0
  12. package/dist/cli/index.d.ts +2 -0
  13. package/dist/cli/index.js +199 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/compiler/compile.d.ts +18 -0
  16. package/dist/compiler/compile.js +226 -0
  17. package/dist/compiler/compile.js.map +1 -0
  18. package/dist/compiler/normalize.d.ts +16 -0
  19. package/dist/compiler/normalize.js +75 -0
  20. package/dist/compiler/normalize.js.map +1 -0
  21. package/dist/compiler/waits.d.ts +31 -0
  22. package/dist/compiler/waits.js +69 -0
  23. package/dist/compiler/waits.js.map +1 -0
  24. package/dist/ir/io.d.ts +47 -0
  25. package/dist/ir/io.js +122 -0
  26. package/dist/ir/io.js.map +1 -0
  27. package/dist/ir/schema.d.ts +236 -0
  28. package/dist/ir/schema.js +153 -0
  29. package/dist/ir/schema.js.map +1 -0
  30. package/dist/mcp/index.d.ts +2 -0
  31. package/dist/mcp/index.js +22 -0
  32. package/dist/mcp/index.js.map +1 -0
  33. package/dist/mcp/server.d.ts +8 -0
  34. package/dist/mcp/server.js +268 -0
  35. package/dist/mcp/server.js.map +1 -0
  36. package/dist/noise.d.ts +20 -0
  37. package/dist/noise.js +70 -0
  38. package/dist/noise.js.map +1 -0
  39. package/dist/recorder/agent/capture.d.ts +15 -0
  40. package/dist/recorder/agent/capture.js +310 -0
  41. package/dist/recorder/agent/capture.js.map +1 -0
  42. package/dist/recorder/agent/config.d.ts +25 -0
  43. package/dist/recorder/agent/config.js +23 -0
  44. package/dist/recorder/agent/config.js.map +1 -0
  45. package/dist/recorder/agent/dom-reaction.d.ts +13 -0
  46. package/dist/recorder/agent/dom-reaction.js +166 -0
  47. package/dist/recorder/agent/dom-reaction.js.map +1 -0
  48. package/dist/recorder/agent/main.d.ts +1 -0
  49. package/dist/recorder/agent/main.js +14 -0
  50. package/dist/recorder/agent/main.js.map +1 -0
  51. package/dist/recorder/agent/page-agent.d.ts +12 -0
  52. package/dist/recorder/agent/page-agent.js +40 -0
  53. package/dist/recorder/agent/page-agent.js.map +1 -0
  54. package/dist/recorder/agent/reveal-tracker.d.ts +26 -0
  55. package/dist/recorder/agent/reveal-tracker.js +41 -0
  56. package/dist/recorder/agent/reveal-tracker.js.map +1 -0
  57. package/dist/recorder/agent/roles.d.ts +11 -0
  58. package/dist/recorder/agent/roles.js +148 -0
  59. package/dist/recorder/agent/roles.js.map +1 -0
  60. package/dist/recorder/agent/selectors.d.ts +26 -0
  61. package/dist/recorder/agent/selectors.js +256 -0
  62. package/dist/recorder/agent/selectors.js.map +1 -0
  63. package/dist/recorder/agent/text.d.ts +19 -0
  64. package/dist/recorder/agent/text.js +82 -0
  65. package/dist/recorder/agent/text.js.map +1 -0
  66. package/dist/recorder/agent/transport.d.ts +14 -0
  67. package/dist/recorder/agent/transport.js +43 -0
  68. package/dist/recorder/agent/transport.js.map +1 -0
  69. package/dist/recorder/agent/visibility.d.ts +8 -0
  70. package/dist/recorder/agent/visibility.js +20 -0
  71. package/dist/recorder/agent/visibility.js.map +1 -0
  72. package/dist/recorder/agent-bundle.generated.d.ts +2 -0
  73. package/dist/recorder/agent-bundle.generated.js +6 -0
  74. package/dist/recorder/agent-bundle.generated.js.map +1 -0
  75. package/dist/recorder/attach.d.ts +52 -0
  76. package/dist/recorder/attach.js +159 -0
  77. package/dist/recorder/attach.js.map +1 -0
  78. package/dist/recorder/instrument.d.ts +17 -0
  79. package/dist/recorder/instrument.js +24 -0
  80. package/dist/recorder/instrument.js.map +1 -0
  81. package/dist/recorder/launch.d.ts +38 -0
  82. package/dist/recorder/launch.js +72 -0
  83. package/dist/recorder/launch.js.map +1 -0
  84. package/dist/recorder/reaction.d.ts +13 -0
  85. package/dist/recorder/reaction.js +65 -0
  86. package/dist/recorder/reaction.js.map +1 -0
  87. package/dist/recorder/types.d.ts +62 -0
  88. package/dist/recorder/types.js +2 -0
  89. package/dist/recorder/types.js.map +1 -0
  90. package/dist/replayer/artifacts.d.ts +25 -0
  91. package/dist/replayer/artifacts.js +58 -0
  92. package/dist/replayer/artifacts.js.map +1 -0
  93. package/dist/replayer/invariants.d.ts +26 -0
  94. package/dist/replayer/invariants.js +109 -0
  95. package/dist/replayer/invariants.js.map +1 -0
  96. package/dist/replayer/resolve.d.ts +35 -0
  97. package/dist/replayer/resolve.js +50 -0
  98. package/dist/replayer/resolve.js.map +1 -0
  99. package/dist/replayer/run.d.ts +104 -0
  100. package/dist/replayer/run.js +467 -0
  101. package/dist/replayer/run.js.map +1 -0
  102. package/dist/replayer/values.d.ts +13 -0
  103. package/dist/replayer/values.js +76 -0
  104. package/dist/replayer/values.js.map +1 -0
  105. package/dist/replayer/waits.d.ts +25 -0
  106. package/dist/replayer/waits.js +90 -0
  107. package/dist/replayer/waits.js.map +1 -0
  108. package/dist/version.d.ts +1 -0
  109. package/dist/version.js +10 -0
  110. package/dist/version.js.map +1 -0
  111. package/package.json +77 -0
@@ -0,0 +1,90 @@
1
+ import { matchesUrlPattern } from '../compiler/normalize.js';
2
+ const NETWORK_POLL_MS = 25;
3
+ /**
4
+ * Poll the network buffer instead of attaching a fresh `waitForResponse`.
5
+ *
6
+ * A request can settle before we get around to waiting on it — the classic
7
+ * lost-wakeup race. Reading a buffer that was already recording covers the
8
+ * window between the action firing and this wait starting.
9
+ */
10
+ function waitForNetwork(ctx, method, urlPattern, timeoutMs) {
11
+ const deadline = Date.now() + timeoutMs;
12
+ const satisfied = () => ctx.network.some((n) => n.settledAt !== null &&
13
+ n.settledAt >= ctx.since &&
14
+ n.method.toUpperCase() === method.toUpperCase() &&
15
+ matchesUrlPattern(n.url, urlPattern, ctx.baseUrl));
16
+ return new Promise((resolve, reject) => {
17
+ if (satisfied())
18
+ return resolve();
19
+ const timer = setInterval(() => {
20
+ if (satisfied()) {
21
+ clearInterval(timer);
22
+ resolve();
23
+ }
24
+ else if (Date.now() > deadline) {
25
+ clearInterval(timer);
26
+ reject(new Error(`no settled ${method} matching ${urlPattern}`));
27
+ }
28
+ }, NETWORK_POLL_MS);
29
+ });
30
+ }
31
+ /**
32
+ * Wait for every recorded signal at once, with the step's timeoutMs as a single
33
+ * ceiling over all of them. Never a fixed sleep — replay proceeds the moment
34
+ * the environment actually reacts, which is where the speed comes from.
35
+ */
36
+ export async function waitForReaction(ctx, waitAfter) {
37
+ const started = Date.now();
38
+ const timeout = waitAfter.timeoutMs;
39
+ const jobs = [];
40
+ for (const n of waitAfter.network ?? []) {
41
+ jobs.push({
42
+ label: `network ${n.method} ${n.urlPattern}`,
43
+ run: waitForNetwork(ctx, n.method, n.urlPattern, timeout),
44
+ });
45
+ }
46
+ for (const selector of waitAfter.domAppeared ?? []) {
47
+ jobs.push({
48
+ label: `appeared ${selector}`,
49
+ run: ctx.page
50
+ .locator(selector)
51
+ .first()
52
+ .waitFor({ state: 'visible', timeout })
53
+ .then(() => undefined),
54
+ });
55
+ }
56
+ for (const selector of waitAfter.domGone ?? []) {
57
+ jobs.push({
58
+ label: `gone ${selector}`,
59
+ // `hidden` covers both ways an element goes away — unmounted, or still
60
+ // attached but no longer rendered. `detached` would hang forever on the
61
+ // second case. `first()` keeps this out of strict mode and resolves
62
+ // immediately when nothing matches, which is exactly "already gone".
63
+ run: ctx.page
64
+ .locator(selector)
65
+ .first()
66
+ .waitFor({ state: 'hidden', timeout })
67
+ .then(() => undefined),
68
+ });
69
+ }
70
+ if (waitAfter.networkIdle) {
71
+ jobs.push({
72
+ label: 'network idle',
73
+ run: ctx.page.waitForLoadState('networkidle', { timeout }).then(() => undefined),
74
+ });
75
+ }
76
+ if (!jobs.length)
77
+ return { ok: true, unmet: [], met: [], durationMs: 0 };
78
+ const results = await Promise.allSettled(jobs.map((j) => j.run));
79
+ const unmet = [];
80
+ const met = [];
81
+ results.forEach((r, i) => {
82
+ const label = jobs[i]?.label ?? 'signal';
83
+ if (r.status === 'fulfilled')
84
+ met.push(label);
85
+ else
86
+ unmet.push(label);
87
+ });
88
+ return { ok: unmet.length === 0, unmet, met, durationMs: Date.now() - started };
89
+ }
90
+ //# sourceMappingURL=waits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waits.js","sourceRoot":"","sources":["../../src/replayer/waits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const VERSION: string;
@@ -0,0 +1,10 @@
1
+ import { createRequire } from 'node:module';
2
+ /**
3
+ * Single source of truth for the version, read from the manifest.
4
+ *
5
+ * Two builds both reporting 0.1.0 made them indistinguishable in the field —
6
+ * the only way to tell them apart was grepping dist/ for a feature string.
7
+ */
8
+ const require = createRequire(import.meta.url);
9
+ export const VERSION = require('../package.json').version;
10
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,OAAO,GAAY,OAAO,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC"}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "fast-replay",
3
+ "version": "0.1.0",
4
+ "description": "Record a browser bug once, verify the fix in seconds. A deterministic eye for coding agents.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "bin": {
11
+ "repro": "./dist/cli/index.js",
12
+ "repro-mcp": "./dist/mcp/index.js"
13
+ },
14
+ "main": "./dist/api.js",
15
+ "types": "./dist/api.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/api.d.ts",
19
+ "import": "./dist/api.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsc -p tsconfig.build.json",
29
+ "dev": "tsc -p tsconfig.build.json --watch",
30
+ "typecheck": "tsc --noEmit",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest",
33
+ "stress": "tsx scripts/stress.ts",
34
+ "demo": "npm --prefix examples/demo-app run dev",
35
+ "build:agent": "tsx scripts/build-agent.ts",
36
+ "prebuild": "npm run build:agent",
37
+ "pretest": "npm run build:agent",
38
+ "prestress": "npm run build:agent",
39
+ "prepare": "npm run build"
40
+ },
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.29.0",
43
+ "commander": "^14.0.3",
44
+ "playwright": "^1.61.1",
45
+ "zod": "^4.4.3"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^22.10.0",
49
+ "esbuild": "^0.28.1",
50
+ "tsx": "^4.19.2",
51
+ "typescript": "^5.7.2",
52
+ "vitest": "^4.1.10"
53
+ },
54
+ "author": "Mukhriddin Shakhriyorov",
55
+ "keywords": [
56
+ "bug",
57
+ "repro",
58
+ "reproduction",
59
+ "playwright",
60
+ "mcp",
61
+ "testing",
62
+ "debugging",
63
+ "browser",
64
+ "automation",
65
+ "claude",
66
+ "agent",
67
+ "ai"
68
+ ],
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "git+https://github.com/mukhrr/replay.git"
72
+ },
73
+ "bugs": {
74
+ "url": "https://github.com/mukhrr/replay/issues"
75
+ },
76
+ "homepage": "https://github.com/mukhrr/replay#readme"
77
+ }