@ait-co/devtools 0.1.136 → 0.1.138
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/{attach-orchestrator-Cjdhir2U.js → attach-orchestrator-6kz_ZdWL.js} +5 -3
- package/dist/{attach-orchestrator-Cjdhir2U.js.map → attach-orchestrator-6kz_ZdWL.js.map} +1 -1
- package/dist/{attach-orchestrator-CE0S09YU.js → attach-orchestrator-BEiz3wAx.js} +5 -3
- package/dist/{attach-orchestrator-CMoDuG2A.js.map → attach-orchestrator-BEiz3wAx.js.map} +1 -1
- package/dist/{attach-orchestrator-CMoDuG2A.js → attach-orchestrator-BG8TGJOZ.js} +5 -3
- package/dist/{attach-orchestrator-CE0S09YU.js.map → attach-orchestrator-BG8TGJOZ.js.map} +1 -1
- package/dist/{bundle-BKqyhEK9.d.ts → bundle-C796JIwG.d.ts} +65 -2
- package/dist/bundle-C796JIwG.d.ts.map +1 -0
- package/dist/{capture-ltuV0gZa.d.ts → capture-DsP525OZ.d.ts} +1 -1
- package/dist/{capture-ltuV0gZa.d.ts.map → capture-DsP525OZ.d.ts.map} +1 -1
- package/dist/{cdp-connection-BYE9meXe.d.ts → cdp-connection-rP1WdnH5.d.ts} +1 -1
- package/dist/{cdp-connection-BYE9meXe.d.ts.map → cdp-connection-rP1WdnH5.d.ts.map} +1 -1
- package/dist/{cell-D1y4shoV.js → cell-BMlFh08P.js} +2 -2
- package/dist/cell-BMlFh08P.js.map +1 -0
- package/dist/{cell-DHA578lX.js → cell-Dtgtusog.js} +90 -16
- package/dist/cell-Dtgtusog.js.map +1 -0
- package/dist/{cell-BIdSQb9T.js → cell-KsRXFdDs.js} +122 -16
- package/dist/cell-KsRXFdDs.js.map +1 -0
- package/dist/{debug-server-BZtH2Z5b.js → debug-server-6c22qSWa.js} +150 -9
- package/dist/debug-server-6c22qSWa.js.map +1 -0
- package/dist/{debug-server-DApo0o3t.js → debug-server-BQHbaKPT.js} +152 -11
- package/dist/debug-server-BQHbaKPT.js.map +1 -0
- package/dist/{debug-server-D2wpPK3_.js → debug-server-DWat7d-9.js} +82 -6
- package/dist/debug-server-DWat7d-9.js.map +1 -0
- package/dist/devtools-opener-3Drge_RJ.js +75 -0
- package/dist/devtools-opener-3Drge_RJ.js.map +1 -0
- package/dist/devtools-opener-CJpEsXXQ.js +76 -0
- package/dist/devtools-opener-CJpEsXXQ.js.map +1 -0
- package/dist/devtools-opener-CxtryS8c.js +75 -0
- package/dist/devtools-opener-CxtryS8c.js.map +1 -0
- package/dist/in-app/auto.js +59 -12
- package/dist/in-app/auto.js.map +1 -1
- package/dist/in-app/index.d.ts +21 -2
- package/dist/in-app/index.d.ts.map +1 -1
- package/dist/in-app/index.js +60 -13
- package/dist/in-app/index.js.map +1 -1
- package/dist/mcp/cli.js +363 -73
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mock/index.d.ts +64 -1
- package/dist/mock/index.d.ts.map +1 -1
- package/dist/mock/index.js +221 -14
- package/dist/mock/index.js.map +1 -1
- package/dist/panel/index.js +178 -23
- package/dist/panel/index.js.map +1 -1
- package/dist/{pool-C6TgrcyW.d.ts → pool-CrP5CPvU.d.ts} +3 -3
- package/dist/{pool-C6TgrcyW.d.ts.map → pool-CrP5CPvU.d.ts.map} +1 -1
- package/dist/{qr-http-server-ZkT6F7is.js → qr-http-server-D1hpoyBF.js} +1 -1
- package/dist/{qr-http-server-ZkT6F7is.js.map → qr-http-server-D1hpoyBF.js.map} +1 -1
- package/dist/qr-http-server-D4rGz8M7.js +1640 -0
- package/dist/qr-http-server-D4rGz8M7.js.map +1 -0
- package/dist/{qr-http-server-C7q8Gn04.js → qr-http-server-DIjCV7h_.js} +1 -1
- package/dist/{qr-http-server-C7q8Gn04.js.map → qr-http-server-DIjCV7h_.js.map} +1 -1
- package/dist/{relay-factory-DnuTH4v-.js → relay-factory-C1X3G3WY.js} +72 -15
- package/dist/relay-factory-C1X3G3WY.js.map +1 -0
- package/dist/{relay-secret-store-CLEGyHou.js → relay-secret-store-Bmyleu0A.js} +1 -1
- package/dist/{relay-secret-store-CLEGyHou.js.map → relay-secret-store-Bmyleu0A.js.map} +1 -1
- package/dist/{relay-secret-store-DhzAnnj-.js → relay-secret-store-CQenfcSL.js} +2 -2
- package/dist/{relay-secret-store-DhzAnnj-.js.map → relay-secret-store-CQenfcSL.js.map} +1 -1
- package/dist/{relay-secret-store-BcVrWwTq.js → relay-secret-store-DKxs7zwq.js} +1 -1
- package/dist/{relay-secret-store-DGduVJhs.js.map → relay-secret-store-DKxs7zwq.js.map} +1 -1
- package/dist/{relay-secret-store-DGduVJhs.js → relay-secret-store-WJ8EGkIl.js} +1 -1
- package/dist/{relay-secret-store-BcVrWwTq.js.map → relay-secret-store-WJ8EGkIl.js.map} +1 -1
- package/dist/{relay-url-store-CKW8RQzf.js → relay-url-store-BR2XodiO.js} +2 -2
- package/dist/{relay-url-store-CKW8RQzf.js.map → relay-url-store-BR2XodiO.js.map} +1 -1
- package/dist/{relay-url-store-CdA58fgw.js → relay-url-store-CH63fVCm.js} +2 -2
- package/dist/{relay-url-store-B0X8TsGr.js.map → relay-url-store-CH63fVCm.js.map} +1 -1
- package/dist/{relay-url-store-CwKT7i04.js → relay-url-store-DaY1QPes.js} +2 -2
- package/dist/{relay-url-store-CwKT7i04.js.map → relay-url-store-DaY1QPes.js.map} +1 -1
- package/dist/{relay-url-store-B0X8TsGr.js → relay-url-store-xmUuTjXA.js} +2 -2
- package/dist/{relay-url-store-CdA58fgw.js.map → relay-url-store-xmUuTjXA.js.map} +1 -1
- package/dist/{relay-worker-UK0nBfDX.js → relay-worker-BUXI0K0b.js} +13 -6
- package/dist/{relay-worker-UK0nBfDX.js.map → relay-worker-BUXI0K0b.js.map} +1 -1
- package/dist/{relay-worker-Dw3aIzIK.d.ts → relay-worker-DcyboK43.d.ts} +70 -11
- package/dist/relay-worker-DcyboK43.d.ts.map +1 -0
- package/dist/{runtime-DfHHZms2.d.ts → runtime-BiigOuvb.d.ts} +30 -3
- package/dist/runtime-BiigOuvb.d.ts.map +1 -0
- package/dist/test-runner/bin.js +481 -62
- package/dist/test-runner/bin.js.map +1 -1
- package/dist/test-runner/bridge-stub.d.ts +125 -0
- package/dist/test-runner/bridge-stub.d.ts.map +1 -0
- package/dist/test-runner/bridge-stub.js +92 -0
- package/dist/test-runner/bridge-stub.js.map +1 -0
- package/dist/test-runner/bundle.d.ts +2 -2
- package/dist/test-runner/bundle.js +107 -24
- package/dist/test-runner/bundle.js.map +1 -1
- package/dist/test-runner/capture.d.ts +1 -1
- package/dist/test-runner/config.d.ts +68 -5
- package/dist/test-runner/config.d.ts.map +1 -1
- package/dist/test-runner/config.js +1 -1
- package/dist/test-runner/method-pace.d.ts +82 -0
- package/dist/test-runner/method-pace.d.ts.map +1 -0
- package/dist/test-runner/method-pace.js +120 -0
- package/dist/test-runner/method-pace.js.map +1 -0
- package/dist/test-runner/pool.d.ts +1 -1
- package/dist/test-runner/pool.js +1 -1
- package/dist/test-runner/relay-factory.d.ts +67 -4
- package/dist/test-runner/relay-factory.d.ts.map +1 -1
- package/dist/test-runner/relay-factory.js +71 -14
- package/dist/test-runner/relay-factory.js.map +1 -1
- package/dist/test-runner/relay-worker.d.ts +1 -1
- package/dist/test-runner/relay-worker.js +1 -1
- package/dist/test-runner/report.d.ts +43 -17
- package/dist/test-runner/report.d.ts.map +1 -1
- package/dist/test-runner/report.js +33 -9
- package/dist/test-runner/report.js.map +1 -1
- package/dist/test-runner/rpc.d.ts +2 -2
- package/dist/test-runner/runtime.d.ts +2 -2
- package/dist/test-runner/runtime.js +83 -6
- package/dist/test-runner/runtime.js.map +1 -1
- package/dist/test-runner/task-graph.d.ts +1 -1
- package/dist/throttle-DKKzX1qC.js +59 -0
- package/dist/throttle-DKKzX1qC.js.map +1 -0
- package/dist/totp-Dwft0Kz7.js +3 -0
- package/package.json +1 -1
- package/dist/bundle-BKqyhEK9.d.ts.map +0 -1
- package/dist/cell-BIdSQb9T.js.map +0 -1
- package/dist/cell-D1y4shoV.js.map +0 -1
- package/dist/cell-DHA578lX.js.map +0 -1
- package/dist/debug-server-BZtH2Z5b.js.map +0 -1
- package/dist/debug-server-D2wpPK3_.js.map +0 -1
- package/dist/debug-server-DApo0o3t.js.map +0 -1
- package/dist/relay-factory-DnuTH4v-.js.map +0 -1
- package/dist/relay-worker-Dw3aIzIK.d.ts.map +0 -1
- package/dist/runtime-DfHHZms2.d.ts.map +0 -1
- package/dist/totp-D1pulXLa.js +0 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as createRelayPool, n as RelayConnectionFactory, t as RELAY_POOL_NAME } from "../pool-
|
|
1
|
+
import { i as createRelayPool, n as RelayConnectionFactory, t as RELAY_POOL_NAME } from "../pool-CrP5CPvU.js";
|
|
2
2
|
|
|
3
3
|
//#region src/test-runner/relay-factory.d.ts
|
|
4
4
|
/** Options for {@link createRelayConnectionFactory}. */
|
|
@@ -7,8 +7,36 @@ interface RelayConnectionFactoryOptions {
|
|
|
7
7
|
* intoss-private:// scheme URL from `ait deploy --scheme-only` (env3). The
|
|
8
8
|
* phone cold-loads the candidate bundle this URL points at. SECRET-HANDLING:
|
|
9
9
|
* never logged.
|
|
10
|
+
*
|
|
11
|
+
* Ignored when {@link attachLauncher} is `true` — the env-2 launcher path
|
|
12
|
+
* builds its attach URL from {@link appUrl} + the relay wss, not a scheme URL.
|
|
13
|
+
* Pass `''` in that case.
|
|
10
14
|
*/
|
|
11
15
|
schemeUrl: string;
|
|
16
|
+
/**
|
|
17
|
+
* env-2 (AITC Sandbox PWA) attach mode (devtools#774). When `true`, `open()`
|
|
18
|
+
* builds the attach URL as a **launcher deep-link**
|
|
19
|
+
* (`buildLauncherAttachUrl(appUrl, wssUrl, totp)` — the same env-2 path the
|
|
20
|
+
* MCP daemon takes via `prepareAttach(deps, 'relay-mobile', …)`, issue #378)
|
|
21
|
+
* instead of an intoss-private scheme deep-link. The relay boot, QR
|
|
22
|
+
* rendering, dashboard, and attach-wait are byte-for-byte identical to env 3;
|
|
23
|
+
* only the URL family differs. Omitted/false keeps the env-3 scheme path
|
|
24
|
+
* unchanged (zero behavior change).
|
|
25
|
+
*/
|
|
26
|
+
attachLauncher?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The consumer dev server's HTTP tunnel URL (e.g. an sdk-example
|
|
29
|
+
* `dev:phone:cdp` `*.trycloudflare.com` URL) that the launcher PWA frames.
|
|
30
|
+
* REQUIRED when {@link attachLauncher} is `true`; ignored otherwise.
|
|
31
|
+
*
|
|
32
|
+
* Threaded to the `relay-mobile` `prepareAttach` branch via the
|
|
33
|
+
* `AIT_TUNNEL_BASE_URL` env var (the same key the MCP daemon reads), so the
|
|
34
|
+
* exact same env-2 assembly runs — no divergent code path.
|
|
35
|
+
*
|
|
36
|
+
* SECRET-HANDLING: this is a tunnel host at the same sensitivity as the relay
|
|
37
|
+
* wss — NEVER logged. It rides only inside the QR/dashboard attach capsule.
|
|
38
|
+
*/
|
|
39
|
+
appUrl?: string;
|
|
12
40
|
/**
|
|
13
41
|
* Project root for the `.ait_relay` secret lookup (read-only). Defaults to
|
|
14
42
|
* `process.cwd()`.
|
|
@@ -35,6 +63,40 @@ interface RelayConnectionFactoryOptions {
|
|
|
35
63
|
sdkLine: string;
|
|
36
64
|
platform: string;
|
|
37
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* When `true`, injects `__AIT_STUB_BLOCKING__ = true` before the first test
|
|
68
|
+
* bundle runs (devtools#740, DT-2) — `bundle.ts`'s sdk-redirect module reads
|
|
69
|
+
* this flag via `isStubBlockingEnabled()` and answers the blocking-UI APIs
|
|
70
|
+
* in `bridge-stub.ts`'s `STUB_REGISTRY` from fixtures instead of forwarding
|
|
71
|
+
* them to native. Optional — omitted/false means no flag is injected, which
|
|
72
|
+
* is byte-for-byte the pre-#740 behavior (the sdk-redirect module treats
|
|
73
|
+
* absence the same as `false`). Not a secret.
|
|
74
|
+
*/
|
|
75
|
+
stubBlocking?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Injects `__AIT_PACE_MS__ = paceMs` before the first test bundle runs
|
|
78
|
+
* (devtools#767) — `runtime.ts`'s test-execution loop reads this page
|
|
79
|
+
* global and waits `paceMs` before every test after the first one that
|
|
80
|
+
* actually runs. Optional — omitted/0 means no flag is injected, which is
|
|
81
|
+
* byte-for-byte the pre-#767 behavior (the loop treats an absent/non-
|
|
82
|
+
* positive value as "no pacing"). Not a secret. This is the PAGE-side half
|
|
83
|
+
* of `--pace`; the RUNNER-side (file-to-file) half is a plain `opts.paceMs`
|
|
84
|
+
* forwarded to `runTestFilesOverRelay` by the caller (cli.ts) — this
|
|
85
|
+
* factory only owns the page-global injection.
|
|
86
|
+
*/
|
|
87
|
+
paceMs?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Injects `__AIT_PACE_METHOD_MS__ = paceMethodMs` before the first test
|
|
90
|
+
* bundle runs (devtools#769) — `bundle.ts`'s sdk-redirect virtual module
|
|
91
|
+
* reads this page global via `method-pace.ts#getPaceMethodMs()` and paces
|
|
92
|
+
* every SDK call to a minimum interval BETWEEN calls to the SAME named
|
|
93
|
+
* function, independent of `--pace`'s test-to-test/file-to-file spacing.
|
|
94
|
+
* Optional — omitted/0 means no flag is injected, which is byte-for-byte
|
|
95
|
+
* the pre-#769 behavior (`getPaceMethodMs()` treats an absent/non-positive
|
|
96
|
+
* value as "no pacing", and `wrapWithMethodPacing` returns the SDK object
|
|
97
|
+
* untouched in that case). Not a secret.
|
|
98
|
+
*/
|
|
99
|
+
paceMethodMs?: number;
|
|
38
100
|
/**
|
|
39
101
|
* Overrides the dashboard HTTP server's bind base port (devtools#752).
|
|
40
102
|
* Threaded straight through to `startQrHttpServer`'s `dashboardPort`
|
|
@@ -62,12 +124,13 @@ interface RelayConnectionFactoryOptions {
|
|
|
62
124
|
onQrContent: (textChunks: string[]) => void;
|
|
63
125
|
}
|
|
64
126
|
/**
|
|
65
|
-
* Builds a {@link RelayConnectionFactory} that opens a standalone
|
|
66
|
-
* connection
|
|
127
|
+
* Builds a {@link RelayConnectionFactory} that opens a standalone relay
|
|
128
|
+
* connection for env 3 (intoss-private scheme, default) or env 2 (AITC Sandbox
|
|
129
|
+
* PWA launcher deep-link, when `opts.attachLauncher` is set — devtools#774).
|
|
67
130
|
*
|
|
68
131
|
* `open()` performs the full attach lifecycle and BLOCKS while a human scans
|
|
69
|
-
* the rendered QR with their phone — there is no way around the manual scan
|
|
70
|
-
*
|
|
132
|
+
* the rendered QR with their phone — there is no way around the manual scan.
|
|
133
|
+
* By default the wait is UNBOUNDED (`opts.timeoutMs` omitted): the
|
|
71
134
|
* runner stays up until the user stops it (Ctrl-C/SIGTERM), since QR-scan is
|
|
72
135
|
* a human-paced action with no sound default bound (devtools#735). Passing an
|
|
73
136
|
* explicit `timeoutMs` opts into the old bounded behavior (CI/headless
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","names":[],"sources":["../../src/test-runner/relay-factory.ts","../../src/test-runner/config.ts"],"mappings":";;;;UAiDiB,6BAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","names":[],"sources":["../../src/test-runner/relay-factory.ts","../../src/test-runner/config.ts"],"mappings":";;;;UAiDiB,6BAAA;ECrBe;;;;;;AAkBhC;;;EDaE,SAAA;ECZA;;;;;AAkBF;;;;;EDKE,cAAA;ECLuE;;;AAczE;;;;;;;;;EDIE,MAAA;ECEW;AAIb;;;EDDE,WAAA;ECC6C;;;;;;AAkC/C;;;EDzBE,SAAA;ECyBkD;EDvBlD,QAAA;ECuB0E;;;;;EDjB1E,IAAA;IAAS,OAAA;IAAiB,QAAA;EAAA;;;;;;;;;;EAU1B,YAAA;;;;;;;;;;;;EAYA,MAAA;;;;;;;;;;;;EAYA,YAAA;;;;;;;;EAQA,aAAA;;;;;;;;;;;;;;;;;EAiBA,WAAA,GAAc,UAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAqBA,4BAAA,CACd,IAAA,EAAM,6BAAA,GACL,sBAAA;;;;;;UChKc,eAAA;ED8JD;;;;ECzJd,OAAA;ED0JA;;;ECtJA,SAAA;;;;AATF;EAcE,cAAA;AAAA;;UAIe,mBAAA;EACf,OAAA;EACA,SAAA;EACA,cAAA;AAAA;AAHF;;;;;;;AAAA,iBAmBgB,qBAAA,CAAsB,UAAA,GAAa,mBAAA,GAAsB,eAAA;;AAAzE;;;;;UAciB,qBAAA;EAdwD;EAgBvE,IAAA,EAAM,UAAA,QAAkB,eAAA;EAhB8D;EAkBtF,OAAA;EAJoC;EAMpC,WAAA;AAAA;;UAIe,qBAAA,SAA8B,mBAAA;EARrB;;;;;AAQ1B;;EAQE,UAAA,EAAY,sBAAA;EARoD;;;;;;;EAgBhE,eAAA;AAAA;;;;;;;;;;;;;;;;iBAkBc,uBAAA,CAAwB,UAAA,EAAY,qBAAA,GAAwB,qBAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RELAY_POOL_NAME, createRelayPool } from "./pool.js";
|
|
2
|
-
import { t as createRelayConnectionFactory } from "../relay-factory-
|
|
2
|
+
import { t as createRelayConnectionFactory } from "../relay-factory-C1X3G3WY.js";
|
|
3
3
|
//#region src/test-runner/config.ts
|
|
4
4
|
const DEFAULT_CONFIG = {
|
|
5
5
|
include: ["**/*.ait.test.ts"],
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/test-runner/method-pace.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Per-method minimum-interval pacing for SDK calls (devtools#769).
|
|
4
|
+
*
|
|
5
|
+
* #767's `--pace` inserts delays BETWEEN test files / test-to-test — it has no
|
|
6
|
+
* effect on a burst of same-method calls WITHIN a single test body (e.g. a
|
|
7
|
+
* clipboard happy-path loop calling `setClipboardText`/`getClipboardText`
|
|
8
|
+
* eight times back to back). Real-device observation (sdk-example#293,
|
|
9
|
+
* 2.x×iOS) showed that burst alone is enough to saturate the native
|
|
10
|
+
* per-method bridge rate limit (`APP_BRIDGE_THROTTLED`, devtools#767/throttle.ts)
|
|
11
|
+
* even though `--pace`'s file/test spacing was already in effect — the
|
|
12
|
+
* limiter reacts to burst cadence within a method name, not just across test
|
|
13
|
+
* boundaries.
|
|
14
|
+
*
|
|
15
|
+
* This module wraps `window.__sdk` (the same bridge object `bundle.ts`'s
|
|
16
|
+
* `sdkRedirectPlugin` redirects SDK imports to) so that every call to the
|
|
17
|
+
* SAME named function waits out a minimum gap since that function's PREVIOUS
|
|
18
|
+
* invocation before the real call proceeds. Preflight (`cell.ts`) proved the
|
|
19
|
+
* inverse case empirically: a steady 250ms sequential cadence passes cleanly
|
|
20
|
+
* where an unpaced burst does not — sequential-with-spacing is the fix this
|
|
21
|
+
* module generalizes to every SDK call, not just the six permission probes.
|
|
22
|
+
*
|
|
23
|
+
* Runs entirely on the PAGE side (browser-compatible, no Node APIs) — bundled
|
|
24
|
+
* into the injected IIFE by `bundle.ts`'s `sdkRedirectPlugin`, the same way
|
|
25
|
+
* `bridge-stub.ts` and `runtime.ts` are. Imported ONLY from the test-runner
|
|
26
|
+
* (never from `sdk-example/src` — boilerplate cleanliness, umbrella §1.4).
|
|
27
|
+
*
|
|
28
|
+
* SECRET-HANDLING: this module carries no secrets — only method names and
|
|
29
|
+
* millisecond timestamps/durations.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Reads the page-global `__AIT_PACE_METHOD_MS__` gap value (devtools#769),
|
|
33
|
+
* injected by `relay-factory.ts` the same way `__AIT_PACE_MS__`/`__AIT_CELL__`
|
|
34
|
+
* are (`cell.ts#injectGlobals`). Absent/non-positive resolves to `0` — the
|
|
35
|
+
* same "treat absence as zero" contract `runtime.ts`'s `__AIT_PACE_MS__` read
|
|
36
|
+
* uses.
|
|
37
|
+
*/
|
|
38
|
+
declare function getPaceMethodMs(): number;
|
|
39
|
+
/**
|
|
40
|
+
* Wraps an SDK-shaped bridge object (`window.__sdk`, or the already
|
|
41
|
+
* stub-wrapped result of `bridge-stub.ts#wrapSdkWithStub`) so that every
|
|
42
|
+
* function-valued export is paced to a minimum `gapMs` interval between
|
|
43
|
+
* calls to the SAME name (devtools#769). Non-function exports (constants,
|
|
44
|
+
* etc.) and classes (`PermissionError`, etc. — wrapping a class would break
|
|
45
|
+
* `new`, see `isClass`) pass through completely untouched.
|
|
46
|
+
*
|
|
47
|
+
* **Composition with bridge-stub (devtools#740)**: this wrapper is applied to
|
|
48
|
+
* the RAW `window.__sdk` object, and `wrapSdkWithStub` is applied on TOP of
|
|
49
|
+
* the paced result (`wrapSdkWithStub(wrapWithMethodPacing(rawSdk, gapMs),
|
|
50
|
+
* stubEnabled)` — see `bundle.ts`'s sdk-redirect virtual module). This means
|
|
51
|
+
* pacing sits BEHIND the stub interception: a stubbed name
|
|
52
|
+
* (`STUB_REGISTRY` — `openPermissionDialog`, `requestPermission`,
|
|
53
|
+
* `saveBase64Data`, `showFullScreenAd`) resolves instantly from the fixture
|
|
54
|
+
* with no added delay, because `wrapSdkWithStub`'s Proxy intercepts the
|
|
55
|
+
* property access before the paced function is ever reached. Only calls that
|
|
56
|
+
* fall through to the REAL bridge — the ones that actually risk
|
|
57
|
+
* `APP_BRIDGE_THROTTLED` — pay the pacing cost. Fixed by this ordering, not
|
|
58
|
+
* incidental: swapping it (pacing outside the stub) would pace fixture
|
|
59
|
+
* look-ups that can never hit the native rate limiter, for no benefit.
|
|
60
|
+
*
|
|
61
|
+
* `gapMs <= 0` (the default, no `--pace-method` / non-2.x cell) returns `sdk`
|
|
62
|
+
* itself, untouched — the exact object identity is preserved so the
|
|
63
|
+
* zero-diff-when-off contract holds under strict-equality checks, matching
|
|
64
|
+
* `wrapSdkWithStub`'s own `enabled === false` fast path.
|
|
65
|
+
*
|
|
66
|
+
* **Memoization**: wrapper functions are cached per name in a `Map` local to
|
|
67
|
+
* this call's `Proxy` (`wrapperCache` below), so repeated property access on
|
|
68
|
+
* the SAME `sdk` object within a single `wrapWithMethodPacing` call returns
|
|
69
|
+
* the SAME wrapper reference. This cache does NOT persist across separate
|
|
70
|
+
* `wrapWithMethodPacing` calls — each call (e.g. the sdk-redirect virtual
|
|
71
|
+
* module re-evaluated per test file bundle) gets its own fresh `Map` and
|
|
72
|
+
* therefore its own wrapper function instances, even for the same method
|
|
73
|
+
* name. That's fine for pacing correctness: the actual timing state lives in
|
|
74
|
+
* the page-global `getRegistry()` map (keyed by method name, not by wrapper
|
|
75
|
+
* identity), so cross-bundle pacing still works. But callers should NOT
|
|
76
|
+
* assume cross-call function identity — only "same wrapper within one call"
|
|
77
|
+
* is guaranteed.
|
|
78
|
+
*/
|
|
79
|
+
declare function wrapWithMethodPacing(sdk: Record<string, unknown>, gapMs: number): Record<string, unknown>;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { getPaceMethodMs, wrapWithMethodPacing };
|
|
82
|
+
//# sourceMappingURL=method-pace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"method-pace.d.ts","names":[],"sources":["../../src/test-runner/method-pace.ts"],"mappings":";;AAmFA;;;;;AA4EA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA5EgB,eAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4EA,oBAAA,CACd,GAAA,EAAK,MAAA,mBACL,KAAA,WACC,MAAA"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//#region src/test-runner/method-pace.ts
|
|
2
|
+
const REGISTRY_KEY = "__AIT_METHOD_PACE_STATE__";
|
|
3
|
+
/** Reads (or lazily creates) the page-global per-method pacing registry. */
|
|
4
|
+
function getRegistry() {
|
|
5
|
+
const g = globalThis;
|
|
6
|
+
let state = g[REGISTRY_KEY];
|
|
7
|
+
if (!(state instanceof Map)) {
|
|
8
|
+
state = /* @__PURE__ */ new Map();
|
|
9
|
+
g[REGISTRY_KEY] = state;
|
|
10
|
+
}
|
|
11
|
+
return state;
|
|
12
|
+
}
|
|
13
|
+
/** `setTimeout`-based sleep — no Node APIs, safe on the page side. */
|
|
14
|
+
function sleep(ms) {
|
|
15
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* True when `value` is a `class` declaration rather than a plain callable
|
|
19
|
+
* function. The SDK export surface includes at least one class (`PermissionError`,
|
|
20
|
+
* `src/__typecheck.ts`/`bridge-stub.ts` both reference it) — wrapping a class
|
|
21
|
+
* in an async arrow function would silently break `new PermissionError()`
|
|
22
|
+
* (arrow functions are not constructible), so classes must pass through
|
|
23
|
+
* `wrapWithMethodPacing` unwrapped exactly like any other non-callable
|
|
24
|
+
* export. Detected via `Function.prototype.toString` starting with
|
|
25
|
+
* `"class "` — the standard, spec-guaranteed way to distinguish a class from
|
|
26
|
+
* an ordinary function at runtime (no Babel/TS transform in this bundle
|
|
27
|
+
* target — `target: 'es2022'` in `bundle.ts` — down-compiles `class` to a
|
|
28
|
+
* function, so this check remains reliable for esbuild's es2022 output).
|
|
29
|
+
*/
|
|
30
|
+
function isClass(value) {
|
|
31
|
+
return Function.prototype.toString.call(value).startsWith("class ");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reads the page-global `__AIT_PACE_METHOD_MS__` gap value (devtools#769),
|
|
35
|
+
* injected by `relay-factory.ts` the same way `__AIT_PACE_MS__`/`__AIT_CELL__`
|
|
36
|
+
* are (`cell.ts#injectGlobals`). Absent/non-positive resolves to `0` — the
|
|
37
|
+
* same "treat absence as zero" contract `runtime.ts`'s `__AIT_PACE_MS__` read
|
|
38
|
+
* uses.
|
|
39
|
+
*/
|
|
40
|
+
function getPaceMethodMs() {
|
|
41
|
+
const raw = globalThis.__AIT_PACE_METHOD_MS__;
|
|
42
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Wraps a single named SDK function so that calls to it wait out `gapMs`
|
|
46
|
+
* since the function's own previous invocation (tracked in the shared
|
|
47
|
+
* `getRegistry()` map, keyed by `name`) before the real `fn` runs. The
|
|
48
|
+
* result/rejection of `fn` passes through completely unchanged — pacing
|
|
49
|
+
* never alters contract-observed behavior, only its timing.
|
|
50
|
+
*/
|
|
51
|
+
function buildPacedFunction(name, fn, gapMs) {
|
|
52
|
+
return async (...args) => {
|
|
53
|
+
const registry = getRegistry();
|
|
54
|
+
const now = performance.now();
|
|
55
|
+
const lastInvokeAt = registry.get(name);
|
|
56
|
+
if (lastInvokeAt !== void 0) {
|
|
57
|
+
const elapsed = now - lastInvokeAt;
|
|
58
|
+
if (elapsed < gapMs) await sleep(gapMs - elapsed);
|
|
59
|
+
}
|
|
60
|
+
registry.set(name, performance.now());
|
|
61
|
+
return fn(...args);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Wraps an SDK-shaped bridge object (`window.__sdk`, or the already
|
|
66
|
+
* stub-wrapped result of `bridge-stub.ts#wrapSdkWithStub`) so that every
|
|
67
|
+
* function-valued export is paced to a minimum `gapMs` interval between
|
|
68
|
+
* calls to the SAME name (devtools#769). Non-function exports (constants,
|
|
69
|
+
* etc.) and classes (`PermissionError`, etc. — wrapping a class would break
|
|
70
|
+
* `new`, see `isClass`) pass through completely untouched.
|
|
71
|
+
*
|
|
72
|
+
* **Composition with bridge-stub (devtools#740)**: this wrapper is applied to
|
|
73
|
+
* the RAW `window.__sdk` object, and `wrapSdkWithStub` is applied on TOP of
|
|
74
|
+
* the paced result (`wrapSdkWithStub(wrapWithMethodPacing(rawSdk, gapMs),
|
|
75
|
+
* stubEnabled)` — see `bundle.ts`'s sdk-redirect virtual module). This means
|
|
76
|
+
* pacing sits BEHIND the stub interception: a stubbed name
|
|
77
|
+
* (`STUB_REGISTRY` — `openPermissionDialog`, `requestPermission`,
|
|
78
|
+
* `saveBase64Data`, `showFullScreenAd`) resolves instantly from the fixture
|
|
79
|
+
* with no added delay, because `wrapSdkWithStub`'s Proxy intercepts the
|
|
80
|
+
* property access before the paced function is ever reached. Only calls that
|
|
81
|
+
* fall through to the REAL bridge — the ones that actually risk
|
|
82
|
+
* `APP_BRIDGE_THROTTLED` — pay the pacing cost. Fixed by this ordering, not
|
|
83
|
+
* incidental: swapping it (pacing outside the stub) would pace fixture
|
|
84
|
+
* look-ups that can never hit the native rate limiter, for no benefit.
|
|
85
|
+
*
|
|
86
|
+
* `gapMs <= 0` (the default, no `--pace-method` / non-2.x cell) returns `sdk`
|
|
87
|
+
* itself, untouched — the exact object identity is preserved so the
|
|
88
|
+
* zero-diff-when-off contract holds under strict-equality checks, matching
|
|
89
|
+
* `wrapSdkWithStub`'s own `enabled === false` fast path.
|
|
90
|
+
*
|
|
91
|
+
* **Memoization**: wrapper functions are cached per name in a `Map` local to
|
|
92
|
+
* this call's `Proxy` (`wrapperCache` below), so repeated property access on
|
|
93
|
+
* the SAME `sdk` object within a single `wrapWithMethodPacing` call returns
|
|
94
|
+
* the SAME wrapper reference. This cache does NOT persist across separate
|
|
95
|
+
* `wrapWithMethodPacing` calls — each call (e.g. the sdk-redirect virtual
|
|
96
|
+
* module re-evaluated per test file bundle) gets its own fresh `Map` and
|
|
97
|
+
* therefore its own wrapper function instances, even for the same method
|
|
98
|
+
* name. That's fine for pacing correctness: the actual timing state lives in
|
|
99
|
+
* the page-global `getRegistry()` map (keyed by method name, not by wrapper
|
|
100
|
+
* identity), so cross-bundle pacing still works. But callers should NOT
|
|
101
|
+
* assume cross-call function identity — only "same wrapper within one call"
|
|
102
|
+
* is guaranteed.
|
|
103
|
+
*/
|
|
104
|
+
function wrapWithMethodPacing(sdk, gapMs) {
|
|
105
|
+
if (!(gapMs > 0)) return sdk;
|
|
106
|
+
const wrapperCache = /* @__PURE__ */ new Map();
|
|
107
|
+
return new Proxy(sdk, { get(target, prop, receiver) {
|
|
108
|
+
const value = Reflect.get(target, prop, receiver);
|
|
109
|
+
if (typeof prop !== "string" || typeof value !== "function" || isClass(value)) return value;
|
|
110
|
+
const cached = wrapperCache.get(prop);
|
|
111
|
+
if (cached !== void 0) return cached;
|
|
112
|
+
const wrapped = buildPacedFunction(prop, value, gapMs);
|
|
113
|
+
wrapperCache.set(prop, wrapped);
|
|
114
|
+
return wrapped;
|
|
115
|
+
} });
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
export { getPaceMethodMs, wrapWithMethodPacing };
|
|
119
|
+
|
|
120
|
+
//# sourceMappingURL=method-pace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"method-pace.js","names":[],"sources":["../../src/test-runner/method-pace.ts"],"sourcesContent":["/**\n * Per-method minimum-interval pacing for SDK calls (devtools#769).\n *\n * #767's `--pace` inserts delays BETWEEN test files / test-to-test — it has no\n * effect on a burst of same-method calls WITHIN a single test body (e.g. a\n * clipboard happy-path loop calling `setClipboardText`/`getClipboardText`\n * eight times back to back). Real-device observation (sdk-example#293,\n * 2.x×iOS) showed that burst alone is enough to saturate the native\n * per-method bridge rate limit (`APP_BRIDGE_THROTTLED`, devtools#767/throttle.ts)\n * even though `--pace`'s file/test spacing was already in effect — the\n * limiter reacts to burst cadence within a method name, not just across test\n * boundaries.\n *\n * This module wraps `window.__sdk` (the same bridge object `bundle.ts`'s\n * `sdkRedirectPlugin` redirects SDK imports to) so that every call to the\n * SAME named function waits out a minimum gap since that function's PREVIOUS\n * invocation before the real call proceeds. Preflight (`cell.ts`) proved the\n * inverse case empirically: a steady 250ms sequential cadence passes cleanly\n * where an unpaced burst does not — sequential-with-spacing is the fix this\n * module generalizes to every SDK call, not just the six permission probes.\n *\n * Runs entirely on the PAGE side (browser-compatible, no Node APIs) — bundled\n * into the injected IIFE by `bundle.ts`'s `sdkRedirectPlugin`, the same way\n * `bridge-stub.ts` and `runtime.ts` are. Imported ONLY from the test-runner\n * (never from `sdk-example/src` — boilerplate cleanliness, umbrella §1.4).\n *\n * SECRET-HANDLING: this module carries no secrets — only method names and\n * millisecond timestamps/durations.\n */\n\n/**\n * Page-global registry of per-method last-invocation timestamps\n * (`performance.now()`-relative, monotonic). One registry per page — shared\n * across every wrapped SDK object so repeated `wrapWithMethodPacing` calls\n * (e.g. the sdk-redirect virtual module re-evaluated per test file bundle)\n * still see the true last-invoke time of a given method name, not a fresh\n * per-bundle registry that would silently reset pacing at every file\n * boundary.\n */\ntype MethodPaceState = Map<string, number>;\n\nconst REGISTRY_KEY = '__AIT_METHOD_PACE_STATE__';\n\n/** Reads (or lazily creates) the page-global per-method pacing registry. */\nfunction getRegistry(): MethodPaceState {\n const g = globalThis as { [REGISTRY_KEY]?: MethodPaceState };\n let state = g[REGISTRY_KEY];\n if (!(state instanceof Map)) {\n state = new Map<string, number>();\n g[REGISTRY_KEY] = state;\n }\n return state;\n}\n\n/** `setTimeout`-based sleep — no Node APIs, safe on the page side. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * True when `value` is a `class` declaration rather than a plain callable\n * function. The SDK export surface includes at least one class (`PermissionError`,\n * `src/__typecheck.ts`/`bridge-stub.ts` both reference it) — wrapping a class\n * in an async arrow function would silently break `new PermissionError()`\n * (arrow functions are not constructible), so classes must pass through\n * `wrapWithMethodPacing` unwrapped exactly like any other non-callable\n * export. Detected via `Function.prototype.toString` starting with\n * `\"class \"` — the standard, spec-guaranteed way to distinguish a class from\n * an ordinary function at runtime (no Babel/TS transform in this bundle\n * target — `target: 'es2022'` in `bundle.ts` — down-compiles `class` to a\n * function, so this check remains reliable for esbuild's es2022 output).\n */\nfunction isClass(value: (...args: unknown[]) => unknown): boolean {\n return Function.prototype.toString.call(value).startsWith('class ');\n}\n\n/**\n * Reads the page-global `__AIT_PACE_METHOD_MS__` gap value (devtools#769),\n * injected by `relay-factory.ts` the same way `__AIT_PACE_MS__`/`__AIT_CELL__`\n * are (`cell.ts#injectGlobals`). Absent/non-positive resolves to `0` — the\n * same \"treat absence as zero\" contract `runtime.ts`'s `__AIT_PACE_MS__` read\n * uses.\n */\nexport function getPaceMethodMs(): number {\n const raw = (globalThis as { __AIT_PACE_METHOD_MS__?: unknown }).__AIT_PACE_METHOD_MS__;\n return typeof raw === 'number' && raw > 0 ? raw : 0;\n}\n\n/**\n * Wraps a single named SDK function so that calls to it wait out `gapMs`\n * since the function's own previous invocation (tracked in the shared\n * `getRegistry()` map, keyed by `name`) before the real `fn` runs. The\n * result/rejection of `fn` passes through completely unchanged — pacing\n * never alters contract-observed behavior, only its timing.\n */\nfunction buildPacedFunction(\n name: string,\n fn: (...args: unknown[]) => unknown,\n gapMs: number,\n): (...args: unknown[]) => unknown {\n return async (...args: unknown[]) => {\n const registry = getRegistry();\n const now = performance.now();\n const lastInvokeAt = registry.get(name);\n if (lastInvokeAt !== undefined) {\n const elapsed = now - lastInvokeAt;\n if (elapsed < gapMs) {\n await sleep(gapMs - elapsed);\n }\n }\n // Record the timestamp AFTER any wait but BEFORE the real call — this is\n // \"last invoke attempt\", matching the preflight's own \"sequential with\n // spacing before each call\" model rather than \"last completion\", so two\n // long-running calls in flight cannot both slip under the gap.\n registry.set(name, performance.now());\n return fn(...args);\n };\n}\n\n/**\n * Wraps an SDK-shaped bridge object (`window.__sdk`, or the already\n * stub-wrapped result of `bridge-stub.ts#wrapSdkWithStub`) so that every\n * function-valued export is paced to a minimum `gapMs` interval between\n * calls to the SAME name (devtools#769). Non-function exports (constants,\n * etc.) and classes (`PermissionError`, etc. — wrapping a class would break\n * `new`, see `isClass`) pass through completely untouched.\n *\n * **Composition with bridge-stub (devtools#740)**: this wrapper is applied to\n * the RAW `window.__sdk` object, and `wrapSdkWithStub` is applied on TOP of\n * the paced result (`wrapSdkWithStub(wrapWithMethodPacing(rawSdk, gapMs),\n * stubEnabled)` — see `bundle.ts`'s sdk-redirect virtual module). This means\n * pacing sits BEHIND the stub interception: a stubbed name\n * (`STUB_REGISTRY` — `openPermissionDialog`, `requestPermission`,\n * `saveBase64Data`, `showFullScreenAd`) resolves instantly from the fixture\n * with no added delay, because `wrapSdkWithStub`'s Proxy intercepts the\n * property access before the paced function is ever reached. Only calls that\n * fall through to the REAL bridge — the ones that actually risk\n * `APP_BRIDGE_THROTTLED` — pay the pacing cost. Fixed by this ordering, not\n * incidental: swapping it (pacing outside the stub) would pace fixture\n * look-ups that can never hit the native rate limiter, for no benefit.\n *\n * `gapMs <= 0` (the default, no `--pace-method` / non-2.x cell) returns `sdk`\n * itself, untouched — the exact object identity is preserved so the\n * zero-diff-when-off contract holds under strict-equality checks, matching\n * `wrapSdkWithStub`'s own `enabled === false` fast path.\n *\n * **Memoization**: wrapper functions are cached per name in a `Map` local to\n * this call's `Proxy` (`wrapperCache` below), so repeated property access on\n * the SAME `sdk` object within a single `wrapWithMethodPacing` call returns\n * the SAME wrapper reference. This cache does NOT persist across separate\n * `wrapWithMethodPacing` calls — each call (e.g. the sdk-redirect virtual\n * module re-evaluated per test file bundle) gets its own fresh `Map` and\n * therefore its own wrapper function instances, even for the same method\n * name. That's fine for pacing correctness: the actual timing state lives in\n * the page-global `getRegistry()` map (keyed by method name, not by wrapper\n * identity), so cross-bundle pacing still works. But callers should NOT\n * assume cross-call function identity — only \"same wrapper within one call\"\n * is guaranteed.\n */\nexport function wrapWithMethodPacing(\n sdk: Record<string, unknown>,\n gapMs: number,\n): Record<string, unknown> {\n if (!(gapMs > 0)) return sdk;\n\n const wrapperCache = new Map<string, (...args: unknown[]) => unknown>();\n\n return new Proxy(sdk, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (\n typeof prop !== 'string' ||\n typeof value !== 'function' ||\n isClass(value as (...args: unknown[]) => unknown)\n ) {\n // Non-function export (constants, symbols) OR a class (e.g.\n // PermissionError) — pass through unchanged. Wrapping a class would\n // break `new`, and per-name pacing only makes sense for callable SDK\n // methods anyway.\n return value;\n }\n const cached = wrapperCache.get(prop);\n if (cached !== undefined) return cached;\n const wrapped = buildPacedFunction(prop, value as (...args: unknown[]) => unknown, gapMs);\n wrapperCache.set(prop, wrapped);\n return wrapped;\n },\n });\n}\n"],"mappings":";AAyCA,MAAM,eAAe;;AAGrB,SAAS,cAA+B;CACtC,MAAM,IAAI;CACV,IAAI,QAAQ,EAAE;AACd,KAAI,EAAE,iBAAiB,MAAM;AAC3B,0BAAQ,IAAI,KAAqB;AACjC,IAAE,gBAAgB;;AAEpB,QAAO;;;AAIT,SAAS,MAAM,IAA2B;AACxC,QAAO,IAAI,SAAS,YAAY,WAAW,SAAS,GAAG,CAAC;;;;;;;;;;;;;;;AAgB1D,SAAS,QAAQ,OAAiD;AAChE,QAAO,SAAS,UAAU,SAAS,KAAK,MAAM,CAAC,WAAW,SAAS;;;;;;;;;AAUrE,SAAgB,kBAA0B;CACxC,MAAM,MAAO,WAAoD;AACjE,QAAO,OAAO,QAAQ,YAAY,MAAM,IAAI,MAAM;;;;;;;;;AAUpD,SAAS,mBACP,MACA,IACA,OACiC;AACjC,QAAO,OAAO,GAAG,SAAoB;EACnC,MAAM,WAAW,aAAa;EAC9B,MAAM,MAAM,YAAY,KAAK;EAC7B,MAAM,eAAe,SAAS,IAAI,KAAK;AACvC,MAAI,iBAAiB,KAAA,GAAW;GAC9B,MAAM,UAAU,MAAM;AACtB,OAAI,UAAU,MACZ,OAAM,MAAM,QAAQ,QAAQ;;AAOhC,WAAS,IAAI,MAAM,YAAY,KAAK,CAAC;AACrC,SAAO,GAAG,GAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CtB,SAAgB,qBACd,KACA,OACyB;AACzB,KAAI,EAAE,QAAQ,GAAI,QAAO;CAEzB,MAAM,+BAAe,IAAI,KAA8C;AAEvE,QAAO,IAAI,MAAM,KAAK,EACpB,IAAI,QAAQ,MAAM,UAAU;EAC1B,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;AACjD,MACE,OAAO,SAAS,YAChB,OAAO,UAAU,cACjB,QAAQ,MAAyC,CAMjD,QAAO;EAET,MAAM,SAAS,aAAa,IAAI,KAAK;AACrC,MAAI,WAAW,KAAA,EAAW,QAAO;EACjC,MAAM,UAAU,mBAAmB,MAAM,OAA0C,MAAM;AACzF,eAAa,IAAI,MAAM,QAAQ;AAC/B,SAAO;IAEV,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as createRelayPool, n as RelayConnectionFactory, r as RelayPoolOptions, t as RELAY_POOL_NAME } from "../pool-
|
|
1
|
+
import { i as createRelayPool, n as RelayConnectionFactory, r as RelayPoolOptions, t as RELAY_POOL_NAME } from "../pool-CrP5CPvU.js";
|
|
2
2
|
export { RELAY_POOL_NAME, RelayConnectionFactory, RelayPoolOptions, createRelayPool };
|
package/dist/test-runner/pool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as runTestFilesOverRelay } from "../relay-worker-
|
|
1
|
+
import { i as runTestFilesOverRelay } from "../relay-worker-BUXI0K0b.js";
|
|
2
2
|
import { synthesizeFileTask, toTaskEventPacks, toTaskResultPacks } from "./task-graph.js";
|
|
3
3
|
//#region src/test-runner/pool.ts
|
|
4
4
|
/** The pool name Vitest matches against `getFilePoolName(project)`. */
|
|
@@ -11105,8 +11105,36 @@ interface RelayConnectionFactoryOptions {
|
|
|
11105
11105
|
* intoss-private:// scheme URL from `ait deploy --scheme-only` (env3). The
|
|
11106
11106
|
* phone cold-loads the candidate bundle this URL points at. SECRET-HANDLING:
|
|
11107
11107
|
* never logged.
|
|
11108
|
+
*
|
|
11109
|
+
* Ignored when {@link attachLauncher} is `true` — the env-2 launcher path
|
|
11110
|
+
* builds its attach URL from {@link appUrl} + the relay wss, not a scheme URL.
|
|
11111
|
+
* Pass `''` in that case.
|
|
11108
11112
|
*/
|
|
11109
11113
|
schemeUrl: string;
|
|
11114
|
+
/**
|
|
11115
|
+
* env-2 (AITC Sandbox PWA) attach mode (devtools#774). When `true`, `open()`
|
|
11116
|
+
* builds the attach URL as a **launcher deep-link**
|
|
11117
|
+
* (`buildLauncherAttachUrl(appUrl, wssUrl, totp)` — the same env-2 path the
|
|
11118
|
+
* MCP daemon takes via `prepareAttach(deps, 'relay-mobile', …)`, issue #378)
|
|
11119
|
+
* instead of an intoss-private scheme deep-link. The relay boot, QR
|
|
11120
|
+
* rendering, dashboard, and attach-wait are byte-for-byte identical to env 3;
|
|
11121
|
+
* only the URL family differs. Omitted/false keeps the env-3 scheme path
|
|
11122
|
+
* unchanged (zero behavior change).
|
|
11123
|
+
*/
|
|
11124
|
+
attachLauncher?: boolean;
|
|
11125
|
+
/**
|
|
11126
|
+
* The consumer dev server's HTTP tunnel URL (e.g. an sdk-example
|
|
11127
|
+
* `dev:phone:cdp` `*.trycloudflare.com` URL) that the launcher PWA frames.
|
|
11128
|
+
* REQUIRED when {@link attachLauncher} is `true`; ignored otherwise.
|
|
11129
|
+
*
|
|
11130
|
+
* Threaded to the `relay-mobile` `prepareAttach` branch via the
|
|
11131
|
+
* `AIT_TUNNEL_BASE_URL` env var (the same key the MCP daemon reads), so the
|
|
11132
|
+
* exact same env-2 assembly runs — no divergent code path.
|
|
11133
|
+
*
|
|
11134
|
+
* SECRET-HANDLING: this is a tunnel host at the same sensitivity as the relay
|
|
11135
|
+
* wss — NEVER logged. It rides only inside the QR/dashboard attach capsule.
|
|
11136
|
+
*/
|
|
11137
|
+
appUrl?: string;
|
|
11110
11138
|
/**
|
|
11111
11139
|
* Project root for the `.ait_relay` secret lookup (read-only). Defaults to
|
|
11112
11140
|
* `process.cwd()`.
|
|
@@ -11133,6 +11161,40 @@ interface RelayConnectionFactoryOptions {
|
|
|
11133
11161
|
sdkLine: string;
|
|
11134
11162
|
platform: string;
|
|
11135
11163
|
};
|
|
11164
|
+
/**
|
|
11165
|
+
* When `true`, injects `__AIT_STUB_BLOCKING__ = true` before the first test
|
|
11166
|
+
* bundle runs (devtools#740, DT-2) — `bundle.ts`'s sdk-redirect module reads
|
|
11167
|
+
* this flag via `isStubBlockingEnabled()` and answers the blocking-UI APIs
|
|
11168
|
+
* in `bridge-stub.ts`'s `STUB_REGISTRY` from fixtures instead of forwarding
|
|
11169
|
+
* them to native. Optional — omitted/false means no flag is injected, which
|
|
11170
|
+
* is byte-for-byte the pre-#740 behavior (the sdk-redirect module treats
|
|
11171
|
+
* absence the same as `false`). Not a secret.
|
|
11172
|
+
*/
|
|
11173
|
+
stubBlocking?: boolean;
|
|
11174
|
+
/**
|
|
11175
|
+
* Injects `__AIT_PACE_MS__ = paceMs` before the first test bundle runs
|
|
11176
|
+
* (devtools#767) — `runtime.ts`'s test-execution loop reads this page
|
|
11177
|
+
* global and waits `paceMs` before every test after the first one that
|
|
11178
|
+
* actually runs. Optional — omitted/0 means no flag is injected, which is
|
|
11179
|
+
* byte-for-byte the pre-#767 behavior (the loop treats an absent/non-
|
|
11180
|
+
* positive value as "no pacing"). Not a secret. This is the PAGE-side half
|
|
11181
|
+
* of `--pace`; the RUNNER-side (file-to-file) half is a plain `opts.paceMs`
|
|
11182
|
+
* forwarded to `runTestFilesOverRelay` by the caller (cli.ts) — this
|
|
11183
|
+
* factory only owns the page-global injection.
|
|
11184
|
+
*/
|
|
11185
|
+
paceMs?: number;
|
|
11186
|
+
/**
|
|
11187
|
+
* Injects `__AIT_PACE_METHOD_MS__ = paceMethodMs` before the first test
|
|
11188
|
+
* bundle runs (devtools#769) — `bundle.ts`'s sdk-redirect virtual module
|
|
11189
|
+
* reads this page global via `method-pace.ts#getPaceMethodMs()` and paces
|
|
11190
|
+
* every SDK call to a minimum interval BETWEEN calls to the SAME named
|
|
11191
|
+
* function, independent of `--pace`'s test-to-test/file-to-file spacing.
|
|
11192
|
+
* Optional — omitted/0 means no flag is injected, which is byte-for-byte
|
|
11193
|
+
* the pre-#769 behavior (`getPaceMethodMs()` treats an absent/non-positive
|
|
11194
|
+
* value as "no pacing", and `wrapWithMethodPacing` returns the SDK object
|
|
11195
|
+
* untouched in that case). Not a secret.
|
|
11196
|
+
*/
|
|
11197
|
+
paceMethodMs?: number;
|
|
11136
11198
|
/**
|
|
11137
11199
|
* Overrides the dashboard HTTP server's bind base port (devtools#752).
|
|
11138
11200
|
* Threaded straight through to `startQrHttpServer`'s `dashboardPort`
|
|
@@ -11160,12 +11222,13 @@ interface RelayConnectionFactoryOptions {
|
|
|
11160
11222
|
onQrContent: (textChunks: string[]) => void;
|
|
11161
11223
|
}
|
|
11162
11224
|
/**
|
|
11163
|
-
* Builds a {@link RelayConnectionFactory} that opens a standalone
|
|
11164
|
-
* connection
|
|
11225
|
+
* Builds a {@link RelayConnectionFactory} that opens a standalone relay
|
|
11226
|
+
* connection for env 3 (intoss-private scheme, default) or env 2 (AITC Sandbox
|
|
11227
|
+
* PWA launcher deep-link, when `opts.attachLauncher` is set — devtools#774).
|
|
11165
11228
|
*
|
|
11166
11229
|
* `open()` performs the full attach lifecycle and BLOCKS while a human scans
|
|
11167
|
-
* the rendered QR with their phone — there is no way around the manual scan
|
|
11168
|
-
*
|
|
11230
|
+
* the rendered QR with their phone — there is no way around the manual scan.
|
|
11231
|
+
* By default the wait is UNBOUNDED (`opts.timeoutMs` omitted): the
|
|
11169
11232
|
* runner stays up until the user stops it (Ctrl-C/SIGTERM), since QR-scan is
|
|
11170
11233
|
* a human-paced action with no sound default bound (devtools#735). Passing an
|
|
11171
11234
|
* explicit `timeoutMs` opts into the old bounded behavior (CI/headless
|