@ait-co/devtools 0.1.143 → 0.2.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 (223) hide show
  1. package/README.en.md +65 -163
  2. package/README.md +65 -192
  3. package/dist/in-app/auto.d.ts +1 -138
  4. package/dist/in-app/auto.js +28 -1102
  5. package/dist/in-app/auto.js.map +1 -1
  6. package/dist/in-app/index.d.ts +38 -547
  7. package/dist/in-app/index.d.ts.map +1 -1
  8. package/dist/in-app/index.js +62 -939
  9. package/dist/in-app/index.js.map +1 -1
  10. package/dist/mcp/cli.d.ts +1 -54
  11. package/dist/mcp/cli.js +33 -9720
  12. package/dist/mcp/cli.js.map +1 -1
  13. package/dist/mcp/server.d.ts +1 -88
  14. package/dist/mcp/server.js +36 -1076
  15. package/dist/mcp/server.js.map +1 -1
  16. package/dist/mock/index.d.ts +19 -20
  17. package/dist/mock/index.d.ts.map +1 -1
  18. package/dist/mock/index.js.map +1 -1
  19. package/dist/optional-peers-CDEFhlhJ.cjs +131 -0
  20. package/dist/optional-peers-CDEFhlhJ.cjs.map +1 -0
  21. package/dist/optional-peers-FdVbUJst.js +96 -0
  22. package/dist/optional-peers-FdVbUJst.js.map +1 -0
  23. package/dist/panel/index.js +1 -103
  24. package/dist/panel/index.js.map +1 -1
  25. package/dist/relay-url-store-CPZAn-T5.js +107 -0
  26. package/dist/relay-url-store-CPZAn-T5.js.map +1 -0
  27. package/dist/relay-url-store-DLjlvMSA.cjs +108 -0
  28. package/dist/relay-url-store-DLjlvMSA.cjs.map +1 -0
  29. package/dist/stubs/bin-devtools-mcp.js +58 -0
  30. package/dist/stubs/bin-devtools-mcp.js.map +1 -0
  31. package/dist/stubs/bin-devtools-test.d.ts +2 -0
  32. package/dist/stubs/bin-devtools-test.js +55 -0
  33. package/dist/stubs/bin-devtools-test.js.map +1 -0
  34. package/dist/test-runner/config.d.ts +1 -231
  35. package/dist/test-runner/config.js +41 -45
  36. package/dist/test-runner/config.js.map +1 -1
  37. package/dist/{tunnel-BVSMXctM.cjs → tunnel-BKZkOyQp.cjs} +27 -75
  38. package/dist/tunnel-BKZkOyQp.cjs.map +1 -0
  39. package/dist/{tunnel-D7xkimBu.js → tunnel-CqSCIrdU.js} +27 -75
  40. package/dist/tunnel-CqSCIrdU.js.map +1 -0
  41. package/dist/unplugin/index.cjs +17 -30
  42. package/dist/unplugin/index.cjs.map +1 -1
  43. package/dist/unplugin/index.d.cts +34 -5
  44. package/dist/unplugin/index.d.cts.map +1 -1
  45. package/dist/unplugin/index.d.ts +35 -6
  46. package/dist/unplugin/index.d.ts.map +1 -1
  47. package/dist/unplugin/index.js +17 -30
  48. package/dist/unplugin/index.js.map +1 -1
  49. package/dist/unplugin/tunnel.cjs +61 -74
  50. package/dist/unplugin/tunnel.cjs.map +1 -1
  51. package/dist/unplugin/tunnel.d.cts +22 -16
  52. package/dist/unplugin/tunnel.d.cts.map +1 -1
  53. package/dist/unplugin/tunnel.d.ts +22 -16
  54. package/dist/unplugin/tunnel.d.ts.map +1 -1
  55. package/dist/unplugin/tunnel.js +61 -74
  56. package/dist/unplugin/tunnel.js.map +1 -1
  57. package/package.json +17 -22
  58. package/dist/attach-orchestrator-0F0m_UqQ.js +0 -1845
  59. package/dist/attach-orchestrator-0F0m_UqQ.js.map +0 -1
  60. package/dist/attach-orchestrator-D65KxFy_.js +0 -1831
  61. package/dist/attach-orchestrator-D65KxFy_.js.map +0 -1
  62. package/dist/attach-orchestrator-DL3NQ9ca.js +0 -1846
  63. package/dist/attach-orchestrator-DL3NQ9ca.js.map +0 -1
  64. package/dist/bundle-C796JIwG.d.ts +0 -159
  65. package/dist/bundle-C796JIwG.d.ts.map +0 -1
  66. package/dist/capture-DsP525OZ.d.ts +0 -58
  67. package/dist/capture-DsP525OZ.d.ts.map +0 -1
  68. package/dist/cdp-connection-rP1WdnH5.d.ts +0 -287
  69. package/dist/cdp-connection-rP1WdnH5.d.ts.map +0 -1
  70. package/dist/cell-BaLvusOl.js +0 -68
  71. package/dist/cell-BaLvusOl.js.map +0 -1
  72. package/dist/cell-CBUS3-nT.js +0 -274
  73. package/dist/cell-CBUS3-nT.js.map +0 -1
  74. package/dist/cell-EBKKpAAT.js +0 -307
  75. package/dist/cell-EBKKpAAT.js.map +0 -1
  76. package/dist/chii-relay-BZ3HqWL5.js +0 -304
  77. package/dist/chii-relay-BZ3HqWL5.js.map +0 -1
  78. package/dist/chii-relay-D7eK2acz.cjs +0 -304
  79. package/dist/chii-relay-D7eK2acz.cjs.map +0 -1
  80. package/dist/debug-server-B3ABDrRI.js +0 -456
  81. package/dist/debug-server-B3ABDrRI.js.map +0 -1
  82. package/dist/debug-server-BWhwrVXa.js +0 -1158
  83. package/dist/debug-server-BWhwrVXa.js.map +0 -1
  84. package/dist/debug-server-CfQNxxGW.js +0 -600
  85. package/dist/debug-server-CfQNxxGW.js.map +0 -1
  86. package/dist/deeplink-B5-Hxu0Q.js +0 -62
  87. package/dist/deeplink-B5-Hxu0Q.js.map +0 -1
  88. package/dist/deeplink-BpO9qc-D.js +0 -62
  89. package/dist/deeplink-BpO9qc-D.js.map +0 -1
  90. package/dist/deeplink-BzdbA1gV.cjs +0 -62
  91. package/dist/deeplink-BzdbA1gV.cjs.map +0 -1
  92. package/dist/deeplink-DCScMYcp.cjs +0 -62
  93. package/dist/deeplink-DCScMYcp.cjs.map +0 -1
  94. package/dist/devtools-opener-3Drge_RJ.js +0 -75
  95. package/dist/devtools-opener-3Drge_RJ.js.map +0 -1
  96. package/dist/devtools-opener-B8nxrxqu.js +0 -71
  97. package/dist/devtools-opener-B8nxrxqu.js.map +0 -1
  98. package/dist/devtools-opener-BDY0w3_0.cjs +0 -68
  99. package/dist/devtools-opener-BDY0w3_0.cjs.map +0 -1
  100. package/dist/devtools-opener-BTl5A6Cd.js +0 -71
  101. package/dist/devtools-opener-BTl5A6Cd.js.map +0 -1
  102. package/dist/devtools-opener-CJpEsXXQ.js +0 -76
  103. package/dist/devtools-opener-CJpEsXXQ.js.map +0 -1
  104. package/dist/devtools-opener-CxtryS8c.js +0 -75
  105. package/dist/devtools-opener-CxtryS8c.js.map +0 -1
  106. package/dist/devtools-opener-iv1OwfJN.cjs +0 -68
  107. package/dist/devtools-opener-iv1OwfJN.cjs.map +0 -1
  108. package/dist/in-app/auto.d.ts.map +0 -1
  109. package/dist/mcp/cli.d.ts.map +0 -1
  110. package/dist/mcp/server.d.ts.map +0 -1
  111. package/dist/pool-DcaaOwUq.d.ts +0 -14761
  112. package/dist/pool-DcaaOwUq.d.ts.map +0 -1
  113. package/dist/qr-http-server--gl2-WKc.cjs +0 -1644
  114. package/dist/qr-http-server--gl2-WKc.cjs.map +0 -1
  115. package/dist/qr-http-server-Bb7lMeqi.js +0 -1644
  116. package/dist/qr-http-server-Bb7lMeqi.js.map +0 -1
  117. package/dist/qr-http-server-C_lqOrgc.js +0 -1644
  118. package/dist/qr-http-server-C_lqOrgc.js.map +0 -1
  119. package/dist/qr-http-server-CopuMbub.js +0 -1644
  120. package/dist/qr-http-server-CopuMbub.js.map +0 -1
  121. package/dist/qr-http-server-D-Off6K1.cjs +0 -1644
  122. package/dist/qr-http-server-D-Off6K1.cjs.map +0 -1
  123. package/dist/qr-http-server-DrbIVDjO.js +0 -1645
  124. package/dist/qr-http-server-DrbIVDjO.js.map +0 -1
  125. package/dist/qr-http-server-n1twN18z.js +0 -1644
  126. package/dist/qr-http-server-n1twN18z.js.map +0 -1
  127. package/dist/relay-factory-N9QobQxG.js +0 -206
  128. package/dist/relay-factory-N9QobQxG.js.map +0 -1
  129. package/dist/relay-secret-store-BPhN1upr.js +0 -240
  130. package/dist/relay-secret-store-BPhN1upr.js.map +0 -1
  131. package/dist/relay-secret-store-Bmyleu0A.js +0 -154
  132. package/dist/relay-secret-store-Bmyleu0A.js.map +0 -1
  133. package/dist/relay-secret-store-CQenfcSL.js +0 -154
  134. package/dist/relay-secret-store-CQenfcSL.js.map +0 -1
  135. package/dist/relay-secret-store-DKxs7zwq.js +0 -153
  136. package/dist/relay-secret-store-DKxs7zwq.js.map +0 -1
  137. package/dist/relay-secret-store-DWKdV-eY.cjs +0 -241
  138. package/dist/relay-secret-store-DWKdV-eY.cjs.map +0 -1
  139. package/dist/relay-secret-store-WJ8EGkIl.js +0 -153
  140. package/dist/relay-secret-store-WJ8EGkIl.js.map +0 -1
  141. package/dist/relay-url-store-1FGuSYAn.cjs +0 -115
  142. package/dist/relay-url-store-1FGuSYAn.cjs.map +0 -1
  143. package/dist/relay-url-store-BR2XodiO.js +0 -123
  144. package/dist/relay-url-store-BR2XodiO.js.map +0 -1
  145. package/dist/relay-url-store-Bskcyeg8.js +0 -114
  146. package/dist/relay-url-store-Bskcyeg8.js.map +0 -1
  147. package/dist/relay-url-store-CH63fVCm.js +0 -122
  148. package/dist/relay-url-store-CH63fVCm.js.map +0 -1
  149. package/dist/relay-url-store-DaY1QPes.js +0 -123
  150. package/dist/relay-url-store-DaY1QPes.js.map +0 -1
  151. package/dist/relay-url-store-xmUuTjXA.js +0 -122
  152. package/dist/relay-url-store-xmUuTjXA.js.map +0 -1
  153. package/dist/relay-worker-B5HKkGUY.js +0 -832
  154. package/dist/relay-worker-B5HKkGUY.js.map +0 -1
  155. package/dist/relay-worker-YdlpZQl9.d.ts +0 -214
  156. package/dist/relay-worker-YdlpZQl9.d.ts.map +0 -1
  157. package/dist/rolldown-runtime-DGkTqVfb.js +0 -15
  158. package/dist/rolldown-runtime-DUslC3ob.js +0 -14
  159. package/dist/runtime-kn9DxOeg.d.ts +0 -249
  160. package/dist/runtime-kn9DxOeg.d.ts.map +0 -1
  161. package/dist/test-runner/bin.js +0 -2584
  162. package/dist/test-runner/bin.js.map +0 -1
  163. package/dist/test-runner/bridge-stub.d.ts +0 -125
  164. package/dist/test-runner/bridge-stub.d.ts.map +0 -1
  165. package/dist/test-runner/bridge-stub.js +0 -92
  166. package/dist/test-runner/bridge-stub.js.map +0 -1
  167. package/dist/test-runner/bundle.d.ts +0 -2
  168. package/dist/test-runner/bundle.js +0 -439
  169. package/dist/test-runner/bundle.js.map +0 -1
  170. package/dist/test-runner/capture.d.ts +0 -2
  171. package/dist/test-runner/capture.js +0 -44
  172. package/dist/test-runner/capture.js.map +0 -1
  173. package/dist/test-runner/config.d.ts.map +0 -1
  174. package/dist/test-runner/method-pace.d.ts +0 -82
  175. package/dist/test-runner/method-pace.d.ts.map +0 -1
  176. package/dist/test-runner/method-pace.js +0 -120
  177. package/dist/test-runner/method-pace.js.map +0 -1
  178. package/dist/test-runner/pool.d.ts +0 -2
  179. package/dist/test-runner/pool.js +0 -136
  180. package/dist/test-runner/pool.js.map +0 -1
  181. package/dist/test-runner/relay-factory.d.ts +0 -11245
  182. package/dist/test-runner/relay-factory.d.ts.map +0 -1
  183. package/dist/test-runner/relay-factory.js +0 -206
  184. package/dist/test-runner/relay-factory.js.map +0 -1
  185. package/dist/test-runner/relay-worker.d.ts +0 -2
  186. package/dist/test-runner/relay-worker.js +0 -2
  187. package/dist/test-runner/report.d.ts +0 -163
  188. package/dist/test-runner/report.d.ts.map +0 -1
  189. package/dist/test-runner/report.js +0 -198
  190. package/dist/test-runner/report.js.map +0 -1
  191. package/dist/test-runner/rpc.d.ts +0 -56
  192. package/dist/test-runner/rpc.d.ts.map +0 -1
  193. package/dist/test-runner/rpc.js +0 -98
  194. package/dist/test-runner/rpc.js.map +0 -1
  195. package/dist/test-runner/runtime.d.ts +0 -2
  196. package/dist/test-runner/runtime.js +0 -659
  197. package/dist/test-runner/runtime.js.map +0 -1
  198. package/dist/test-runner/task-graph.d.ts +0 -38
  199. package/dist/test-runner/task-graph.d.ts.map +0 -1
  200. package/dist/test-runner/task-graph.js +0 -182
  201. package/dist/test-runner/task-graph.js.map +0 -1
  202. package/dist/throttle-DKKzX1qC.js +0 -59
  203. package/dist/throttle-DKKzX1qC.js.map +0 -1
  204. package/dist/totp-95OAa20j.js +0 -64
  205. package/dist/totp-95OAa20j.js.map +0 -1
  206. package/dist/totp-BjtoQNfu.cjs +0 -64
  207. package/dist/totp-BjtoQNfu.cjs.map +0 -1
  208. package/dist/totp-CZLLKfOC.js +0 -200
  209. package/dist/totp-CZLLKfOC.js.map +0 -1
  210. package/dist/totp-DAxys-r0.js +0 -199
  211. package/dist/totp-DAxys-r0.js.map +0 -1
  212. package/dist/totp-DIbrZtI7.js +0 -189
  213. package/dist/totp-DIbrZtI7.js.map +0 -1
  214. package/dist/totp-Df252ZdA.cjs +0 -192
  215. package/dist/totp-Df252ZdA.cjs.map +0 -1
  216. package/dist/totp-DfekTBk3.js +0 -211
  217. package/dist/totp-DfekTBk3.js.map +0 -1
  218. package/dist/totp-Dwft0Kz7.js +0 -3
  219. package/dist/totp-WY6l0ysP.js +0 -190
  220. package/dist/totp-WY6l0ysP.js.map +0 -1
  221. package/dist/tunnel-BVSMXctM.cjs.map +0 -1
  222. package/dist/tunnel-D7xkimBu.js.map +0 -1
  223. /package/dist/{test-runner/bin.d.ts → stubs/bin-devtools-mcp.d.ts} +0 -0
@@ -1,120 +0,0 @@
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
@@ -1 +0,0 @@
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 +0,0 @@
1
- import { i as createRelayPool, n as RelayConnectionFactory, r as RelayPoolOptions, t as RELAY_POOL_NAME } from "../pool-DcaaOwUq.js";
2
- export { RELAY_POOL_NAME, RelayConnectionFactory, RelayPoolOptions, createRelayPool };
@@ -1,136 +0,0 @@
1
- import { i as runTestFilesOverRelay } from "../relay-worker-B5HKkGUY.js";
2
- import { synthesizeFileTask, toTaskEventPacks, toTaskResultPacks } from "./task-graph.js";
3
- //#region src/test-runner/pool.ts
4
- /** The pool name Vitest matches against `getFilePoolName(project)`. */
5
- const RELAY_POOL_NAME = "ait-relay";
6
- /**
7
- * In-process `PoolWorker` backed by a CDP relay. Mirrors `TypecheckPoolWorker`:
8
- * `send` handles the message in-process and emits a `WorkerResponse` via the
9
- * `'message'` listener registered by the core's pool driver.
10
- */
11
- var RelayPoolWorker = class {
12
- name = RELAY_POOL_NAME;
13
- cacheFs = false;
14
- project;
15
- factory;
16
- runOpts;
17
- listeners = /* @__PURE__ */ new Map();
18
- connection;
19
- constructor(project, opts) {
20
- this.project = project;
21
- this.factory = opts.connection;
22
- this.runOpts = opts.run;
23
- }
24
- on(event, callback) {
25
- let set = this.listeners.get(event);
26
- if (!set) {
27
- set = /* @__PURE__ */ new Set();
28
- this.listeners.set(event, set);
29
- }
30
- set.add(callback);
31
- }
32
- off(event, callback) {
33
- this.listeners.get(event)?.delete(callback);
34
- }
35
- emit(event, arg) {
36
- const set = this.listeners.get(event);
37
- if (!set) return;
38
- for (const cb of set) cb(arg);
39
- }
40
- deserialize(data) {
41
- return data;
42
- }
43
- async start() {}
44
- async stop() {
45
- if (this.connection) {
46
- const conn = this.connection;
47
- this.connection = void 0;
48
- await this.factory.close(conn);
49
- }
50
- }
51
- send(message) {
52
- this.handle(message).then((response) => {
53
- if (response) this.emit("message", response);
54
- });
55
- }
56
- async handle(message) {
57
- switch (message.type) {
58
- case "start": return {
59
- __vitest_worker_response__: true,
60
- type: "started"
61
- };
62
- case "run":
63
- case "collect": {
64
- const files = message.context.files.map((s) => s.filepath);
65
- return {
66
- __vitest_worker_response__: true,
67
- type: "testfileFinished",
68
- error: await this.runFiles(files).catch((e) => e)
69
- };
70
- }
71
- case "stop": return {
72
- __vitest_worker_response__: true,
73
- type: "stopped"
74
- };
75
- case "cancel": return;
76
- }
77
- }
78
- /**
79
- * Bundles + injects + collects the given files over the relay, synthesises a
80
- * Vitest task graph per file, and reports it through `vitest.state` so the
81
- * reporter/watch/UI ecosystem sees real results.
82
- *
83
- * Returns nothing on success; a thrown error is surfaced as the
84
- * `testfileFinished` error (a whole-pool failure, e.g. relay unreachable).
85
- */
86
- async runFiles(files) {
87
- const report = await runTestFilesOverRelay(await this.ensureConnection(), files, this.runOpts);
88
- const root = this.project.config.root;
89
- const projectName = this.project.name || void 0;
90
- const state = this.project.vitest.state;
91
- for (const fileResult of report.files) {
92
- const perFile = "error" in fileResult.result ? {
93
- startedAt: report.startedAt,
94
- duration: 0,
95
- passed: 0,
96
- failed: 1,
97
- skipped: 0,
98
- tests: []
99
- } : fileResult.result;
100
- const fileTask = synthesizeFileTask(fileResult.file, root, projectName, RELAY_POOL_NAME, perFile);
101
- state.collectFiles(this.project, [fileTask]);
102
- state.updateTasks(toTaskResultPacks(fileTask));
103
- toTaskEventPacks(fileTask);
104
- }
105
- }
106
- async ensureConnection() {
107
- if (!this.connection) this.connection = await this.factory.open();
108
- return this.connection;
109
- }
110
- };
111
- /**
112
- * Creates the Vitest `PoolRunnerInitializer` for the relay pool.
113
- *
114
- * Wire it into a Vitest config as `pool: createRelayPool({ connection })`.
115
- * Vitest moves an object `pool` into `config.poolRunner` and dispatches files
116
- * whose pool name equals `RELAY_POOL_NAME` to our `createPoolWorker`.
117
- *
118
- * @example
119
- * // vitest.config.ts
120
- * import { createRelayPool } from '@ait-co/devtools/test-runner';
121
- * export default defineConfig({
122
- * test: { pool: createRelayPool({ connection: myFactory }) },
123
- * });
124
- */
125
- function createRelayPool(opts) {
126
- return {
127
- name: RELAY_POOL_NAME,
128
- createPoolWorker(options) {
129
- return new RelayPoolWorker(options.project, opts);
130
- }
131
- };
132
- }
133
- //#endregion
134
- export { RELAY_POOL_NAME, createRelayPool };
135
-
136
- //# sourceMappingURL=pool.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pool.js","names":[],"sources":["../../src/test-runner/pool.ts"],"sourcesContent":["/**\n * Vitest 4.x custom pool: runs mini-app tests on a real device WebView over a\n * CDP relay instead of in a Node child process.\n *\n * Vitest's pool abstraction lets a `PoolRunnerInitializer` create a `PoolWorker`\n * that the core drives via a `WorkerRequest`/`WorkerResponse` message protocol.\n * Built-in pools (`forks`/`threads`) fork a child process; the `typecheck` pool\n * runs in-process and handles messages synchronously. We follow the in-process\n * `TypecheckPoolWorker` shape: a single long-lived \"worker\" that, on a `run`\n * request, bundles + injects + collects each file over the relay (#644's\n * `runTestFilesOverRelay`), synthesises a Vitest task graph (`task-graph.ts`),\n * and reports it through `vitest.state` so reporters/watch/UI/snapshot all work.\n *\n * Single-attach constraint: the relay supports one active page, so we keep one\n * worker for the whole run (`isolate: false`) rather than starting/stopping per\n * file — per-file start/stop would re-attach the relay on every file.\n *\n * SECRET-HANDLING: the relay connection (wss/TOTP) is supplied by the caller's\n * factory and never logged here; bundle code and result values are not logged.\n */\n\nimport type { PoolOptions, PoolWorker, TestProject, WorkerRequest } from 'vitest/node';\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\nimport type { RelayRunOptions } from './relay-worker.js';\nimport { runTestFilesOverRelay } from './relay-worker.js';\nimport { synthesizeFileTask, toTaskEventPacks, toTaskResultPacks } from './task-graph.js';\n\n/** The pool name Vitest matches against `getFilePoolName(project)`. */\nexport const RELAY_POOL_NAME = 'ait-relay';\n\n/**\n * Factory the caller provides to open (and later close) the CDP relay\n * connection. Called once per worker lifecycle (`start`). The returned\n * `close` runs on `stop`.\n *\n * Kept as a factory (not a live connection) so the pool can be constructed in\n * config before any device is attached, and so `start`/`stop` own the lifecycle.\n */\nexport interface RelayConnectionFactory {\n /** Opens the relay connection. Resolves once the page is attached & ready. */\n open(): Promise<CdpConnection>;\n /** Closes the relay connection opened by {@link open}. */\n close(connection: CdpConnection): Promise<void>;\n /**\n * CLI-only session-phase hook (#730) — drives the QR dashboard's `phase`\n * field (`'running'` on run start, `'complete'` on run end) so the\n * dashboard can push an immediate SSE update instead of waiting for a\n * poll/watchdog. The pool (this file) has no equivalent lifecycle and\n * omits it; only `createRelayConnectionFactory` (relay-factory.ts) sets it.\n */\n onSessionPhase?(phase: 'running' | 'complete'): void;\n /**\n * CLI-only manual-blocking prompt hook (devtools#741) — pushes the QR\n * dashboard's `manualPrompt` field before each manual-tagged file is\n * injected, so a human watching the dashboard sees which file is next and\n * how far along the manual queue is. Pass `null` to clear the prompt (the\n * CLI does this once all manual files have run). The pool has no\n * equivalent lifecycle and omits it; only `createRelayConnectionFactory`\n * sets it.\n */\n onManualPrompt?(prompt: { file: string; index: number; total: number } | null): void;\n}\n\n/** Options for {@link createRelayPool}. */\nexport interface RelayPoolOptions {\n /** Opens/closes the relay connection. */\n connection: RelayConnectionFactory;\n /** Forwarded to `runTestFilesOverRelay` (bundle options, per-file timeout). */\n run?: RelayRunOptions;\n}\n\n/* -------------------------------------------------------------------------- */\n/* WorkerResponse helpers */\n/* -------------------------------------------------------------------------- */\n\n/** Minimal `WorkerResponse` shape we emit. Matches vitest/node's union. */\ntype EmittedResponse =\n | { __vitest_worker_response__: true; type: 'started'; error?: unknown }\n | { __vitest_worker_response__: true; type: 'stopped'; error?: unknown }\n | { __vitest_worker_response__: true; type: 'testfileFinished'; error?: unknown };\n\n/* -------------------------------------------------------------------------- */\n/* The in-process relay PoolWorker */\n/* -------------------------------------------------------------------------- */\n\n/**\n * In-process `PoolWorker` backed by a CDP relay. Mirrors `TypecheckPoolWorker`:\n * `send` handles the message in-process and emits a `WorkerResponse` via the\n * `'message'` listener registered by the core's pool driver.\n */\nclass RelayPoolWorker implements PoolWorker {\n readonly name = RELAY_POOL_NAME;\n readonly cacheFs = false;\n\n private readonly project: TestProject;\n private readonly factory: RelayConnectionFactory;\n private readonly runOpts: RelayRunOptions | undefined;\n private readonly listeners = new Map<string, Set<(arg: unknown) => void>>();\n private connection: CdpConnection | undefined;\n\n constructor(project: TestProject, opts: RelayPoolOptions) {\n this.project = project;\n this.factory = opts.connection;\n this.runOpts = opts.run;\n }\n\n on(event: string, callback: (arg: unknown) => void): void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(callback);\n }\n\n off(event: string, callback: (arg: unknown) => void): void {\n this.listeners.get(event)?.delete(callback);\n }\n\n private emit(event: string, arg: unknown): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const cb of set) cb(arg);\n }\n\n deserialize(data: unknown): unknown {\n // Relay results arrive as plain JSON objects already — identity is correct.\n return data;\n }\n\n async start(): Promise<void> {\n // Lifecycle ownership lives here, but the connection is opened lazily on the\n // first `run`/`collect` so a never-run worker never touches the device.\n }\n\n async stop(): Promise<void> {\n if (this.connection) {\n const conn = this.connection;\n this.connection = undefined;\n await this.factory.close(conn);\n }\n }\n\n send(message: WorkerRequest): void {\n // Fire-and-forget like TypecheckPoolWorker: handle async, emit on settle.\n void this.handle(message).then((response) => {\n if (response) this.emit('message', response);\n });\n }\n\n private async handle(message: WorkerRequest): Promise<EmittedResponse | undefined> {\n switch (message.type) {\n case 'start':\n return { __vitest_worker_response__: true, type: 'started' };\n case 'run':\n case 'collect': {\n const files = message.context.files.map((s) => s.filepath);\n const error = await this.runFiles(files).catch((e) => e);\n return { __vitest_worker_response__: true, type: 'testfileFinished', error };\n }\n case 'stop':\n return { __vitest_worker_response__: true, type: 'stopped' };\n case 'cancel':\n return undefined;\n }\n }\n\n /**\n * Bundles + injects + collects the given files over the relay, synthesises a\n * Vitest task graph per file, and reports it through `vitest.state` so the\n * reporter/watch/UI ecosystem sees real results.\n *\n * Returns nothing on success; a thrown error is surfaced as the\n * `testfileFinished` error (a whole-pool failure, e.g. relay unreachable).\n */\n private async runFiles(files: string[]): Promise<void> {\n const conn = await this.ensureConnection();\n const report = await runTestFilesOverRelay(conn, files, this.runOpts);\n\n const root = this.project.config.root;\n const projectName = this.project.name || undefined;\n const state = this.project.vitest.state;\n\n for (const fileResult of report.files) {\n const perFile =\n 'error' in fileResult.result\n ? // Whole-file bundle/inject error → synthesise a failed file with no tests.\n {\n startedAt: report.startedAt,\n duration: 0,\n passed: 0,\n failed: 1,\n skipped: 0,\n tests: [],\n }\n : fileResult.result;\n\n const fileTask = synthesizeFileTask(\n fileResult.file,\n root,\n projectName,\n RELAY_POOL_NAME,\n perFile,\n );\n\n state.collectFiles(this.project, [fileTask]);\n state.updateTasks(toTaskResultPacks(fileTask));\n // Event packs drive reporter progress; updateTasks already recorded\n // results, so events are advisory but keep watch/UI output coherent.\n void toTaskEventPacks(fileTask);\n }\n }\n\n private async ensureConnection(): Promise<CdpConnection> {\n if (!this.connection) {\n this.connection = await this.factory.open();\n }\n return this.connection;\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* PoolRunnerInitializer factory */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Creates the Vitest `PoolRunnerInitializer` for the relay pool.\n *\n * Wire it into a Vitest config as `pool: createRelayPool({ connection })`.\n * Vitest moves an object `pool` into `config.poolRunner` and dispatches files\n * whose pool name equals `RELAY_POOL_NAME` to our `createPoolWorker`.\n *\n * @example\n * // vitest.config.ts\n * import { createRelayPool } from '@ait-co/devtools/test-runner';\n * export default defineConfig({\n * test: { pool: createRelayPool({ connection: myFactory }) },\n * });\n */\nexport function createRelayPool(opts: RelayPoolOptions): {\n readonly name: string;\n createPoolWorker: (options: PoolOptions) => PoolWorker;\n} {\n return {\n name: RELAY_POOL_NAME,\n createPoolWorker(options: PoolOptions): PoolWorker {\n return new RelayPoolWorker(options.project, opts);\n },\n };\n}\n"],"mappings":";;;;AA4BA,MAAa,kBAAkB;;;;;;AA8D/B,IAAM,kBAAN,MAA4C;CAC1C,OAAgB;CAChB,UAAmB;CAEnB;CACA;CACA;CACA,4BAA6B,IAAI,KAA0C;CAC3E;CAEA,YAAY,SAAsB,MAAwB;AACxD,OAAK,UAAU;AACf,OAAK,UAAU,KAAK;AACpB,OAAK,UAAU,KAAK;;CAGtB,GAAG,OAAe,UAAwC;EACxD,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM;AACnC,MAAI,CAAC,KAAK;AACR,yBAAM,IAAI,KAAK;AACf,QAAK,UAAU,IAAI,OAAO,IAAI;;AAEhC,MAAI,IAAI,SAAS;;CAGnB,IAAI,OAAe,UAAwC;AACzD,OAAK,UAAU,IAAI,MAAM,EAAE,OAAO,SAAS;;CAG7C,KAAa,OAAe,KAAoB;EAC9C,MAAM,MAAM,KAAK,UAAU,IAAI,MAAM;AACrC,MAAI,CAAC,IAAK;AACV,OAAK,MAAM,MAAM,IAAK,IAAG,IAAI;;CAG/B,YAAY,MAAwB;AAElC,SAAO;;CAGT,MAAM,QAAuB;CAK7B,MAAM,OAAsB;AAC1B,MAAI,KAAK,YAAY;GACnB,MAAM,OAAO,KAAK;AAClB,QAAK,aAAa,KAAA;AAClB,SAAM,KAAK,QAAQ,MAAM,KAAK;;;CAIlC,KAAK,SAA8B;AAE5B,OAAK,OAAO,QAAQ,CAAC,MAAM,aAAa;AAC3C,OAAI,SAAU,MAAK,KAAK,WAAW,SAAS;IAC5C;;CAGJ,MAAc,OAAO,SAA8D;AACjF,UAAQ,QAAQ,MAAhB;GACE,KAAK,QACH,QAAO;IAAE,4BAA4B;IAAM,MAAM;IAAW;GAC9D,KAAK;GACL,KAAK,WAAW;IACd,MAAM,QAAQ,QAAQ,QAAQ,MAAM,KAAK,MAAM,EAAE,SAAS;AAE1D,WAAO;KAAE,4BAA4B;KAAM,MAAM;KAAoB,OADvD,MAAM,KAAK,SAAS,MAAM,CAAC,OAAO,MAAM,EAAE;KACoB;;GAE9E,KAAK,OACH,QAAO;IAAE,4BAA4B;IAAM,MAAM;IAAW;GAC9D,KAAK,SACH;;;;;;;;;;;CAYN,MAAc,SAAS,OAAgC;EAErD,MAAM,SAAS,MAAM,sBADR,MAAM,KAAK,kBAAkB,EACO,OAAO,KAAK,QAAQ;EAErE,MAAM,OAAO,KAAK,QAAQ,OAAO;EACjC,MAAM,cAAc,KAAK,QAAQ,QAAQ,KAAA;EACzC,MAAM,QAAQ,KAAK,QAAQ,OAAO;AAElC,OAAK,MAAM,cAAc,OAAO,OAAO;GACrC,MAAM,UACJ,WAAW,WAAW,SAElB;IACE,WAAW,OAAO;IAClB,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO,EAAE;IACV,GACD,WAAW;GAEjB,MAAM,WAAW,mBACf,WAAW,MACX,MACA,aACA,iBACA,QACD;AAED,SAAM,aAAa,KAAK,SAAS,CAAC,SAAS,CAAC;AAC5C,SAAM,YAAY,kBAAkB,SAAS,CAAC;AAGzC,oBAAiB,SAAS;;;CAInC,MAAc,mBAA2C;AACvD,MAAI,CAAC,KAAK,WACR,MAAK,aAAa,MAAM,KAAK,QAAQ,MAAM;AAE7C,SAAO,KAAK;;;;;;;;;;;;;;;;;AAsBhB,SAAgB,gBAAgB,MAG9B;AACA,QAAO;EACL,MAAM;EACN,iBAAiB,SAAkC;AACjD,UAAO,IAAI,gBAAgB,QAAQ,SAAS,KAAK;;EAEpD"}