everything-dev 0.3.3 → 1.3.3

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 (313) hide show
  1. package/README.md +64 -0
  2. package/cli.js +10 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +29 -0
  4. package/dist/api-contract.cjs +172 -0
  5. package/dist/api-contract.cjs.map +1 -0
  6. package/dist/api-contract.mjs +171 -0
  7. package/dist/api-contract.mjs.map +1 -0
  8. package/dist/api.cjs +124 -0
  9. package/dist/api.cjs.map +1 -0
  10. package/dist/api.d.cts +36 -0
  11. package/dist/api.d.cts.map +1 -0
  12. package/dist/api.d.mts +36 -0
  13. package/dist/api.d.mts.map +1 -0
  14. package/dist/api.mjs +119 -0
  15. package/dist/api.mjs.map +1 -0
  16. package/dist/app.cjs +156 -0
  17. package/dist/app.cjs.map +1 -0
  18. package/dist/app.mjs +153 -0
  19. package/dist/app.mjs.map +1 -0
  20. package/dist/cli/catalog.cjs +30 -0
  21. package/dist/cli/catalog.cjs.map +1 -0
  22. package/dist/cli/catalog.mjs +29 -0
  23. package/dist/cli/catalog.mjs.map +1 -0
  24. package/dist/cli/help.cjs +16 -0
  25. package/dist/cli/help.cjs.map +1 -0
  26. package/dist/cli/help.mjs +16 -0
  27. package/dist/cli/help.mjs.map +1 -0
  28. package/dist/cli/init.cjs +287 -0
  29. package/dist/cli/init.cjs.map +1 -0
  30. package/dist/cli/init.d.cts +36 -0
  31. package/dist/cli/init.d.cts.map +1 -0
  32. package/dist/cli/init.d.mts +36 -0
  33. package/dist/cli/init.d.mts.map +1 -0
  34. package/dist/cli/init.mjs +279 -0
  35. package/dist/cli/init.mjs.map +1 -0
  36. package/dist/cli/parse.cjs +96 -0
  37. package/dist/cli/parse.cjs.map +1 -0
  38. package/dist/cli/parse.mjs +95 -0
  39. package/dist/cli/parse.mjs.map +1 -0
  40. package/dist/cli/prompts.cjs +42 -0
  41. package/dist/cli/prompts.cjs.map +1 -0
  42. package/dist/cli/prompts.mjs +41 -0
  43. package/dist/cli/prompts.mjs.map +1 -0
  44. package/dist/cli.cjs +167 -0
  45. package/dist/cli.cjs.map +1 -0
  46. package/dist/cli.d.cts +1 -0
  47. package/dist/cli.d.mts +1 -0
  48. package/dist/cli.mjs +166 -0
  49. package/dist/cli.mjs.map +1 -0
  50. package/dist/components/dev-view.cjs +307 -0
  51. package/dist/components/dev-view.cjs.map +1 -0
  52. package/dist/components/dev-view.mjs +306 -0
  53. package/dist/components/dev-view.mjs.map +1 -0
  54. package/dist/components/streaming-view.cjs +146 -0
  55. package/dist/components/streaming-view.cjs.map +1 -0
  56. package/dist/components/streaming-view.mjs +144 -0
  57. package/dist/components/streaming-view.mjs.map +1 -0
  58. package/dist/config.cjs +280 -0
  59. package/dist/config.cjs.map +1 -0
  60. package/dist/config.d.cts +35 -0
  61. package/dist/config.d.cts.map +1 -0
  62. package/dist/config.d.mts +35 -0
  63. package/dist/config.d.mts.map +1 -0
  64. package/dist/config.mjs +266 -0
  65. package/dist/config.mjs.map +1 -0
  66. package/dist/contract.cjs +209 -0
  67. package/dist/contract.cjs.map +1 -0
  68. package/dist/contract.d.cts +490 -0
  69. package/dist/contract.d.cts.map +1 -0
  70. package/dist/contract.d.mts +490 -0
  71. package/dist/contract.d.mts.map +1 -0
  72. package/dist/contract.meta.cjs +104 -0
  73. package/dist/contract.meta.cjs.map +1 -0
  74. package/dist/contract.meta.d.cts +141 -0
  75. package/dist/contract.meta.d.cts.map +1 -0
  76. package/dist/contract.meta.d.mts +141 -0
  77. package/dist/contract.meta.d.mts.map +1 -0
  78. package/dist/contract.meta.mjs +102 -0
  79. package/dist/contract.meta.mjs.map +1 -0
  80. package/dist/contract.mjs +186 -0
  81. package/dist/contract.mjs.map +1 -0
  82. package/dist/dev-logs.cjs +53 -0
  83. package/dist/dev-logs.cjs.map +1 -0
  84. package/dist/dev-logs.mjs +51 -0
  85. package/dist/dev-logs.mjs.map +1 -0
  86. package/dist/dev-session.cjs +195 -0
  87. package/dist/dev-session.cjs.map +1 -0
  88. package/dist/dev-session.mjs +194 -0
  89. package/dist/dev-session.mjs.map +1 -0
  90. package/dist/fastkv.cjs +89 -0
  91. package/dist/fastkv.cjs.map +1 -0
  92. package/dist/fastkv.d.cts +11 -0
  93. package/dist/fastkv.d.cts.map +1 -0
  94. package/dist/fastkv.d.mts +11 -0
  95. package/dist/fastkv.d.mts.map +1 -0
  96. package/dist/fastkv.mjs +82 -0
  97. package/dist/fastkv.mjs.map +1 -0
  98. package/dist/federation.server.cjs +27 -0
  99. package/dist/federation.server.cjs.map +1 -0
  100. package/dist/federation.server.mjs +27 -0
  101. package/dist/federation.server.mjs.map +1 -0
  102. package/dist/host.cjs +367 -0
  103. package/dist/host.cjs.map +1 -0
  104. package/dist/host.d.cts +22 -0
  105. package/dist/host.d.cts.map +1 -0
  106. package/dist/host.d.mts +22 -0
  107. package/dist/host.d.mts.map +1 -0
  108. package/dist/host.mjs +364 -0
  109. package/dist/host.mjs.map +1 -0
  110. package/dist/index.cjs +122 -0
  111. package/dist/index.d.cts +7 -0
  112. package/dist/index.d.mts +7 -0
  113. package/dist/index.mjs +9 -0
  114. package/dist/integrity.cjs +39 -0
  115. package/dist/integrity.cjs.map +1 -0
  116. package/dist/integrity.d.cts +7 -0
  117. package/dist/integrity.d.cts.map +1 -0
  118. package/dist/integrity.d.mts +7 -0
  119. package/dist/integrity.d.mts.map +1 -0
  120. package/dist/integrity.mjs +35 -0
  121. package/dist/integrity.mjs.map +1 -0
  122. package/dist/internal/manifest-normalizer.cjs +140 -0
  123. package/dist/internal/manifest-normalizer.cjs.map +1 -0
  124. package/dist/internal/manifest-normalizer.mjs +138 -0
  125. package/dist/internal/manifest-normalizer.mjs.map +1 -0
  126. package/dist/mf.cjs +77 -0
  127. package/dist/mf.cjs.map +1 -0
  128. package/dist/mf.d.cts +19 -0
  129. package/dist/mf.d.cts.map +1 -0
  130. package/dist/mf.d.mts +19 -0
  131. package/dist/mf.d.mts.map +1 -0
  132. package/dist/mf.mjs +71 -0
  133. package/dist/mf.mjs.map +1 -0
  134. package/dist/near-cli.cjs +196 -0
  135. package/dist/near-cli.cjs.map +1 -0
  136. package/dist/near-cli.mjs +193 -0
  137. package/dist/near-cli.mjs.map +1 -0
  138. package/dist/network.cjs +9 -0
  139. package/dist/network.cjs.map +1 -0
  140. package/dist/network.mjs +8 -0
  141. package/dist/network.mjs.map +1 -0
  142. package/dist/orchestrator.cjs +441 -0
  143. package/dist/orchestrator.cjs.map +1 -0
  144. package/dist/orchestrator.d.cts +40 -0
  145. package/dist/orchestrator.d.cts.map +1 -0
  146. package/dist/orchestrator.d.mts +40 -0
  147. package/dist/orchestrator.d.mts.map +1 -0
  148. package/dist/orchestrator.mjs +436 -0
  149. package/dist/orchestrator.mjs.map +1 -0
  150. package/dist/plugin.cjs +830 -0
  151. package/dist/plugin.cjs.map +1 -0
  152. package/dist/plugin.d.cts +347 -0
  153. package/dist/plugin.d.cts.map +1 -0
  154. package/dist/plugin.d.mts +348 -0
  155. package/dist/plugin.d.mts.map +1 -0
  156. package/dist/plugin.mjs +827 -0
  157. package/dist/plugin.mjs.map +1 -0
  158. package/dist/process-registry.cjs +120 -0
  159. package/dist/process-registry.cjs.map +1 -0
  160. package/dist/process-registry.d.cts +25 -0
  161. package/dist/process-registry.d.cts.map +1 -0
  162. package/dist/process-registry.d.mts +25 -0
  163. package/dist/process-registry.d.mts.map +1 -0
  164. package/dist/process-registry.mjs +119 -0
  165. package/dist/process-registry.mjs.map +1 -0
  166. package/dist/sdk.cjs +61 -0
  167. package/dist/sdk.d.cts +5 -0
  168. package/dist/sdk.d.mts +5 -0
  169. package/dist/sdk.mjs +6 -0
  170. package/dist/shared.cjs +143 -0
  171. package/dist/shared.cjs.map +1 -0
  172. package/dist/shared.d.cts +33 -0
  173. package/dist/shared.d.cts.map +1 -0
  174. package/dist/shared.d.mts +33 -0
  175. package/dist/shared.d.mts.map +1 -0
  176. package/dist/shared.mjs +140 -0
  177. package/dist/shared.mjs.map +1 -0
  178. package/dist/types.cjs +160 -0
  179. package/dist/types.cjs.map +1 -0
  180. package/dist/types.d.cts +269 -0
  181. package/dist/types.d.cts.map +1 -0
  182. package/dist/types.d.mts +269 -0
  183. package/dist/types.d.mts.map +1 -0
  184. package/dist/types.mjs +144 -0
  185. package/dist/types.mjs.map +1 -0
  186. package/dist/ui/head.cjs +67 -0
  187. package/dist/ui/head.cjs.map +1 -0
  188. package/dist/ui/head.d.cts +19 -0
  189. package/dist/ui/head.d.cts.map +1 -0
  190. package/dist/ui/head.d.mts +19 -0
  191. package/dist/ui/head.d.mts.map +1 -0
  192. package/dist/ui/head.mjs +61 -0
  193. package/dist/ui/head.mjs.map +1 -0
  194. package/dist/ui/index.cjs +32 -0
  195. package/dist/ui/index.d.cts +7 -0
  196. package/dist/ui/index.d.mts +7 -0
  197. package/dist/ui/index.mjs +6 -0
  198. package/dist/ui/metadata.cjs +106 -0
  199. package/dist/ui/metadata.cjs.map +1 -0
  200. package/dist/ui/metadata.d.cts +35 -0
  201. package/dist/ui/metadata.d.cts.map +1 -0
  202. package/dist/ui/metadata.d.mts +35 -0
  203. package/dist/ui/metadata.d.mts.map +1 -0
  204. package/dist/ui/metadata.mjs +100 -0
  205. package/dist/ui/metadata.mjs.map +1 -0
  206. package/dist/ui/router.cjs +56 -0
  207. package/dist/ui/router.cjs.map +1 -0
  208. package/dist/ui/router.d.cts +11 -0
  209. package/dist/ui/router.d.cts.map +1 -0
  210. package/dist/ui/router.d.mts +11 -0
  211. package/dist/ui/router.d.mts.map +1 -0
  212. package/dist/ui/router.mjs +51 -0
  213. package/dist/ui/router.mjs.map +1 -0
  214. package/dist/ui/runtime.cjs +65 -0
  215. package/dist/ui/runtime.cjs.map +1 -0
  216. package/dist/ui/runtime.d.cts +29 -0
  217. package/dist/ui/runtime.d.cts.map +1 -0
  218. package/dist/ui/runtime.d.mts +29 -0
  219. package/dist/ui/runtime.d.mts.map +1 -0
  220. package/dist/ui/runtime.mjs +53 -0
  221. package/dist/ui/runtime.mjs.map +1 -0
  222. package/dist/ui/types.cjs +0 -0
  223. package/dist/ui/types.d.cts +52 -0
  224. package/dist/ui/types.d.cts.map +1 -0
  225. package/dist/ui/types.d.mts +52 -0
  226. package/dist/ui/types.d.mts.map +1 -0
  227. package/dist/ui/types.mjs +1 -0
  228. package/dist/utils/banner.cjs +24 -0
  229. package/dist/utils/banner.cjs.map +1 -0
  230. package/dist/utils/banner.mjs +23 -0
  231. package/dist/utils/banner.mjs.map +1 -0
  232. package/dist/utils/linkify.cjs +15 -0
  233. package/dist/utils/linkify.cjs.map +1 -0
  234. package/dist/utils/linkify.mjs +14 -0
  235. package/dist/utils/linkify.mjs.map +1 -0
  236. package/dist/utils/run.cjs +40 -0
  237. package/dist/utils/run.cjs.map +1 -0
  238. package/dist/utils/run.mjs +39 -0
  239. package/dist/utils/run.mjs.map +1 -0
  240. package/dist/utils/theme.cjs +44 -0
  241. package/dist/utils/theme.cjs.map +1 -0
  242. package/dist/utils/theme.mjs +37 -0
  243. package/dist/utils/theme.mjs.map +1 -0
  244. package/package.json +269 -80
  245. package/src/api-contract.ts +309 -0
  246. package/src/api.ts +181 -0
  247. package/src/app.ts +346 -0
  248. package/src/cli/catalog.ts +49 -0
  249. package/src/cli/help.ts +13 -0
  250. package/src/cli/init.ts +386 -0
  251. package/src/cli/parse.ts +130 -0
  252. package/src/cli/prompts.ts +64 -0
  253. package/src/cli.ts +203 -1507
  254. package/src/components/dev-view.tsx +307 -255
  255. package/src/components/streaming-view.ts +164 -128
  256. package/src/config.ts +462 -532
  257. package/src/contract.meta.ts +96 -0
  258. package/src/contract.ts +164 -561
  259. package/src/dev-logs.ts +85 -0
  260. package/src/dev-session.ts +318 -0
  261. package/src/fastkv.ts +153 -0
  262. package/src/federation.server.ts +43 -0
  263. package/src/host.ts +526 -0
  264. package/src/index.ts +6 -3
  265. package/src/integrity.ts +54 -0
  266. package/src/internal/manifest-normalizer.ts +251 -0
  267. package/src/mf.ts +105 -0
  268. package/src/near-cli.ts +284 -0
  269. package/src/network.ts +3 -0
  270. package/src/orchestrator.ts +648 -0
  271. package/src/plugin.ts +1130 -2311
  272. package/src/process-registry.ts +154 -0
  273. package/src/scripts/sync-api-contract.ts +24 -0
  274. package/src/sdk.ts +14 -0
  275. package/src/shared.ts +206 -0
  276. package/src/types.ts +152 -206
  277. package/src/ui/head.ts +34 -27
  278. package/src/ui/index.ts +3 -3
  279. package/src/ui/metadata.ts +95 -0
  280. package/src/ui/router.ts +22 -6
  281. package/src/ui/runtime.ts +55 -6
  282. package/src/ui/types.ts +24 -11
  283. package/src/utils/banner.ts +10 -6
  284. package/src/utils/run.ts +26 -27
  285. package/src/utils/theme.ts +3 -66
  286. package/src/components/monitor-view.tsx +0 -475
  287. package/src/components/status-view.tsx +0 -173
  288. package/src/lib/env.ts +0 -109
  289. package/src/lib/near-cli.ts +0 -289
  290. package/src/lib/nova.ts +0 -266
  291. package/src/lib/orchestrator.ts +0 -276
  292. package/src/lib/process-registry.ts +0 -166
  293. package/src/lib/process.ts +0 -550
  294. package/src/lib/resource-monitor/assertions.ts +0 -234
  295. package/src/lib/resource-monitor/command.ts +0 -283
  296. package/src/lib/resource-monitor/diff.ts +0 -157
  297. package/src/lib/resource-monitor/errors.ts +0 -127
  298. package/src/lib/resource-monitor/index.ts +0 -305
  299. package/src/lib/resource-monitor/platform/darwin.ts +0 -306
  300. package/src/lib/resource-monitor/platform/index.ts +0 -35
  301. package/src/lib/resource-monitor/platform/linux.ts +0 -332
  302. package/src/lib/resource-monitor/platform/windows.ts +0 -298
  303. package/src/lib/resource-monitor/snapshot.ts +0 -217
  304. package/src/lib/resource-monitor/types.ts +0 -74
  305. package/src/lib/session-recorder/errors.ts +0 -102
  306. package/src/lib/session-recorder/flows/login.ts +0 -210
  307. package/src/lib/session-recorder/index.ts +0 -361
  308. package/src/lib/session-recorder/playwright.ts +0 -257
  309. package/src/lib/session-recorder/report.ts +0 -353
  310. package/src/lib/session-recorder/server.ts +0 -268
  311. package/src/lib/session-recorder/types.ts +0 -115
  312. package/src/lib/sync.ts +0 -1
  313. package/src/ui/files.ts +0 -134
@@ -1,210 +0,0 @@
1
- import { Effect } from "effect";
2
- import { AuthenticationFailed, PopupNotDetected } from "../errors";
3
- import {
4
- type BrowserHandle,
5
- clickElement,
6
- getBrowserMetrics,
7
- navigateTo,
8
- sleep,
9
- waitForPopup,
10
- waitForSelector,
11
- } from "../playwright";
12
- import type { SessionEventType } from "../types";
13
-
14
- interface FlowRecorder {
15
- recordEvent: (
16
- type: SessionEventType,
17
- label: string,
18
- metadata?: Record<string, unknown>
19
- ) => Effect.Effect<void>;
20
- }
21
-
22
- interface LoginFlowOptions {
23
- baseUrl: string;
24
- headless: boolean;
25
- stubWallet: boolean;
26
- timeout: number;
27
- }
28
-
29
- const DEFAULT_LOGIN_OPTIONS: LoginFlowOptions = {
30
- baseUrl: "http://localhost:3000",
31
- headless: true,
32
- stubWallet: true,
33
- timeout: 30000,
34
- };
35
-
36
- export const runLoginFlow = (
37
- browser: BrowserHandle,
38
- recorder: FlowRecorder,
39
- options: Partial<LoginFlowOptions> = {}
40
- ): Effect.Effect<void, AuthenticationFailed | PopupNotDetected> =>
41
- Effect.gen(function* () {
42
- const opts = { ...DEFAULT_LOGIN_OPTIONS, ...options };
43
- const { page, context } = browser;
44
-
45
- yield* Effect.logInfo("Starting login flow");
46
- yield* Effect.asVoid(recorder.recordEvent("custom", "login_flow_start"));
47
-
48
- yield* navigateTo(page, `${opts.baseUrl}/login`);
49
- yield* Effect.asVoid(recorder.recordEvent("pageload", "/login", { url: `${opts.baseUrl}/login` }));
50
-
51
- yield* sleep(1000);
52
-
53
- const connectButtonSelector = 'button:has-text("connect near wallet")';
54
-
55
- yield* Effect.tryPromise({
56
- try: () => page.waitForSelector(connectButtonSelector, { timeout: opts.timeout }),
57
- catch: () => new AuthenticationFailed({
58
- step: "find_connect_button",
59
- reason: "Connect wallet button not found",
60
- }),
61
- });
62
-
63
- yield* Effect.asVoid(recorder.recordEvent("auth_start", "wallet_connect_initiated"));
64
-
65
- if (opts.headless && opts.stubWallet) {
66
- yield* Effect.logInfo("Stubbing wallet connection in headless mode");
67
- yield* Effect.asVoid(recorder.recordEvent("custom", "wallet_stubbed", { reason: "headless_mode" }));
68
-
69
- yield* clickElement(page, connectButtonSelector);
70
-
71
- yield* sleep(2000);
72
-
73
- const hasSignInButton = yield* Effect.tryPromise({
74
- try: async () => {
75
- try {
76
- await page.waitForSelector('button:has-text("sign in as")', { timeout: 5000 });
77
- return true;
78
- } catch {
79
- return false;
80
- }
81
- },
82
- catch: () => false,
83
- });
84
-
85
- if (hasSignInButton) {
86
- yield* Effect.asVoid(recorder.recordEvent("custom", "sign_in_button_appeared"));
87
- } else {
88
- yield* Effect.asVoid(recorder.recordEvent("custom", "wallet_popup_would_open", {
89
- note: "In headed mode, NEAR wallet popup would appear here",
90
- }));
91
- }
92
-
93
- yield* Effect.asVoid(recorder.recordEvent("auth_complete", "login_flow_completed_stubbed"));
94
-
95
- } else {
96
- yield* Effect.logInfo("Running full wallet flow (headed mode)");
97
-
98
- yield* clickElement(page, connectButtonSelector);
99
- yield* Effect.asVoid(recorder.recordEvent("click", "connect_wallet_button"));
100
-
101
- const popupPromise = waitForPopup(context, opts.timeout);
102
-
103
- const popup = yield* Effect.catchAll(popupPromise, () =>
104
- Effect.fail(new PopupNotDetected({ timeoutMs: opts.timeout }))
105
- );
106
-
107
- yield* Effect.asVoid(recorder.recordEvent("popup_open", "near_wallet_popup", {
108
- url: popup.url(),
109
- }));
110
-
111
- yield* Effect.logInfo("NEAR wallet popup opened - waiting for user interaction");
112
- yield* Effect.asVoid(recorder.recordEvent("custom", "awaiting_user_approval"));
113
-
114
- yield* sleep(5000);
115
-
116
- const popupClosed = yield* Effect.tryPromise({
117
- try: async () => {
118
- try {
119
- await popup.waitForSelector("body", { timeout: 1000 });
120
- return false;
121
- } catch {
122
- return true;
123
- }
124
- },
125
- catch: () => true,
126
- });
127
-
128
- if (popupClosed) {
129
- yield* Effect.asVoid(recorder.recordEvent("popup_close", "near_wallet_popup"));
130
- }
131
-
132
- const signInButtonSelector = 'button:has-text("sign in as")';
133
- const hasSignIn = yield* Effect.tryPromise({
134
- try: async () => {
135
- try {
136
- await page.waitForSelector(signInButtonSelector, { timeout: 10000 });
137
- return true;
138
- } catch {
139
- return false;
140
- }
141
- },
142
- catch: () => false,
143
- });
144
-
145
- if (hasSignIn) {
146
- yield* Effect.asVoid(recorder.recordEvent("custom", "wallet_connected"));
147
- yield* clickElement(page, signInButtonSelector);
148
- yield* Effect.asVoid(recorder.recordEvent("click", "sign_in_button"));
149
- }
150
-
151
- yield* Effect.asVoid(recorder.recordEvent("auth_complete", "login_flow_completed"));
152
- }
153
-
154
- yield* Effect.logInfo("Login flow completed");
155
- });
156
-
157
- export const runNavigationFlow = (
158
- browser: BrowserHandle,
159
- recorder: FlowRecorder,
160
- routes: string[],
161
- baseUrl: string
162
- ): Effect.Effect<void> =>
163
- Effect.gen(function* () {
164
- yield* Effect.logInfo(`Running navigation flow through ${routes.length} routes`);
165
-
166
- for (const route of routes) {
167
- const url = `${baseUrl}${route}`;
168
- yield* navigateTo(browser.page, url);
169
- yield* Effect.asVoid(recorder.recordEvent("navigation", route, { url }));
170
-
171
- yield* sleep(1000);
172
-
173
- yield* Effect.asVoid(recorder.recordEvent("interval", `visited_${route}`));
174
- }
175
-
176
- yield* Effect.logInfo("Navigation flow completed");
177
- });
178
-
179
- export const runClickFlow = (
180
- browser: BrowserHandle,
181
- recorder: FlowRecorder,
182
- selectors: Array<{ selector: string; label: string }>
183
- ): Effect.Effect<void> =>
184
- Effect.gen(function* () {
185
- yield* Effect.logInfo(`Running click flow with ${selectors.length} interactions`);
186
-
187
- for (const { selector, label } of selectors) {
188
- const exists = yield* Effect.tryPromise({
189
- try: async () => {
190
- try {
191
- await browser.page.waitForSelector(selector, { timeout: 5000 });
192
- return true;
193
- } catch {
194
- return false;
195
- }
196
- },
197
- catch: () => false,
198
- });
199
-
200
- if (exists) {
201
- yield* clickElement(browser.page, selector);
202
- yield* Effect.asVoid(recorder.recordEvent("click", label, { selector }));
203
- yield* sleep(500);
204
- } else {
205
- yield* Effect.logWarning(`Selector not found: ${selector}`);
206
- }
207
- }
208
-
209
- yield* Effect.logInfo("Click flow completed");
210
- });
@@ -1,361 +0,0 @@
1
- import { Effect, Logger, LogLevel } from "effect";
2
- import { createSnapshotWithPlatform, PlatformLive, runSilent } from "../resource-monitor";
3
- import type { Snapshot } from "../resource-monitor";
4
- import {
5
- type SessionRecorderError,
6
- SessionTimeout,
7
- SnapshotFailed,
8
- } from "./errors";
9
- import {
10
- type BrowserHandle,
11
- closeBrowser,
12
- getBrowserMetrics,
13
- launchBrowser,
14
- } from "./playwright";
15
- import {
16
- exportHTMLReport,
17
- exportJSON,
18
- formatEventTimeline,
19
- formatReportSummary,
20
- generateReport,
21
- } from "./report";
22
- import {
23
- checkPortsAvailable,
24
- shutdownServers,
25
- startServers,
26
- waitForPortFree,
27
- } from "./server";
28
- import {
29
- DEFAULT_SESSION_CONFIG,
30
- type BrowserMetrics,
31
- type SessionConfig,
32
- type SessionEvent,
33
- type SessionEventType,
34
- type SessionReport,
35
- type ServerOrchestrator,
36
- } from "./types";
37
-
38
- let eventCounter = 0;
39
-
40
- const generateEventId = (): string => {
41
- eventCounter += 1;
42
- return `evt_${Date.now()}_${eventCounter}`;
43
- };
44
-
45
- const generateSessionId = (): string => {
46
- return `sess_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
47
- };
48
-
49
- export class SessionRecorder {
50
- private config: SessionConfig;
51
- private sessionId: string;
52
- private events: SessionEvent[] = [];
53
- private startTime: number = 0;
54
- private endTime: number = 0;
55
- private intervalHandle: ReturnType<typeof setInterval> | null = null;
56
- private serverOrchestrator: ServerOrchestrator | null = null;
57
- private browserHandle: BrowserHandle | null = null;
58
- private isRecording = false;
59
-
60
- private constructor(config: SessionConfig) {
61
- this.config = config;
62
- this.sessionId = generateSessionId();
63
- }
64
-
65
- static create = (
66
- config?: Partial<SessionConfig>
67
- ): Effect.Effect<SessionRecorder> =>
68
- Effect.gen(function* () {
69
- const fullConfig = { ...DEFAULT_SESSION_CONFIG, ...config };
70
- yield* Effect.logInfo(`Creating SessionRecorder: ${JSON.stringify(fullConfig)}`);
71
- return new SessionRecorder(fullConfig);
72
- });
73
-
74
- getConfig(): SessionConfig {
75
- return { ...this.config };
76
- }
77
-
78
- getSessionId(): string {
79
- return this.sessionId;
80
- }
81
-
82
- getEvents(): SessionEvent[] {
83
- return [...this.events];
84
- }
85
-
86
- isActive(): boolean {
87
- return this.isRecording;
88
- }
89
-
90
- takeSnapshot(): Effect.Effect<Snapshot, SnapshotFailed> {
91
- const self = this;
92
- return Effect.gen(function* () {
93
- const snapshot = yield* Effect.tryPromise({
94
- try: () => runSilent(createSnapshotWithPlatform({ ports: self.config.ports })),
95
- catch: (e) => new SnapshotFailed({ reason: String(e) }),
96
- });
97
- return snapshot;
98
- });
99
- }
100
-
101
- recordEvent(
102
- type: SessionEventType,
103
- label: string,
104
- metadata?: Record<string, unknown>
105
- ): Effect.Effect<SessionEvent, SnapshotFailed> {
106
- const self = this;
107
- return Effect.gen(function* () {
108
- const snapshot = yield* self.takeSnapshot();
109
-
110
- let browserMetrics: BrowserMetrics | undefined;
111
- if (self.browserHandle) {
112
- const metricsResult = yield* Effect.either(
113
- getBrowserMetrics(self.browserHandle.page)
114
- );
115
- if (metricsResult._tag === "Right") {
116
- browserMetrics = metricsResult.right;
117
- }
118
- }
119
-
120
- const event: SessionEvent = {
121
- id: generateEventId(),
122
- timestamp: Date.now(),
123
- type,
124
- label,
125
- snapshot,
126
- browserMetrics,
127
- url: self.browserHandle?.page.url(),
128
- metadata,
129
- };
130
-
131
- self.events.push(event);
132
- yield* Effect.logDebug(`Event recorded: ${type} - ${label}`);
133
-
134
- return event;
135
- });
136
- }
137
-
138
- startServers(
139
- mode: "start" | "dev" = "start"
140
- ): Effect.Effect<void, SessionRecorderError> {
141
- const self = this;
142
- return Effect.gen(function* () {
143
- yield* Effect.logInfo(`Starting servers in ${mode} mode`);
144
-
145
- const portsAvailable = yield* checkPortsAvailable(self.config.ports);
146
- if (!portsAvailable) {
147
- yield* Effect.logWarning("Some ports already in use - proceeding anyway");
148
- }
149
-
150
- const orchestrator = yield* startServers(mode, {
151
- port: self.config.ports[0],
152
- });
153
-
154
- self.serverOrchestrator = orchestrator;
155
- yield* Effect.logInfo("Servers started successfully");
156
- });
157
- }
158
-
159
- stopServers(): Effect.Effect<void> {
160
- const self = this;
161
- return Effect.gen(function* () {
162
- if (self.serverOrchestrator) {
163
- yield* shutdownServers(self.serverOrchestrator);
164
- self.serverOrchestrator = null;
165
- }
166
- });
167
- }
168
-
169
- launchBrowser(): Effect.Effect<BrowserHandle, SessionRecorderError> {
170
- const self = this;
171
- return Effect.gen(function* () {
172
- yield* Effect.logInfo(`Launching browser (headless: ${self.config.headless})`);
173
-
174
- const handle = yield* launchBrowser(self.config.headless);
175
- self.browserHandle = handle;
176
-
177
- return handle;
178
- });
179
- }
180
-
181
- closeBrowser(): Effect.Effect<void> {
182
- const self = this;
183
- return Effect.gen(function* () {
184
- if (self.browserHandle) {
185
- yield* closeBrowser(self.browserHandle);
186
- self.browserHandle = null;
187
- }
188
- });
189
- }
190
-
191
- getBrowser(): BrowserHandle | null {
192
- return this.browserHandle;
193
- }
194
-
195
- startRecording(): Effect.Effect<void, SnapshotFailed> {
196
- const self = this;
197
- return Effect.gen(function* () {
198
- if (self.isRecording) {
199
- yield* Effect.logWarning("Already recording");
200
- return;
201
- }
202
-
203
- self.isRecording = true;
204
- self.startTime = Date.now();
205
- self.events = [];
206
-
207
- yield* Effect.logInfo("Starting session recording");
208
-
209
- yield* self.recordEvent("baseline", "session_start");
210
-
211
- if (self.config.snapshotIntervalMs > 0) {
212
- self.intervalHandle = setInterval(() => {
213
- Effect.runPromise(
214
- self.recordEvent("interval", "auto_snapshot").pipe(
215
- Effect.catchAll(() => Effect.void)
216
- )
217
- );
218
- }, self.config.snapshotIntervalMs);
219
- }
220
-
221
- yield* Effect.logInfo(`Recording started with ${self.config.snapshotIntervalMs}ms interval`);
222
- });
223
- }
224
-
225
- stopRecording(): Effect.Effect<SessionReport, SnapshotFailed> {
226
- const self = this;
227
- return Effect.gen(function* () {
228
- if (!self.isRecording) {
229
- yield* Effect.logWarning("Not recording");
230
- return generateReport(
231
- self.sessionId,
232
- self.config,
233
- self.events,
234
- self.startTime,
235
- Date.now()
236
- );
237
- }
238
-
239
- if (self.intervalHandle) {
240
- clearInterval(self.intervalHandle);
241
- self.intervalHandle = null;
242
- }
243
-
244
- yield* self.recordEvent("custom", "session_end");
245
-
246
- self.isRecording = false;
247
- self.endTime = Date.now();
248
-
249
- yield* Effect.logInfo("Recording stopped");
250
-
251
- const report = generateReport(
252
- self.sessionId,
253
- self.config,
254
- self.events,
255
- self.startTime,
256
- self.endTime
257
- );
258
-
259
- return report;
260
- });
261
- }
262
-
263
- exportReport(
264
- filepath: string,
265
- format: "json" | "html" = "json"
266
- ): Effect.Effect<void, SessionRecorderError> {
267
- const self = this;
268
- return Effect.gen(function* () {
269
- const report = generateReport(
270
- self.sessionId,
271
- self.config,
272
- self.events,
273
- self.startTime,
274
- self.endTime || Date.now()
275
- );
276
-
277
- if (format === "html") {
278
- yield* exportHTMLReport(report, filepath);
279
- } else {
280
- yield* exportJSON(report, filepath);
281
- }
282
- });
283
- }
284
-
285
- generateReport(): SessionReport {
286
- return generateReport(
287
- this.sessionId,
288
- this.config,
289
- this.events,
290
- this.startTime,
291
- this.endTime || Date.now()
292
- );
293
- }
294
-
295
- printSummary(): Effect.Effect<void> {
296
- const self = this;
297
- return Effect.sync(() => {
298
- const report = self.generateReport();
299
- console.log(formatReportSummary(report));
300
- });
301
- }
302
-
303
- printTimeline(): Effect.Effect<void> {
304
- const self = this;
305
- return Effect.sync(() => {
306
- console.log(formatEventTimeline(self.events));
307
- });
308
- }
309
-
310
- cleanup(): Effect.Effect<void> {
311
- const self = this;
312
- return Effect.gen(function* () {
313
- yield* Effect.logInfo("Cleaning up session recorder");
314
-
315
- if (self.intervalHandle) {
316
- clearInterval(self.intervalHandle);
317
- self.intervalHandle = null;
318
- }
319
-
320
- yield* self.closeBrowser();
321
- yield* self.stopServers();
322
-
323
- yield* Effect.logInfo("Cleanup complete");
324
- });
325
- }
326
- }
327
-
328
- export const runSession = <E>(
329
- effect: Effect.Effect<void, E>
330
- ): Promise<void> =>
331
- effect.pipe(
332
- Effect.provide(PlatformLive),
333
- Logger.withMinimumLogLevel(LogLevel.Info),
334
- Effect.runPromise
335
- );
336
-
337
- export const runSessionSilent = <E>(
338
- effect: Effect.Effect<void, E>
339
- ): Promise<void> =>
340
- effect.pipe(
341
- Effect.provide(PlatformLive),
342
- Logger.withMinimumLogLevel(LogLevel.Error),
343
- Effect.runPromise
344
- );
345
-
346
- export const runSessionDebug = <E>(
347
- effect: Effect.Effect<void, E>
348
- ): Promise<void> =>
349
- effect.pipe(
350
- Effect.provide(PlatformLive),
351
- Logger.withMinimumLogLevel(LogLevel.Debug),
352
- Effect.runPromise
353
- );
354
-
355
- export * from "./errors";
356
- export * from "./types";
357
- export * from "./server";
358
- export * from "./playwright";
359
- export * from "./report";
360
- export { runLoginFlow, runNavigationFlow, runClickFlow } from "./flows/login";
361
- export { diffSnapshots, hasLeaks, type Snapshot, type SnapshotDiff } from "../resource-monitor";