sweetlink 0.2.0 → 0.2.1

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 (229) hide show
  1. package/CHANGELOG.md +6 -2
  2. package/LICENSE +1 -1
  3. package/README.md +6 -6
  4. package/dist/daemon/src/codename.d.ts.map +1 -1
  5. package/dist/daemon/src/codename.js +11 -11
  6. package/dist/daemon/src/codename.js.map +1 -1
  7. package/dist/daemon/src/index.d.ts +1 -1
  8. package/dist/daemon/src/index.js +131 -122
  9. package/dist/daemon/src/index.js.map +1 -1
  10. package/dist/shared/src/env.d.ts.map +1 -1
  11. package/dist/shared/src/env.js +12 -12
  12. package/dist/shared/src/env.js.map +1 -1
  13. package/dist/shared/src/index.d.ts +30 -30
  14. package/dist/shared/src/index.d.ts.map +1 -1
  15. package/dist/shared/src/index.js +17 -17
  16. package/dist/shared/src/index.js.map +1 -1
  17. package/dist/shared/src/node.d.ts +1 -1
  18. package/dist/shared/src/node.d.ts.map +1 -1
  19. package/dist/shared/src/node.js +18 -18
  20. package/dist/shared/src/node.js.map +1 -1
  21. package/dist/src/codex.d.ts +1 -1
  22. package/dist/src/codex.js +19 -19
  23. package/dist/src/codex.js.map +1 -1
  24. package/dist/src/commands/click.d.ts +1 -1
  25. package/dist/src/commands/click.d.ts.map +1 -1
  26. package/dist/src/commands/click.js +32 -24
  27. package/dist/src/commands/click.js.map +1 -1
  28. package/dist/src/commands/run-js.d.ts +1 -1
  29. package/dist/src/commands/run-js.d.ts.map +1 -1
  30. package/dist/src/commands/run-js.js +10 -10
  31. package/dist/src/commands/run-js.js.map +1 -1
  32. package/dist/src/commands/trust-ca.d.ts +1 -1
  33. package/dist/src/commands/trust-ca.js +15 -15
  34. package/dist/src/core/config-file.d.ts.map +1 -1
  35. package/dist/src/core/config-file.js +49 -41
  36. package/dist/src/core/config-file.js.map +1 -1
  37. package/dist/src/core/config.d.ts +2 -2
  38. package/dist/src/core/config.d.ts.map +1 -1
  39. package/dist/src/core/config.js +22 -18
  40. package/dist/src/core/config.js.map +1 -1
  41. package/dist/src/core/dev-bootstrap.d.ts +1 -1
  42. package/dist/src/core/dev-bootstrap.d.ts.map +1 -1
  43. package/dist/src/core/dev-bootstrap.js +12 -12
  44. package/dist/src/core/dev-bootstrap.js.map +1 -1
  45. package/dist/src/core/env.d.ts +1 -1
  46. package/dist/src/core/env.d.ts.map +1 -1
  47. package/dist/src/core/env.js +3 -3
  48. package/dist/src/core/env.js.map +1 -1
  49. package/dist/src/devtools-registry.d.ts.map +1 -1
  50. package/dist/src/devtools-registry.js +48 -46
  51. package/dist/src/devtools-registry.js.map +1 -1
  52. package/dist/src/env.d.ts +1 -1
  53. package/dist/src/env.js +1 -1
  54. package/dist/src/http.d.ts.map +1 -1
  55. package/dist/src/http.js +7 -6
  56. package/dist/src/http.js.map +1 -1
  57. package/dist/src/index.d.ts +7 -7
  58. package/dist/src/index.d.ts.map +1 -1
  59. package/dist/src/index.js +399 -367
  60. package/dist/src/index.js.map +1 -1
  61. package/dist/src/runtime/browser/client.d.ts +3 -3
  62. package/dist/src/runtime/browser/client.d.ts.map +1 -1
  63. package/dist/src/runtime/browser/client.js +79 -72
  64. package/dist/src/runtime/browser/client.js.map +1 -1
  65. package/dist/src/runtime/browser/commands/index.d.ts +2 -2
  66. package/dist/src/runtime/browser/commands/index.js +17 -17
  67. package/dist/src/runtime/browser/commands/index.js.map +1 -1
  68. package/dist/src/runtime/browser/dom-to-image-loader.d.ts.map +1 -1
  69. package/dist/src/runtime/browser/dom-to-image-loader.js +7 -7
  70. package/dist/src/runtime/browser/dom-to-image-loader.js.map +1 -1
  71. package/dist/src/runtime/browser/index.d.ts +3 -3
  72. package/dist/src/runtime/browser/index.js +2 -2
  73. package/dist/src/runtime/browser/module-loader.js +2 -2
  74. package/dist/src/runtime/browser/screenshot/hooks.d.ts +5 -5
  75. package/dist/src/runtime/browser/screenshot/hooks.d.ts.map +1 -1
  76. package/dist/src/runtime/browser/screenshot/hooks.js +32 -29
  77. package/dist/src/runtime/browser/screenshot/hooks.js.map +1 -1
  78. package/dist/src/runtime/browser/screenshot/index.d.ts +3 -3
  79. package/dist/src/runtime/browser/screenshot/index.d.ts.map +1 -1
  80. package/dist/src/runtime/browser/screenshot/index.js +17 -15
  81. package/dist/src/runtime/browser/screenshot/index.js.map +1 -1
  82. package/dist/src/runtime/browser/screenshot/renderers/dom-to-image.d.ts +1 -1
  83. package/dist/src/runtime/browser/screenshot/renderers/dom-to-image.js +13 -13
  84. package/dist/src/runtime/browser/screenshot/renderers/dom-to-image.js.map +1 -1
  85. package/dist/src/runtime/browser/screenshot/renderers/html2canvas.d.ts +1 -1
  86. package/dist/src/runtime/browser/screenshot/renderers/html2canvas.d.ts.map +1 -1
  87. package/dist/src/runtime/browser/screenshot/renderers/html2canvas.js +24 -24
  88. package/dist/src/runtime/browser/screenshot/renderers/html2canvas.js.map +1 -1
  89. package/dist/src/runtime/browser/screenshot/targets.d.ts +2 -2
  90. package/dist/src/runtime/browser/screenshot/targets.js +9 -9
  91. package/dist/src/runtime/browser/screenshot/utils.d.ts +1 -1
  92. package/dist/src/runtime/browser/screenshot/utils.d.ts.map +1 -1
  93. package/dist/src/runtime/browser/screenshot/utils.js +73 -71
  94. package/dist/src/runtime/browser/screenshot/utils.js.map +1 -1
  95. package/dist/src/runtime/browser/selector-discovery.d.ts +1 -1
  96. package/dist/src/runtime/browser/selector-discovery.d.ts.map +1 -1
  97. package/dist/src/runtime/browser/selector-discovery.js +24 -22
  98. package/dist/src/runtime/browser/selector-discovery.js.map +1 -1
  99. package/dist/src/runtime/browser/storage/session-storage.d.ts +1 -1
  100. package/dist/src/runtime/browser/storage/session-storage.d.ts.map +1 -1
  101. package/dist/src/runtime/browser/storage/session-storage.js +12 -10
  102. package/dist/src/runtime/browser/storage/session-storage.js.map +1 -1
  103. package/dist/src/runtime/browser/types.d.ts +7 -7
  104. package/dist/src/runtime/browser/types.js +1 -1
  105. package/dist/src/runtime/browser/utils/console.d.ts +1 -1
  106. package/dist/src/runtime/browser/utils/console.js +16 -16
  107. package/dist/src/runtime/browser/utils/console.js.map +1 -1
  108. package/dist/src/runtime/browser/utils/environment.js +2 -2
  109. package/dist/src/runtime/browser/utils/errors.d.ts.map +1 -1
  110. package/dist/src/runtime/browser/utils/errors.js +11 -11
  111. package/dist/src/runtime/browser/utils/number.d.ts.map +1 -1
  112. package/dist/src/runtime/browser/utils/number.js.map +1 -1
  113. package/dist/src/runtime/browser/utils/object.d.ts.map +1 -1
  114. package/dist/src/runtime/browser/utils/object.js +2 -2
  115. package/dist/src/runtime/browser/utils/object.js.map +1 -1
  116. package/dist/src/runtime/browser/utils/sanitize.js +2 -2
  117. package/dist/src/runtime/browser/utils/time.d.ts.map +1 -1
  118. package/dist/src/runtime/browser/utils/time.js +1 -1
  119. package/dist/src/runtime/chrome/cookies.d.ts +4 -4
  120. package/dist/src/runtime/chrome/cookies.d.ts.map +1 -1
  121. package/dist/src/runtime/chrome/cookies.js +31 -31
  122. package/dist/src/runtime/chrome/cookies.js.map +1 -1
  123. package/dist/src/runtime/chrome/deep-link.d.ts +1 -1
  124. package/dist/src/runtime/chrome/deep-link.d.ts.map +1 -1
  125. package/dist/src/runtime/chrome/deep-link.js +46 -36
  126. package/dist/src/runtime/chrome/deep-link.js.map +1 -1
  127. package/dist/src/runtime/chrome/diagnostics.d.ts.map +1 -1
  128. package/dist/src/runtime/chrome/diagnostics.js +13 -11
  129. package/dist/src/runtime/chrome/diagnostics.js.map +1 -1
  130. package/dist/src/runtime/chrome/focus.d.ts.map +1 -1
  131. package/dist/src/runtime/chrome/focus.js +5 -5
  132. package/dist/src/runtime/chrome/focus.js.map +1 -1
  133. package/dist/src/runtime/chrome/launch.d.ts.map +1 -1
  134. package/dist/src/runtime/chrome/launch.js +30 -30
  135. package/dist/src/runtime/chrome/launch.js.map +1 -1
  136. package/dist/src/runtime/chrome/puppeteer.d.ts +2 -2
  137. package/dist/src/runtime/chrome/puppeteer.d.ts.map +1 -1
  138. package/dist/src/runtime/chrome/puppeteer.js +16 -11
  139. package/dist/src/runtime/chrome/puppeteer.js.map +1 -1
  140. package/dist/src/runtime/chrome/reuse.d.ts.map +1 -1
  141. package/dist/src/runtime/chrome/reuse.js +38 -35
  142. package/dist/src/runtime/chrome/reuse.js.map +1 -1
  143. package/dist/src/runtime/chrome/session.d.ts +1 -1
  144. package/dist/src/runtime/chrome/session.d.ts.map +1 -1
  145. package/dist/src/runtime/chrome/session.js +12 -10
  146. package/dist/src/runtime/chrome/session.js.map +1 -1
  147. package/dist/src/runtime/chrome.d.ts +8 -8
  148. package/dist/src/runtime/chrome.js +8 -8
  149. package/dist/src/runtime/cookies.d.ts +1 -16
  150. package/dist/src/runtime/cookies.d.ts.map +1 -1
  151. package/dist/src/runtime/cookies.js +175 -286
  152. package/dist/src/runtime/cookies.js.map +1 -1
  153. package/dist/src/runtime/devstack.d.ts +1 -1
  154. package/dist/src/runtime/devstack.d.ts.map +1 -1
  155. package/dist/src/runtime/devstack.js +31 -28
  156. package/dist/src/runtime/devstack.js.map +1 -1
  157. package/dist/src/runtime/devtools/background.js +22 -22
  158. package/dist/src/runtime/devtools/cdp.d.ts +3 -3
  159. package/dist/src/runtime/devtools/cdp.d.ts.map +1 -1
  160. package/dist/src/runtime/devtools/cdp.js +59 -55
  161. package/dist/src/runtime/devtools/cdp.js.map +1 -1
  162. package/dist/src/runtime/devtools/config.d.ts.map +1 -1
  163. package/dist/src/runtime/devtools/config.js +15 -15
  164. package/dist/src/runtime/devtools/config.js.map +1 -1
  165. package/dist/src/runtime/devtools/constants.d.ts.map +1 -1
  166. package/dist/src/runtime/devtools/constants.js +18 -10
  167. package/dist/src/runtime/devtools/constants.js.map +1 -1
  168. package/dist/src/runtime/devtools/diagnostics.d.ts +4 -4
  169. package/dist/src/runtime/devtools/diagnostics.d.ts.map +1 -1
  170. package/dist/src/runtime/devtools/diagnostics.js +40 -38
  171. package/dist/src/runtime/devtools/diagnostics.js.map +1 -1
  172. package/dist/src/runtime/devtools/oauth.d.ts +1 -1
  173. package/dist/src/runtime/devtools/oauth.d.ts.map +1 -1
  174. package/dist/src/runtime/devtools/oauth.js +35 -28
  175. package/dist/src/runtime/devtools/oauth.js.map +1 -1
  176. package/dist/src/runtime/devtools/types.d.ts +3 -3
  177. package/dist/src/runtime/devtools/types.d.ts.map +1 -1
  178. package/dist/src/runtime/devtools.d.ts +7 -7
  179. package/dist/src/runtime/devtools.js +7 -7
  180. package/dist/src/runtime/next-devtools.d.ts.map +1 -1
  181. package/dist/src/runtime/next-devtools.js +12 -12
  182. package/dist/src/runtime/next-devtools.js.map +1 -1
  183. package/dist/src/runtime/screenshot.d.ts +9 -9
  184. package/dist/src/runtime/screenshot.d.ts.map +1 -1
  185. package/dist/src/runtime/screenshot.js +65 -46
  186. package/dist/src/runtime/screenshot.js.map +1 -1
  187. package/dist/src/runtime/scripts.d.ts +1 -1
  188. package/dist/src/runtime/scripts.d.ts.map +1 -1
  189. package/dist/src/runtime/scripts.js +28 -28
  190. package/dist/src/runtime/scripts.js.map +1 -1
  191. package/dist/src/runtime/session.d.ts +6 -6
  192. package/dist/src/runtime/session.d.ts.map +1 -1
  193. package/dist/src/runtime/session.js +35 -35
  194. package/dist/src/runtime/session.js.map +1 -1
  195. package/dist/src/runtime/smoke.d.ts +3 -3
  196. package/dist/src/runtime/smoke.d.ts.map +1 -1
  197. package/dist/src/runtime/smoke.js +85 -79
  198. package/dist/src/runtime/smoke.js.map +1 -1
  199. package/dist/src/runtime/url.d.ts +2 -2
  200. package/dist/src/runtime/url.d.ts.map +1 -1
  201. package/dist/src/runtime/url.js +20 -20
  202. package/dist/src/runtime/url.js.map +1 -1
  203. package/dist/src/screenshot-hooks.d.ts +1 -1
  204. package/dist/src/screenshot-hooks.d.ts.map +1 -1
  205. package/dist/src/screenshot-hooks.js +12 -12
  206. package/dist/src/screenshot-hooks.js.map +1 -1
  207. package/dist/src/shared/env.d.ts.map +1 -1
  208. package/dist/src/shared/env.js +11 -11
  209. package/dist/src/shared/env.js.map +1 -1
  210. package/dist/src/shared/index.d.ts +30 -30
  211. package/dist/src/shared/index.d.ts.map +1 -1
  212. package/dist/src/shared/index.js +17 -17
  213. package/dist/src/shared/index.js.map +1 -1
  214. package/dist/src/shared/node.d.ts +1 -1
  215. package/dist/src/shared/node.d.ts.map +1 -1
  216. package/dist/src/shared/node.js +18 -18
  217. package/dist/src/shared/node.js.map +1 -1
  218. package/dist/src/token.d.ts +1 -1
  219. package/dist/src/token.d.ts.map +1 -1
  220. package/dist/src/token.js +16 -16
  221. package/dist/src/token.js.map +1 -1
  222. package/dist/src/types.d.ts +1 -1
  223. package/dist/src/util/app-label.js +4 -4
  224. package/dist/src/util/errors.d.ts.map +1 -1
  225. package/dist/src/util/errors.js +12 -10
  226. package/dist/src/util/errors.js.map +1 -1
  227. package/dist/src/util/path.js +2 -2
  228. package/dist/src/util/regex.js +4 -4
  229. package/package.json +45 -39
@@ -1,23 +1,23 @@
1
1
  #!/usr/bin/env node
2
- import 'dotenv/config';
3
- import { spawnSync } from 'node:child_process';
4
- import { existsSync, mkdirSync, readFileSync } from 'node:fs';
5
- import { createServer as createHttpsServer, request as httpsRequest } from 'node:https';
6
- import os from 'node:os';
7
- import path from 'node:path';
8
- import { URL } from 'node:url';
9
- import { createSweetLinkCommandId, SWEETLINK_DEFAULT_PORT, SWEETLINK_HEARTBEAT_INTERVAL_MS, SWEETLINK_HEARTBEAT_TOLERANCE_MS, SWEETLINK_WS_PATH, verifySweetLinkToken, } from '../../shared/src/index.js';
10
- import { readSweetLinkEnv } from '../../shared/src/env.js';
11
- import { getDefaultSweetLinkSecretPath, resolveSweetLinkSecret, } from '../../shared/src/node.js';
12
- import WebSocket, { WebSocketServer } from 'ws';
13
- import { z } from 'zod';
14
- import { generateSessionCodename } from './codename.js';
2
+ import "dotenv/config";
3
+ import { spawnSync } from "node:child_process";
4
+ import { existsSync, mkdirSync, readFileSync } from "node:fs";
5
+ import { createServer as createHttpsServer, request as httpsRequest } from "node:https";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { URL } from "node:url";
9
+ import { createSweetLinkCommandId, SWEETLINK_DEFAULT_PORT, SWEETLINK_HEARTBEAT_INTERVAL_MS, SWEETLINK_HEARTBEAT_TOLERANCE_MS, SWEETLINK_WS_PATH, verifySweetLinkToken, } from "../../shared/src/index.js";
10
+ import { readSweetLinkEnv } from "../../shared/src/env.js";
11
+ import { getDefaultSweetLinkSecretPath, resolveSweetLinkSecret, } from "../../shared/src/node.js";
12
+ import WebSocket, { WebSocketServer } from "ws";
13
+ import { z } from "zod";
14
+ import { generateSessionCodename } from "./codename.js";
15
15
  const SHUTDOWN_GRACE_MS = 1000;
16
16
  const unrefTimer = (handle) => {
17
17
  const candidate = handle;
18
- if (typeof candidate === 'object' && candidate !== null && 'unref' in candidate) {
18
+ if (typeof candidate === "object" && candidate !== null && "unref" in candidate) {
19
19
  const unref = candidate.unref;
20
- if (typeof unref === 'function') {
20
+ if (typeof unref === "function") {
21
21
  unref.call(candidate);
22
22
  }
23
23
  }
@@ -26,31 +26,31 @@ const toError = (value) => {
26
26
  if (value instanceof Error) {
27
27
  return value;
28
28
  }
29
- if (typeof value === 'string') {
29
+ if (typeof value === "string") {
30
30
  return Object.assign(new Error(value), { cause: value });
31
31
  }
32
- if (value && typeof value === 'object' && 'message' in value) {
32
+ if (value && typeof value === "object" && "message" in value) {
33
33
  const candidate = value.message;
34
- if (typeof candidate === 'string' && candidate.trim().length > 0) {
34
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
35
35
  return Object.assign(new Error(candidate.trim()), { cause: value });
36
36
  }
37
37
  }
38
- return Object.assign(new Error('Unknown error'), { cause: value });
38
+ return Object.assign(new Error("Unknown error"), { cause: value });
39
39
  };
40
40
  const getErrorMessage = (value) => {
41
41
  const error = toError(value);
42
- return error.message || 'Unknown error';
42
+ return error.message || "Unknown error";
43
43
  };
44
- const CERT_DIR = path.join(os.homedir(), '.sweetlink', 'certs');
45
- const CERT_PATH = path.join(CERT_DIR, 'localhost-cert.pem');
46
- const KEY_PATH = path.join(CERT_DIR, 'localhost-key.pem');
44
+ const CERT_DIR = path.join(os.homedir(), ".sweetlink", "certs");
45
+ const CERT_PATH = path.join(CERT_DIR, "localhost-cert.pem");
46
+ const KEY_PATH = path.join(CERT_DIR, "localhost-key.pem");
47
47
  const SOCKET_STATE_LABEL = {
48
- 0: 'connecting',
49
- 1: 'open',
50
- 2: 'closing',
51
- 3: 'closed',
48
+ 0: "connecting",
49
+ 1: "open",
50
+ 2: "closing",
51
+ 3: "closed",
52
52
  };
53
- const SweetLinkConsoleLevelSchema = z.enum(['log', 'info', 'warn', 'error', 'debug']);
53
+ const SweetLinkConsoleLevelSchema = z.enum(["log", "info", "warn", "error", "debug"]);
54
54
  const consoleEventSchema = z
55
55
  .object({
56
56
  id: z.string(),
@@ -59,7 +59,7 @@ const consoleEventSchema = z
59
59
  args: z.array(z.unknown()),
60
60
  })
61
61
  .passthrough();
62
- const commandResultSchema = z.discriminatedUnion('ok', [
62
+ const commandResultSchema = z.discriminatedUnion("ok", [
63
63
  z
64
64
  .object({
65
65
  ok: z.literal(true),
@@ -82,7 +82,7 @@ const commandResultSchema = z.discriminatedUnion('ok', [
82
82
  ]);
83
83
  const registerMessageSchema = z
84
84
  .object({
85
- kind: z.literal('register'),
85
+ kind: z.literal("register"),
86
86
  token: z.string(),
87
87
  sessionId: z.string(),
88
88
  url: z.string(),
@@ -93,25 +93,25 @@ const registerMessageSchema = z
93
93
  .passthrough();
94
94
  const heartbeatMessageSchema = z
95
95
  .object({
96
- kind: z.literal('heartbeat'),
96
+ kind: z.literal("heartbeat"),
97
97
  sessionId: z.string(),
98
98
  })
99
99
  .passthrough();
100
100
  const commandResultMessageSchema = z
101
101
  .object({
102
- kind: z.literal('commandResult'),
102
+ kind: z.literal("commandResult"),
103
103
  sessionId: z.string(),
104
104
  result: commandResultSchema,
105
105
  })
106
106
  .passthrough();
107
107
  const consoleMessageSchema = z
108
108
  .object({
109
- kind: z.literal('console'),
109
+ kind: z.literal("console"),
110
110
  sessionId: z.string(),
111
111
  events: z.array(consoleEventSchema),
112
112
  })
113
113
  .passthrough();
114
- const clientMessageSchema = z.discriminatedUnion('kind', [
114
+ const clientMessageSchema = z.discriminatedUnion("kind", [
115
115
  registerMessageSchema,
116
116
  heartbeatMessageSchema,
117
117
  commandResultMessageSchema,
@@ -119,7 +119,7 @@ const clientMessageSchema = z.discriminatedUnion('kind', [
119
119
  ]);
120
120
  const runScriptCommandSchema = z
121
121
  .object({
122
- type: z.literal('runScript'),
122
+ type: z.literal("runScript"),
123
123
  code: z.string(),
124
124
  timeoutMs: z.number().finite().positive().optional(),
125
125
  captureConsole: z.boolean().optional(),
@@ -127,44 +127,49 @@ const runScriptCommandSchema = z
127
127
  .passthrough();
128
128
  const getDomCommandSchema = z
129
129
  .object({
130
- type: z.literal('getDom'),
130
+ type: z.literal("getDom"),
131
131
  selector: z.string().optional(),
132
132
  includeShadowDom: z.boolean().optional(),
133
133
  })
134
134
  .passthrough();
135
135
  const navigateCommandSchema = z
136
136
  .object({
137
- type: z.literal('navigate'),
137
+ type: z.literal("navigate"),
138
138
  url: z.string(),
139
139
  })
140
140
  .passthrough();
141
141
  const pingCommandSchema = z
142
142
  .object({
143
- type: z.literal('ping'),
143
+ type: z.literal("ping"),
144
144
  })
145
145
  .passthrough();
146
146
  const screenshotCommandSchema = z
147
147
  .object({
148
- type: z.literal('screenshot'),
149
- mode: z.union([z.literal('full'), z.literal('element')]).default('full'),
148
+ type: z.literal("screenshot"),
149
+ mode: z.union([z.literal("full"), z.literal("element")]).default("full"),
150
150
  selector: z.union([z.string(), z.null()]).optional(),
151
151
  quality: z.number().finite().min(0).max(100).optional(),
152
152
  timeoutMs: z.number().finite().positive().optional(),
153
153
  renderer: z
154
- .union([z.literal('auto'), z.literal('puppeteer'), z.literal('html2canvas'), z.literal('html-to-image')])
154
+ .union([
155
+ z.literal("auto"),
156
+ z.literal("puppeteer"),
157
+ z.literal("html2canvas"),
158
+ z.literal("html-to-image"),
159
+ ])
155
160
  .optional(),
156
161
  hooks: z.array(z.unknown()).optional(),
157
162
  })
158
163
  .passthrough();
159
164
  const discoverSelectorsCommandSchema = z
160
165
  .object({
161
- type: z.literal('discoverSelectors'),
166
+ type: z.literal("discoverSelectors"),
162
167
  scopeSelector: z.union([z.string(), z.null()]).optional(),
163
168
  limit: z.number().int().positive().optional(),
164
169
  includeHidden: z.boolean().optional(),
165
170
  })
166
171
  .passthrough();
167
- const commandSchema = z.discriminatedUnion('type', [
172
+ const commandSchema = z.discriminatedUnion("type", [
168
173
  runScriptCommandSchema,
169
174
  getDomCommandSchema,
170
175
  navigateCommandSchema,
@@ -174,33 +179,35 @@ const commandSchema = z.discriminatedUnion('type', [
174
179
  ]);
175
180
  const timeoutOverrideSchema = z.number().finite().positive().optional();
176
181
  const resolveDaemonPort = (value) => {
177
- if (value && typeof value === 'object' && value !== null) {
182
+ if (value && typeof value === "object" && value !== null) {
178
183
  const portCandidate = value.port;
179
- if (typeof portCandidate === 'number' && Number.isFinite(portCandidate) && portCandidate > 0) {
184
+ if (typeof portCandidate === "number" && Number.isFinite(portCandidate) && portCandidate > 0) {
180
185
  return portCandidate;
181
186
  }
182
187
  }
183
188
  return SWEETLINK_DEFAULT_PORT;
184
189
  };
185
190
  const isSecretResolution = (value) => {
186
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
191
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
187
192
  return false;
188
193
  }
189
194
  const candidate = value;
190
- if (typeof candidate.secret !== 'string' || candidate.secret.length === 0) {
195
+ if (typeof candidate.secret !== "string" || candidate.secret.length === 0) {
191
196
  return false;
192
197
  }
193
- if (candidate.source !== 'env' && candidate.source !== 'file' && candidate.source !== 'generated') {
198
+ if (candidate.source !== "env" &&
199
+ candidate.source !== "file" &&
200
+ candidate.source !== "generated") {
194
201
  return false;
195
202
  }
196
- if (candidate.path !== undefined && typeof candidate.path !== 'string') {
203
+ if (candidate.path !== undefined && typeof candidate.path !== "string") {
197
204
  return false;
198
205
  }
199
206
  return true;
200
207
  };
201
208
  const assertSecretResolution = (value) => {
202
209
  if (!isSecretResolution(value)) {
203
- throw new TypeError('SweetLink secret resolution payload is invalid');
210
+ throw new TypeError("SweetLink secret resolution payload is invalid");
204
211
  }
205
212
  return value;
206
213
  };
@@ -213,24 +220,24 @@ async function main() {
213
220
  }
214
221
  const rawSecretResolution = await resolveSweetLinkSecret({ autoCreate: true });
215
222
  const { secret, source, path: secretPath } = assertSecretResolution(rawSecretResolution);
216
- log(`SweetLink secret source: ${source}${secretPath ? ` (${secretPath})` : ''}`);
223
+ log(`SweetLink secret source: ${source}${secretPath ? ` (${secretPath})` : ""}`);
217
224
  ensureCertificates();
218
225
  const { cert, key } = loadCertificates();
219
226
  const state = new SweetLinkState(secret);
220
227
  const server = createHttpsServer({ key, cert }, (req, res) => {
221
228
  handleHttpRequest(state, req, res).catch((error) => {
222
- console.warn('SweetLink daemon request handler failed:', getErrorMessage(error));
229
+ console.warn("SweetLink daemon request handler failed:", getErrorMessage(error));
223
230
  });
224
231
  });
225
232
  const wsServer = new WebSocketServer({ server, path: SWEETLINK_WS_PATH });
226
- wsServer.on('connection', (socket) => state.handleSocket(socket));
227
- server.listen(daemonPort, '127.0.0.1', () => {
233
+ wsServer.on("connection", (socket) => state.handleSocket(socket));
234
+ server.listen(daemonPort, "127.0.0.1", () => {
228
235
  log(`SweetLink daemon listening on https://localhost:${daemonPort}`);
229
236
  log(`WebSocket endpoint ready at wss://localhost:${daemonPort}${SWEETLINK_WS_PATH}`);
230
- log('Press Ctrl+C to stop.');
237
+ log("Press Ctrl+C to stop.");
231
238
  });
232
- process.on('SIGINT', () => shutdown('SIGINT'));
233
- process.on('SIGTERM', () => shutdown('SIGTERM'));
239
+ process.on("SIGINT", () => shutdown("SIGINT"));
240
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
234
241
  function shutdown(signal) {
235
242
  log(`Received ${signal}, shutting down SweetLink daemon...`);
236
243
  wsServer.close();
@@ -248,18 +255,18 @@ async function main() {
248
255
  async function isDaemonAlreadyRunning(port) {
249
256
  return await new Promise((resolve) => {
250
257
  const request = httpsRequest({
251
- hostname: '127.0.0.1',
258
+ hostname: "127.0.0.1",
252
259
  port,
253
- path: '/healthz',
254
- method: 'GET',
260
+ path: "/healthz",
261
+ method: "GET",
255
262
  rejectUnauthorized: false,
256
263
  timeout: 750,
257
264
  }, (response) => {
258
265
  response.resume();
259
266
  resolve(response.statusCode === 200);
260
267
  });
261
- request.on('error', () => resolve(false));
262
- request.on('timeout', () => {
268
+ request.on("error", () => resolve(false));
269
+ request.on("timeout", () => {
263
270
  request.destroy();
264
271
  resolve(false);
265
272
  });
@@ -275,29 +282,29 @@ class SweetLinkState {
275
282
  unrefTimer(expiryInterval);
276
283
  }
277
284
  verifyCliToken(token) {
278
- return verifySweetLinkToken({ secret: this.#secret, token, expectedScope: 'cli' });
285
+ return verifySweetLinkToken({ secret: this.#secret, token, expectedScope: "cli" });
279
286
  }
280
287
  handleSocket(socket) {
281
288
  let sessionId = null;
282
- socket.on('message', (data) => {
289
+ socket.on("message", (data) => {
283
290
  try {
284
291
  const raw = decodeSocketPayload(data);
285
292
  const parsedMessage = parseClientMessage(JSON.parse(raw));
286
293
  const message = parsedMessage;
287
294
  switch (message.kind) {
288
- case 'register': {
295
+ case "register": {
289
296
  sessionId = this.#handleRegister(socket, message);
290
297
  break;
291
298
  }
292
- case 'heartbeat': {
299
+ case "heartbeat": {
293
300
  this.#touchSession(message.sessionId);
294
301
  break;
295
302
  }
296
- case 'commandResult': {
303
+ case "commandResult": {
297
304
  this.#handleCommandResult(message.sessionId, message.result);
298
305
  break;
299
306
  }
300
- case 'console': {
307
+ case "console": {
301
308
  this.#handleConsoleEvents(message.sessionId, message.events);
302
309
  break;
303
310
  }
@@ -314,10 +321,12 @@ class SweetLinkState {
314
321
  console.warn(`SweetLink socket error: ${errorMessage}`);
315
322
  }
316
323
  });
317
- socket.once('close', (code, reasonBuffer) => {
324
+ socket.once("close", (code, reasonBuffer) => {
318
325
  if (sessionId) {
319
- const reasonText = reasonBuffer?.toString?.('utf8') ?? '';
320
- const closeDetail = reasonText && reasonText.length > 0 ? `socket closed (${code}: ${reasonText})` : `socket closed (${code})`;
326
+ const reasonText = reasonBuffer?.toString?.("utf8") ?? "";
327
+ const closeDetail = reasonText && reasonText.length > 0
328
+ ? `socket closed (${code}: ${reasonText})`
329
+ : `socket closed (${code})`;
321
330
  this.#removeSession(sessionId, closeDetail);
322
331
  }
323
332
  });
@@ -328,7 +337,7 @@ class SweetLinkState {
328
337
  const consoleEventsBuffered = entry.consoleBuffer.length;
329
338
  let consoleErrorsBuffered = 0;
330
339
  for (const event of entry.consoleBuffer) {
331
- if (event.level === 'error') {
340
+ if (event.level === "error") {
332
341
  consoleErrorsBuffered += 1;
333
342
  }
334
343
  }
@@ -354,15 +363,15 @@ class SweetLinkState {
354
363
  sendCommand(sessionId, rawCommand, timeoutMs = 15_000) {
355
364
  const session = this.#sessions.get(sessionId);
356
365
  if (!session) {
357
- throw new Error('Session not found or offline');
366
+ throw new Error("Session not found or offline");
358
367
  }
359
368
  if (session.socket.readyState !== WebSocket.OPEN) {
360
- throw new Error('Session socket is not open');
369
+ throw new Error("Session socket is not open");
361
370
  }
362
371
  const commandId = createSweetLinkCommandId();
363
372
  const command = { ...rawCommand, id: commandId };
364
373
  const payload = {
365
- kind: 'command',
374
+ kind: "command",
366
375
  sessionId: session.metadata.sessionId,
367
376
  command,
368
377
  };
@@ -370,7 +379,7 @@ class SweetLinkState {
370
379
  return new Promise((resolve, reject) => {
371
380
  const timeout = setTimeout(() => {
372
381
  session.pending.delete(commandId);
373
- reject(new Error('Command timed out'));
382
+ reject(new Error("Command timed out"));
374
383
  }, timeoutMs);
375
384
  session.pending.set(commandId, {
376
385
  commandId,
@@ -400,9 +409,9 @@ class SweetLinkState {
400
409
  #handleRegister(socket, message) {
401
410
  const token = message.token;
402
411
  const sessionId = message.sessionId;
403
- const payload = verifySweetLinkToken({ secret: this.#secret, token, expectedScope: 'session' });
412
+ const payload = verifySweetLinkToken({ secret: this.#secret, token, expectedScope: "session" });
404
413
  if (!payload.sessionId || payload.sessionId !== sessionId) {
405
- throw new Error('Session token mismatch');
414
+ throw new Error("Session token mismatch");
406
415
  }
407
416
  const metadata = {
408
417
  sessionId,
@@ -429,7 +438,7 @@ class SweetLinkState {
429
438
  this.#sessions.set(sessionId, entry);
430
439
  try {
431
440
  const metadataMessage = {
432
- kind: 'metadata',
441
+ kind: "metadata",
433
442
  sessionId,
434
443
  codename: metadata.codename,
435
444
  };
@@ -476,7 +485,7 @@ class SweetLinkState {
476
485
  }
477
486
  }
478
487
  #socketStateToString(readyState) {
479
- return SOCKET_STATE_LABEL[readyState] ?? 'unknown';
488
+ return SOCKET_STATE_LABEL[readyState] ?? "unknown";
480
489
  }
481
490
  #removeSession(sessionId, reason) {
482
491
  const session = this.#sessions.get(sessionId);
@@ -505,24 +514,24 @@ async function handleHttpRequest(state, req, res) {
505
514
  const basePort = daemonPort;
506
515
  const requestUrl = req.url ? new URL(req.url, `https://localhost:${basePort}`) : null;
507
516
  if (!requestUrl) {
508
- respondJson(res, 400, { error: 'Invalid request URL' });
517
+ respondJson(res, 400, { error: "Invalid request URL" });
509
518
  return;
510
519
  }
511
- if (req.method === 'OPTIONS') {
520
+ if (req.method === "OPTIONS") {
512
521
  respondCors(res);
513
522
  return;
514
523
  }
515
- if (requestUrl.pathname === '/healthz') {
516
- respondJson(res, 200, { status: 'ok' });
524
+ if (requestUrl.pathname === "/healthz") {
525
+ respondJson(res, 200, { status: "ok" });
517
526
  return;
518
527
  }
519
528
  const authorization = req.headers.authorization;
520
- if (!authorization?.startsWith('Bearer ')) {
521
- respondJson(res, 401, { error: 'Missing SweetLink token' });
529
+ if (!authorization?.startsWith("Bearer ")) {
530
+ respondJson(res, 401, { error: "Missing SweetLink token" });
522
531
  return;
523
532
  }
524
533
  try {
525
- const token = authorization.slice('Bearer '.length).trim();
534
+ const token = authorization.slice("Bearer ".length).trim();
526
535
  state.verifyCliToken(token);
527
536
  }
528
537
  catch (error) {
@@ -530,29 +539,29 @@ async function handleHttpRequest(state, req, res) {
530
539
  respondJson(res, 401, { error: message });
531
540
  return;
532
541
  }
533
- if (req.method === 'GET' && requestUrl.pathname === '/sessions') {
542
+ if (req.method === "GET" && requestUrl.pathname === "/sessions") {
534
543
  const sessions = state.listSessions();
535
544
  respondJson(res, 200, { sessions });
536
545
  return;
537
546
  }
538
- if (req.method === 'GET' &&
539
- requestUrl.pathname.startsWith('/sessions/') &&
540
- requestUrl.pathname.endsWith('/console')) {
541
- const sessionId = requestUrl.pathname.split('/')[2];
547
+ if (req.method === "GET" &&
548
+ requestUrl.pathname.startsWith("/sessions/") &&
549
+ requestUrl.pathname.endsWith("/console")) {
550
+ const sessionId = requestUrl.pathname.split("/")[2];
542
551
  if (sessionId == null) {
543
- respondJson(res, 400, { error: 'Session id missing' });
552
+ respondJson(res, 400, { error: "Session id missing" });
544
553
  return;
545
554
  }
546
555
  const events = state.getSessionConsole(sessionId);
547
556
  respondJson(res, 200, { sessionId, events });
548
557
  return;
549
558
  }
550
- if (req.method === 'POST' &&
551
- requestUrl.pathname.startsWith('/sessions/') &&
552
- requestUrl.pathname.endsWith('/command')) {
553
- const sessionId = requestUrl.pathname.split('/')[2];
559
+ if (req.method === "POST" &&
560
+ requestUrl.pathname.startsWith("/sessions/") &&
561
+ requestUrl.pathname.endsWith("/command")) {
562
+ const sessionId = requestUrl.pathname.split("/")[2];
554
563
  if (sessionId == null) {
555
- respondJson(res, 400, { error: 'Session id missing' });
564
+ respondJson(res, 400, { error: "Session id missing" });
556
565
  return;
557
566
  }
558
567
  try {
@@ -567,18 +576,18 @@ async function handleHttpRequest(state, req, res) {
567
576
  }
568
577
  return;
569
578
  }
570
- respondJson(res, 404, { error: 'Not Found' });
579
+ respondJson(res, 404, { error: "Not Found" });
571
580
  }
572
581
  async function readJson(req) {
573
582
  const chunks = [];
574
583
  for await (const chunk of req) {
575
- const bufferChunk = typeof chunk === 'string' ? Buffer.from(chunk, 'utf8') : chunk;
584
+ const bufferChunk = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
576
585
  chunks.push(bufferChunk);
577
586
  }
578
587
  if (chunks.length === 0) {
579
588
  return {};
580
589
  }
581
- const text = Buffer.concat(chunks).toString('utf8');
590
+ const text = Buffer.concat(chunks).toString("utf8");
582
591
  if (!text) {
583
592
  return {};
584
593
  }
@@ -587,38 +596,38 @@ async function readJson(req) {
587
596
  function respondJson(res, status, body) {
588
597
  const payload = JSON.stringify(body ?? {}, null, 2);
589
598
  res.statusCode = status;
590
- res.setHeader('Content-Type', 'application/json');
591
- res.setHeader('Access-Control-Allow-Origin', '*');
592
- res.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
593
- res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
599
+ res.setHeader("Content-Type", "application/json");
600
+ res.setHeader("Access-Control-Allow-Origin", "*");
601
+ res.setHeader("Access-Control-Allow-Headers", "authorization, content-type");
602
+ res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
594
603
  res.end(payload);
595
604
  }
596
605
  function respondCors(res) {
597
606
  res.statusCode = 204;
598
- res.setHeader('Access-Control-Allow-Origin', '*');
599
- res.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
600
- res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
607
+ res.setHeader("Access-Control-Allow-Origin", "*");
608
+ res.setHeader("Access-Control-Allow-Headers", "authorization, content-type");
609
+ res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
601
610
  res.end();
602
611
  }
603
612
  function decodeSocketPayload(data) {
604
- if (typeof data === 'string') {
613
+ if (typeof data === "string") {
605
614
  return data;
606
615
  }
607
616
  if (Buffer.isBuffer(data)) {
608
- return data.toString('utf8');
617
+ return data.toString("utf8");
609
618
  }
610
619
  if (Array.isArray(data)) {
611
620
  const buffers = data.map((chunk) => (Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
612
- return Buffer.concat(buffers).toString('utf8');
621
+ return Buffer.concat(buffers).toString("utf8");
613
622
  }
614
623
  if (ArrayBuffer.isView(data)) {
615
624
  const view = data;
616
- return Buffer.from(view.buffer, view.byteOffset, view.byteLength).toString('utf8');
625
+ return Buffer.from(view.buffer, view.byteOffset, view.byteLength).toString("utf8");
617
626
  }
618
627
  if (data instanceof ArrayBuffer) {
619
- return Buffer.from(data).toString('utf8');
628
+ return Buffer.from(data).toString("utf8");
620
629
  }
621
- return Buffer.from([]).toString('utf8');
630
+ return Buffer.from([]).toString("utf8");
622
631
  }
623
632
  function parseClientMessage(raw) {
624
633
  return clientMessageSchema.parse(raw);
@@ -630,8 +639,8 @@ function parseCommandRequest(raw) {
630
639
  return { command, timeoutMs };
631
640
  }
632
641
  function ensureObject(value) {
633
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
634
- throw new Error('Request body must be a JSON object');
642
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
643
+ throw new Error("Request body must be a JSON object");
635
644
  }
636
645
  return value;
637
646
  }
@@ -639,21 +648,21 @@ function ensureCertificates() {
639
648
  if (existsSync(CERT_PATH) && existsSync(KEY_PATH)) {
640
649
  return;
641
650
  }
642
- log('Generating SweetLink TLS certificates via mkcert...');
651
+ log("Generating SweetLink TLS certificates via mkcert...");
643
652
  mkdirSync(CERT_DIR, { recursive: true });
644
- const mkcertLookup = spawnSync('which', ['mkcert'], { stdio: 'pipe' });
653
+ const mkcertLookup = spawnSync("which", ["mkcert"], { stdio: "pipe" });
645
654
  if (mkcertLookup.status !== 0) {
646
655
  const secretPath = getDefaultSweetLinkSecretPath();
647
656
  throw new Error('mkcert is required but not found. Install via "brew install mkcert nss" and rerun pnpm sweetlink. ' +
648
657
  `Generated SweetLink secret saved at ${secretPath}.`);
649
658
  }
650
- const install = spawnSync('mkcert', ['-install'], { stdio: 'inherit' });
659
+ const install = spawnSync("mkcert", ["-install"], { stdio: "inherit" });
651
660
  if (install.status !== 0) {
652
- throw new Error('Failed to run mkcert -install');
661
+ throw new Error("Failed to run mkcert -install");
653
662
  }
654
- const create = spawnSync('mkcert', ['-cert-file', CERT_PATH, '-key-file', KEY_PATH, 'localhost', '127.0.0.1', '::1'], { stdio: 'inherit' });
663
+ const create = spawnSync("mkcert", ["-cert-file", CERT_PATH, "-key-file", KEY_PATH, "localhost", "127.0.0.1", "::1"], { stdio: "inherit" });
655
664
  if (create.status !== 0) {
656
- throw new Error('Failed to generate mkcert certificates');
665
+ throw new Error("Failed to generate mkcert certificates");
657
666
  }
658
667
  }
659
668
  function loadCertificates() {