@melra/browser-runtime 0.3.0-alpha.10

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 (71) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +44 -0
  3. package/dist/browser-connection.d.ts +25 -0
  4. package/dist/browser-connection.d.ts.map +1 -0
  5. package/dist/browser-connection.js +119 -0
  6. package/dist/browser-connection.js.map +1 -0
  7. package/dist/browser-connection.test.d.ts +2 -0
  8. package/dist/browser-connection.test.d.ts.map +1 -0
  9. package/dist/browser-connection.test.js +210 -0
  10. package/dist/browser-connection.test.js.map +1 -0
  11. package/dist/dialogs.test.d.ts +2 -0
  12. package/dist/dialogs.test.d.ts.map +1 -0
  13. package/dist/dialogs.test.js +165 -0
  14. package/dist/dialogs.test.js.map +1 -0
  15. package/dist/frames.test.d.ts +2 -0
  16. package/dist/frames.test.d.ts.map +1 -0
  17. package/dist/frames.test.js +157 -0
  18. package/dist/frames.test.js.map +1 -0
  19. package/dist/history-tabs.test.d.ts +2 -0
  20. package/dist/history-tabs.test.d.ts.map +1 -0
  21. package/dist/history-tabs.test.js +171 -0
  22. package/dist/history-tabs.test.js.map +1 -0
  23. package/dist/index.d.ts +169 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +939 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/input-fidelity.test.d.ts +2 -0
  28. package/dist/input-fidelity.test.d.ts.map +1 -0
  29. package/dist/input-fidelity.test.js +260 -0
  30. package/dist/input-fidelity.test.js.map +1 -0
  31. package/dist/network-policy.d.ts +28 -0
  32. package/dist/network-policy.d.ts.map +1 -0
  33. package/dist/network-policy.js +121 -0
  34. package/dist/network-policy.js.map +1 -0
  35. package/dist/network-policy.test.d.ts +2 -0
  36. package/dist/network-policy.test.d.ts.map +1 -0
  37. package/dist/network-policy.test.js +39 -0
  38. package/dist/network-policy.test.js.map +1 -0
  39. package/dist/pinning-proxy.d.ts +8 -0
  40. package/dist/pinning-proxy.d.ts.map +1 -0
  41. package/dist/pinning-proxy.js +115 -0
  42. package/dist/pinning-proxy.js.map +1 -0
  43. package/dist/pinning-proxy.test.d.ts +2 -0
  44. package/dist/pinning-proxy.test.d.ts.map +1 -0
  45. package/dist/pinning-proxy.test.js +80 -0
  46. package/dist/pinning-proxy.test.js.map +1 -0
  47. package/dist/popups-profile.test.d.ts +2 -0
  48. package/dist/popups-profile.test.d.ts.map +1 -0
  49. package/dist/popups-profile.test.js +170 -0
  50. package/dist/popups-profile.test.js.map +1 -0
  51. package/dist/see-act.test.d.ts +2 -0
  52. package/dist/see-act.test.d.ts.map +1 -0
  53. package/dist/see-act.test.js +152 -0
  54. package/dist/see-act.test.js.map +1 -0
  55. package/dist/selector.d.ts +30 -0
  56. package/dist/selector.d.ts.map +1 -0
  57. package/dist/selector.js +39 -0
  58. package/dist/selector.js.map +1 -0
  59. package/dist/selector.test.d.ts +2 -0
  60. package/dist/selector.test.d.ts.map +1 -0
  61. package/dist/selector.test.js +34 -0
  62. package/dist/selector.test.js.map +1 -0
  63. package/dist/stable-dom.d.ts +21 -0
  64. package/dist/stable-dom.d.ts.map +1 -0
  65. package/dist/stable-dom.js +76 -0
  66. package/dist/stable-dom.js.map +1 -0
  67. package/dist/stable-dom.test.d.ts +2 -0
  68. package/dist/stable-dom.test.d.ts.map +1 -0
  69. package/dist/stable-dom.test.js +22 -0
  70. package/dist/stable-dom.test.js.map +1 -0
  71. package/package.json +33 -0
@@ -0,0 +1,39 @@
1
+ // Copyright 2026 XAGI Labs Private Limited
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /** CSS identifiers may not start with a digit and may not contain punctuation. */
4
+ const PLAIN_IDENTIFIER = /^[A-Za-z_-][\w-]*$/;
5
+ function attributeValue(value) {
6
+ return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
7
+ }
8
+ /**
9
+ * Assemble a CSS selector addressing the element the chain ends at.
10
+ *
11
+ * `snapshot` previously reported `{tag, role, name, type}` and nothing else,
12
+ * which left a caller no way to turn something it had just seen into something
13
+ * it could act on — the only remaining option was `getByText(..., {exact: true})`,
14
+ * which breaks on whitespace, casing, and nested markup. Emitting a selector
15
+ * alongside each element closes that loop.
16
+ *
17
+ * The chain runs anchor-first. Collection stops as soon as it reaches an element
18
+ * carrying an `id` or `data-testid`, so a page that labels its markup produces a
19
+ * short, re-render-durable selector; a page that does not falls back to a
20
+ * positional path, which is exact for the snapshot it came from.
21
+ */
22
+ export function buildSelector(chain) {
23
+ if (chain.length === 0)
24
+ throw new Error("browser_selector_requires_chain");
25
+ return chain
26
+ .map((step) => {
27
+ if (step.id !== undefined) {
28
+ return PLAIN_IDENTIFIER.test(step.id)
29
+ ? `#${step.id}`
30
+ : `[id="${attributeValue(step.id)}"]`;
31
+ }
32
+ if (step.testId !== undefined) {
33
+ return `[data-testid="${attributeValue(step.testId)}"]`;
34
+ }
35
+ return `${step.tag}:nth-child(${step.nth})`;
36
+ })
37
+ .join(" > ");
38
+ }
39
+ //# sourceMappingURL=selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.js","sourceRoot":"","sources":["../src/selector.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,sCAAsC;AAiBtC,kFAAkF;AAClF,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AAE9C,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,KAA0B;IACtD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC3E,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE;gBACf,CAAC,CAAC,QAAQ,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;QAC1C,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,iBAAiB,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;QAC1D,CAAC;QACD,OAAO,GAAG,IAAI,CAAC,GAAG,cAAc,IAAI,CAAC,GAAG,GAAG,CAAC;IAC9C,CAAC,CAAC;SACD,IAAI,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=selector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.test.d.ts","sourceRoot":"","sources":["../src/selector.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,34 @@
1
+ // Copyright 2026 XAGI Labs Private Limited
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { describe, expect, it } from "vitest";
4
+ import { buildSelector } from "./selector.js";
5
+ describe("buildSelector", () => {
6
+ it("anchors on an id when the page provides one", () => {
7
+ expect(buildSelector([
8
+ { tag: "form", nth: 2, id: "login" },
9
+ { tag: "input", nth: 3 },
10
+ ])).toBe("#login > input:nth-child(3)");
11
+ });
12
+ it("prefers a test id over positional descent", () => {
13
+ expect(buildSelector([
14
+ { tag: "div", nth: 1, testId: "cart" },
15
+ { tag: "button", nth: 2 },
16
+ ])).toBe('[data-testid="cart"] > button:nth-child(2)');
17
+ });
18
+ it("falls back to a positional path when nothing is labelled", () => {
19
+ expect(buildSelector([
20
+ { tag: "html", nth: 1 },
21
+ { tag: "body", nth: 2 },
22
+ { tag: "a", nth: 5 },
23
+ ])).toBe("html:nth-child(1) > body:nth-child(2) > a:nth-child(5)");
24
+ });
25
+ it("quotes an id that is not a bare CSS identifier", () => {
26
+ // Frameworks emit ids like `:r1:` and `user.email`, which `#id` cannot spell.
27
+ expect(buildSelector([{ tag: "input", nth: 1, id: ":r1:" }])).toBe('[id=":r1:"]');
28
+ expect(buildSelector([{ tag: "input", nth: 1, id: 'a"b' }])).toBe('[id="a\\"b"]');
29
+ });
30
+ it("refuses an empty chain rather than emitting a selector matching everything", () => {
31
+ expect(() => buildSelector([])).toThrow("browser_selector_requires_chain");
32
+ });
33
+ });
34
+ //# sourceMappingURL=selector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.test.js","sourceRoot":"","sources":["../src/selector.test.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,sCAAsC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CACJ,aAAa,CAAC;YACZ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE;YACpC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;SACzB,CAAC,CACH,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CACJ,aAAa,CAAC;YACZ,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE;YACtC,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE;SAC1B,CAAC,CACH,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CACJ,aAAa,CAAC;YACZ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE;YACvB,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE;YACvB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;SACrB,CAAC,CACH,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,8EAA8E;QAC9E,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAChE,aAAa,CACd,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAC/D,cAAc,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Page } from "playwright-core";
2
+ export interface DomStabilityOptions {
3
+ quietWindowMs?: number;
4
+ timeoutMs?: number;
5
+ }
6
+ export interface DomStabilityResult {
7
+ waitedMs: number;
8
+ mutationCount: number;
9
+ timedOut: boolean;
10
+ reason: "quiet_window" | "timeout" | "page_unavailable";
11
+ }
12
+ export declare function normalizeDomStabilityOptions(options?: DomStabilityOptions): Required<DomStabilityOptions>;
13
+ /**
14
+ * Wait until DOM mutations have been quiet for a bounded window.
15
+ *
16
+ * This is intentionally condition-based instead of a fixed sleep. It returns
17
+ * its own measurement so callers can distinguish a stable observation from a
18
+ * timeout and preserve that distinction in execution evidence.
19
+ */
20
+ export declare function waitForStableDom(page: Page, options?: DomStabilityOptions): Promise<DomStabilityResult>;
21
+ //# sourceMappingURL=stable-dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stable-dom.d.ts","sourceRoot":"","sources":["../src/stable-dom.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,WAAW,mBAAmB;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,cAAc,GAAG,SAAS,GAAG,kBAAkB,CAAC;CACzD;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,GAAE,mBAAwB,GAChC,QAAQ,CAAC,mBAAmB,CAAC,CAU/B;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAqE7B"}
@@ -0,0 +1,76 @@
1
+ // Copyright 2026 XAGI Labs Private Limited
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export function normalizeDomStabilityOptions(options = {}) {
4
+ const quietWindowMs = Math.max(25, Math.min(2_000, Math.round(options.quietWindowMs ?? 180)));
5
+ const timeoutMs = Math.max(quietWindowMs, Math.min(10_000, Math.round(options.timeoutMs ?? 1_500)));
6
+ return { quietWindowMs, timeoutMs };
7
+ }
8
+ /**
9
+ * Wait until DOM mutations have been quiet for a bounded window.
10
+ *
11
+ * This is intentionally condition-based instead of a fixed sleep. It returns
12
+ * its own measurement so callers can distinguish a stable observation from a
13
+ * timeout and preserve that distinction in execution evidence.
14
+ */
15
+ export async function waitForStableDom(page, options = {}) {
16
+ if (page.isClosed()) {
17
+ return {
18
+ waitedMs: 0,
19
+ mutationCount: 0,
20
+ timedOut: false,
21
+ reason: "page_unavailable",
22
+ };
23
+ }
24
+ const normalized = normalizeDomStabilityOptions(options);
25
+ try {
26
+ return await page.evaluate(({ quietWindowMs, timeoutMs }) => new Promise((resolve) => {
27
+ const startedAt = performance.now();
28
+ let mutations = 0;
29
+ let quietTimer;
30
+ let timeoutTimer;
31
+ let settled = false;
32
+ const finish = (reason, timedOut) => {
33
+ if (settled)
34
+ return;
35
+ settled = true;
36
+ observer.disconnect();
37
+ if (quietTimer !== undefined)
38
+ clearTimeout(quietTimer);
39
+ if (timeoutTimer !== undefined)
40
+ clearTimeout(timeoutTimer);
41
+ resolve({
42
+ waitedMs: Math.round(performance.now() - startedAt),
43
+ mutationCount: mutations,
44
+ timedOut,
45
+ reason,
46
+ });
47
+ };
48
+ const armQuietWindow = () => {
49
+ if (quietTimer !== undefined)
50
+ clearTimeout(quietTimer);
51
+ quietTimer = setTimeout(() => finish("quiet_window", false), quietWindowMs);
52
+ };
53
+ const observer = new MutationObserver((records) => {
54
+ mutations += records.length;
55
+ armQuietWindow();
56
+ });
57
+ observer.observe(document.documentElement, {
58
+ attributes: true,
59
+ characterData: true,
60
+ childList: true,
61
+ subtree: true,
62
+ });
63
+ timeoutTimer = setTimeout(() => finish("timeout", true), timeoutMs);
64
+ armQuietWindow();
65
+ }), normalized);
66
+ }
67
+ catch {
68
+ return {
69
+ waitedMs: 0,
70
+ mutationCount: 0,
71
+ timedOut: false,
72
+ reason: "page_unavailable",
73
+ };
74
+ }
75
+ }
76
+ //# sourceMappingURL=stable-dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stable-dom.js","sourceRoot":"","sources":["../src/stable-dom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stable-dom.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stable-dom.test.d.ts","sourceRoot":"","sources":["../src/stable-dom.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ // Copyright 2026 XAGI Labs Private Limited
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { describe, expect, it } from "vitest";
4
+ import { normalizeDomStabilityOptions } from "./stable-dom.js";
5
+ describe("DOM stability options", () => {
6
+ it("applies bounded defaults", () => {
7
+ expect(normalizeDomStabilityOptions()).toEqual({
8
+ quietWindowMs: 180,
9
+ timeoutMs: 1_500,
10
+ });
11
+ });
12
+ it("keeps the timeout at or above the quiet window", () => {
13
+ expect(normalizeDomStabilityOptions({
14
+ quietWindowMs: 900,
15
+ timeoutMs: 100,
16
+ })).toEqual({
17
+ quietWindowMs: 900,
18
+ timeoutMs: 900,
19
+ });
20
+ });
21
+ });
22
+ //# sourceMappingURL=stable-dom.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stable-dom.test.js","sourceRoot":"","sources":["../src/stable-dom.test.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,sCAAsC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAE/D,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,4BAA4B,EAAE,CAAC,CAAC,OAAO,CAAC;YAC7C,aAAa,EAAE,GAAG;YAClB,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CACJ,4BAA4B,CAAC;YAC3B,aAAa,EAAE,GAAG;YAClB,SAAS,EAAE,GAAG;SACf,CAAC,CACH,CAAC,OAAO,CAAC;YACR,aAAa,EAAE,GAAG;YAClB,SAAS,EAAE,GAAG;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@melra/browser-runtime",
3
+ "version": "0.3.0-alpha.10",
4
+ "description": "Browser reference effect adapter for the MELRA kernel.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/XAGI-Lab/melra.git",
9
+ "directory": "packages/browser-runtime"
10
+ },
11
+ "homepage": "https://github.com/XAGI-Lab/melra#readme",
12
+ "bugs": "https://github.com/XAGI-Lab/melra/issues",
13
+ "type": "module",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "dependencies": {
24
+ "playwright-core": "1.62.0",
25
+ "@melra/protocol": "0.3.0-alpha.10"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc -p tsconfig.json",
29
+ "clean": "rm -rf dist",
30
+ "test": "vitest run --testTimeout=60000 --hookTimeout=60000",
31
+ "typecheck": "tsc -p tsconfig.json --noEmit"
32
+ }
33
+ }