everything-dev 0.3.2 → 1.3.2

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 (308) 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 +317 -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 +309 -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/mf.cjs +77 -0
  123. package/dist/mf.cjs.map +1 -0
  124. package/dist/mf.d.cts +19 -0
  125. package/dist/mf.d.cts.map +1 -0
  126. package/dist/mf.d.mts +19 -0
  127. package/dist/mf.d.mts.map +1 -0
  128. package/dist/mf.mjs +71 -0
  129. package/dist/mf.mjs.map +1 -0
  130. package/dist/near-cli.cjs +196 -0
  131. package/dist/near-cli.cjs.map +1 -0
  132. package/dist/near-cli.mjs +193 -0
  133. package/dist/near-cli.mjs.map +1 -0
  134. package/dist/network.cjs +9 -0
  135. package/dist/network.cjs.map +1 -0
  136. package/dist/network.mjs +8 -0
  137. package/dist/network.mjs.map +1 -0
  138. package/dist/orchestrator.cjs +441 -0
  139. package/dist/orchestrator.cjs.map +1 -0
  140. package/dist/orchestrator.d.cts +40 -0
  141. package/dist/orchestrator.d.cts.map +1 -0
  142. package/dist/orchestrator.d.mts +40 -0
  143. package/dist/orchestrator.d.mts.map +1 -0
  144. package/dist/orchestrator.mjs +436 -0
  145. package/dist/orchestrator.mjs.map +1 -0
  146. package/dist/plugin.cjs +825 -0
  147. package/dist/plugin.cjs.map +1 -0
  148. package/dist/plugin.d.cts +347 -0
  149. package/dist/plugin.d.cts.map +1 -0
  150. package/dist/plugin.d.mts +348 -0
  151. package/dist/plugin.d.mts.map +1 -0
  152. package/dist/plugin.mjs +822 -0
  153. package/dist/plugin.mjs.map +1 -0
  154. package/dist/process-registry.cjs +120 -0
  155. package/dist/process-registry.cjs.map +1 -0
  156. package/dist/process-registry.d.cts +25 -0
  157. package/dist/process-registry.d.cts.map +1 -0
  158. package/dist/process-registry.d.mts +25 -0
  159. package/dist/process-registry.d.mts.map +1 -0
  160. package/dist/process-registry.mjs +119 -0
  161. package/dist/process-registry.mjs.map +1 -0
  162. package/dist/sdk.cjs +61 -0
  163. package/dist/sdk.d.cts +5 -0
  164. package/dist/sdk.d.mts +5 -0
  165. package/dist/sdk.mjs +6 -0
  166. package/dist/shared.cjs +143 -0
  167. package/dist/shared.cjs.map +1 -0
  168. package/dist/shared.d.cts +33 -0
  169. package/dist/shared.d.cts.map +1 -0
  170. package/dist/shared.d.mts +33 -0
  171. package/dist/shared.d.mts.map +1 -0
  172. package/dist/shared.mjs +140 -0
  173. package/dist/shared.mjs.map +1 -0
  174. package/dist/types.cjs +160 -0
  175. package/dist/types.cjs.map +1 -0
  176. package/dist/types.d.cts +269 -0
  177. package/dist/types.d.cts.map +1 -0
  178. package/dist/types.d.mts +269 -0
  179. package/dist/types.d.mts.map +1 -0
  180. package/dist/types.mjs +144 -0
  181. package/dist/types.mjs.map +1 -0
  182. package/dist/ui/head.cjs +67 -0
  183. package/dist/ui/head.cjs.map +1 -0
  184. package/dist/ui/head.d.cts +19 -0
  185. package/dist/ui/head.d.cts.map +1 -0
  186. package/dist/ui/head.d.mts +19 -0
  187. package/dist/ui/head.d.mts.map +1 -0
  188. package/dist/ui/head.mjs +61 -0
  189. package/dist/ui/head.mjs.map +1 -0
  190. package/dist/ui/index.cjs +32 -0
  191. package/dist/ui/index.d.cts +7 -0
  192. package/dist/ui/index.d.mts +7 -0
  193. package/dist/ui/index.mjs +6 -0
  194. package/dist/ui/metadata.cjs +106 -0
  195. package/dist/ui/metadata.cjs.map +1 -0
  196. package/dist/ui/metadata.d.cts +35 -0
  197. package/dist/ui/metadata.d.cts.map +1 -0
  198. package/dist/ui/metadata.d.mts +35 -0
  199. package/dist/ui/metadata.d.mts.map +1 -0
  200. package/dist/ui/metadata.mjs +100 -0
  201. package/dist/ui/metadata.mjs.map +1 -0
  202. package/dist/ui/router.cjs +56 -0
  203. package/dist/ui/router.cjs.map +1 -0
  204. package/dist/ui/router.d.cts +11 -0
  205. package/dist/ui/router.d.cts.map +1 -0
  206. package/dist/ui/router.d.mts +11 -0
  207. package/dist/ui/router.d.mts.map +1 -0
  208. package/dist/ui/router.mjs +51 -0
  209. package/dist/ui/router.mjs.map +1 -0
  210. package/dist/ui/runtime.cjs +65 -0
  211. package/dist/ui/runtime.cjs.map +1 -0
  212. package/dist/ui/runtime.d.cts +29 -0
  213. package/dist/ui/runtime.d.cts.map +1 -0
  214. package/dist/ui/runtime.d.mts +29 -0
  215. package/dist/ui/runtime.d.mts.map +1 -0
  216. package/dist/ui/runtime.mjs +53 -0
  217. package/dist/ui/runtime.mjs.map +1 -0
  218. package/dist/ui/types.cjs +0 -0
  219. package/dist/ui/types.d.cts +52 -0
  220. package/dist/ui/types.d.cts.map +1 -0
  221. package/dist/ui/types.d.mts +52 -0
  222. package/dist/ui/types.d.mts.map +1 -0
  223. package/dist/ui/types.mjs +1 -0
  224. package/dist/utils/banner.cjs +24 -0
  225. package/dist/utils/banner.cjs.map +1 -0
  226. package/dist/utils/banner.mjs +23 -0
  227. package/dist/utils/banner.mjs.map +1 -0
  228. package/dist/utils/linkify.cjs +15 -0
  229. package/dist/utils/linkify.cjs.map +1 -0
  230. package/dist/utils/linkify.mjs +14 -0
  231. package/dist/utils/linkify.mjs.map +1 -0
  232. package/dist/utils/run.cjs +40 -0
  233. package/dist/utils/run.cjs.map +1 -0
  234. package/dist/utils/run.mjs +39 -0
  235. package/dist/utils/run.mjs.map +1 -0
  236. package/dist/utils/theme.cjs +44 -0
  237. package/dist/utils/theme.cjs.map +1 -0
  238. package/dist/utils/theme.mjs +37 -0
  239. package/dist/utils/theme.mjs.map +1 -0
  240. package/package.json +269 -80
  241. package/src/api-contract.ts +309 -0
  242. package/src/api.ts +181 -0
  243. package/src/app.ts +346 -0
  244. package/src/cli/catalog.ts +49 -0
  245. package/src/cli/help.ts +13 -0
  246. package/src/cli/init.ts +415 -0
  247. package/src/cli/parse.ts +130 -0
  248. package/src/cli/prompts.ts +64 -0
  249. package/src/cli.ts +203 -1507
  250. package/src/components/dev-view.tsx +104 -41
  251. package/src/components/streaming-view.ts +89 -22
  252. package/src/config.ts +462 -532
  253. package/src/contract.meta.ts +96 -0
  254. package/src/contract.ts +164 -561
  255. package/src/dev-logs.ts +85 -0
  256. package/src/dev-session.ts +318 -0
  257. package/src/fastkv.ts +153 -0
  258. package/src/federation.server.ts +43 -0
  259. package/src/host.ts +526 -0
  260. package/src/index.ts +6 -3
  261. package/src/integrity.ts +54 -0
  262. package/src/mf.ts +105 -0
  263. package/src/near-cli.ts +284 -0
  264. package/src/network.ts +3 -0
  265. package/src/orchestrator.ts +648 -0
  266. package/src/plugin.ts +1116 -2303
  267. package/src/process-registry.ts +154 -0
  268. package/src/scripts/sync-api-contract.ts +24 -0
  269. package/src/sdk.ts +14 -0
  270. package/src/shared.ts +206 -0
  271. package/src/types.ts +152 -206
  272. package/src/ui/head.ts +34 -27
  273. package/src/ui/index.ts +3 -3
  274. package/src/ui/metadata.ts +95 -0
  275. package/src/ui/router.ts +22 -6
  276. package/src/ui/runtime.ts +55 -6
  277. package/src/ui/types.ts +24 -11
  278. package/src/utils/banner.ts +10 -6
  279. package/src/utils/run.ts +26 -27
  280. package/src/utils/theme.ts +3 -66
  281. package/src/components/monitor-view.tsx +0 -475
  282. package/src/components/status-view.tsx +0 -173
  283. package/src/lib/env.ts +0 -109
  284. package/src/lib/near-cli.ts +0 -289
  285. package/src/lib/nova.ts +0 -266
  286. package/src/lib/orchestrator.ts +0 -276
  287. package/src/lib/process-registry.ts +0 -166
  288. package/src/lib/process.ts +0 -549
  289. package/src/lib/resource-monitor/assertions.ts +0 -234
  290. package/src/lib/resource-monitor/command.ts +0 -283
  291. package/src/lib/resource-monitor/diff.ts +0 -157
  292. package/src/lib/resource-monitor/errors.ts +0 -127
  293. package/src/lib/resource-monitor/index.ts +0 -305
  294. package/src/lib/resource-monitor/platform/darwin.ts +0 -306
  295. package/src/lib/resource-monitor/platform/index.ts +0 -35
  296. package/src/lib/resource-monitor/platform/linux.ts +0 -332
  297. package/src/lib/resource-monitor/platform/windows.ts +0 -298
  298. package/src/lib/resource-monitor/snapshot.ts +0 -217
  299. package/src/lib/resource-monitor/types.ts +0 -74
  300. package/src/lib/session-recorder/errors.ts +0 -102
  301. package/src/lib/session-recorder/flows/login.ts +0 -210
  302. package/src/lib/session-recorder/index.ts +0 -361
  303. package/src/lib/session-recorder/playwright.ts +0 -257
  304. package/src/lib/session-recorder/report.ts +0 -353
  305. package/src/lib/session-recorder/server.ts +0 -267
  306. package/src/lib/session-recorder/types.ts +0 -115
  307. package/src/lib/sync.ts +0 -1
  308. 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";