autokap 1.0.6 → 1.0.8

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 (347) hide show
  1. package/assets/chrome/ios-statusbar-comparison-reference.jpg +0 -0
  2. package/assets/chrome/ios-statusbar-dark-reference.jpg +0 -0
  3. package/assets/chrome/ios-statusbar-light-reference.jpg +0 -0
  4. package/assets/cursors/macos.svg +4 -0
  5. package/assets/cursors/windows.svg +15 -0
  6. package/assets/devices/ipad-pro-11-m4.json +52 -0
  7. package/assets/devices/iphone-16-pro.json +53 -0
  8. package/assets/devices/macbook-air-13.json +45 -0
  9. package/assets/frames/MacBook Air 13.svg +242 -0
  10. package/assets/frames/Status bar - iPhone.png +0 -0
  11. Menu bar- iPad.png +0 -0
  12. package/assets/frames/iPad Pro M4 11_.png +0 -0
  13. package/assets/frames/iPhone 16 Pro.png +0 -0
  14. package/assets/icons/Cellular Connection.svg +3 -0
  15. package/assets/icons/Union.svg +6 -0
  16. package/assets/icons/Wifi.svg +3 -0
  17. package/assets/icons/battery.svg +5 -0
  18. package/assets/icons/battery_charging.svg +8 -0
  19. package/assets/skill/OPCODE-REFERENCE.md +607 -0
  20. package/assets/skill/README.md +39 -0
  21. package/assets/skill/SKILL.md +453 -468
  22. package/assets/skill/STUDIO-SKILL.md +476 -0
  23. package/assets/skill/references/examples.md +104 -0
  24. package/assets/skill/references/interactive-demo.md +225 -0
  25. package/assets/skill/references/mock-data.md +178 -0
  26. package/dist/abort.d.ts +5 -0
  27. package/dist/abort.js +44 -0
  28. package/dist/action-verifier.d.ts +29 -0
  29. package/dist/action-verifier.js +133 -0
  30. package/dist/agent-action-recovery.d.ts +45 -0
  31. package/dist/agent-action-recovery.js +370 -0
  32. package/dist/agent-message-utils.d.ts +21 -0
  33. package/dist/agent-message-utils.js +77 -0
  34. package/dist/agent-url-utils.d.ts +30 -0
  35. package/dist/agent-url-utils.js +138 -0
  36. package/dist/agent.d.ts +226 -0
  37. package/dist/agent.js +6666 -0
  38. package/dist/ak-tree.d.ts +39 -0
  39. package/dist/ak-tree.js +368 -0
  40. package/dist/alt-text.d.ts +26 -0
  41. package/dist/alt-text.js +55 -0
  42. package/dist/auth-capture.d.ts +17 -0
  43. package/dist/auth-capture.js +164 -0
  44. package/dist/benchmark.d.ts +59 -0
  45. package/dist/benchmark.js +135 -0
  46. package/dist/billing-operation-logging.d.ts +38 -0
  47. package/dist/billing-operation-logging.js +248 -0
  48. package/dist/browser-bar.d.ts +48 -0
  49. package/dist/browser-bar.js +284 -0
  50. package/dist/browser-pool.d.ts +7 -0
  51. package/dist/browser-pool.js +15 -5
  52. package/dist/browser-utils.d.ts +31 -0
  53. package/dist/browser-utils.js +97 -0
  54. package/dist/browser.d.ts +76 -1
  55. package/dist/browser.js +1657 -39
  56. package/dist/capture-alt-text.d.ts +12 -0
  57. package/dist/capture-alt-text.js +52 -0
  58. package/dist/capture-encryption.d.ts +10 -0
  59. package/dist/capture-encryption.js +41 -0
  60. package/dist/capture-language-preflight.d.ts +41 -0
  61. package/dist/capture-language-preflight.js +300 -0
  62. package/dist/capture-llm-page-identity.d.ts +15 -0
  63. package/dist/capture-llm-page-identity.js +128 -0
  64. package/dist/capture-model-resolution.d.ts +9 -0
  65. package/dist/capture-model-resolution.js +21 -0
  66. package/dist/capture-page-identity.d.ts +7 -0
  67. package/dist/capture-page-identity.js +352 -0
  68. package/dist/capture-preset-credentials.d.ts +62 -0
  69. package/dist/capture-preset-credentials.js +184 -0
  70. package/dist/capture-request-plan.d.ts +58 -0
  71. package/dist/capture-request-plan.js +264 -0
  72. package/dist/capture-run-optimizer.d.ts +139 -0
  73. package/dist/capture-run-optimizer.js +863 -0
  74. package/dist/capture-selector-memory.d.ts +31 -0
  75. package/dist/capture-selector-memory.js +345 -0
  76. package/dist/capture-session-profile-encryption.d.ts +2 -0
  77. package/dist/capture-session-profile-encryption.js +22 -0
  78. package/dist/capture-step-timeout.d.ts +10 -0
  79. package/dist/capture-step-timeout.js +30 -0
  80. package/dist/capture-strategy.d.ts +36 -0
  81. package/dist/capture-strategy.js +95 -0
  82. package/dist/capture-studio-sync.d.ts +23 -0
  83. package/dist/capture-studio-sync.js +172 -0
  84. package/dist/capture-surface-contract.d.ts +36 -0
  85. package/dist/capture-surface-contract.js +299 -0
  86. package/dist/capture-transition-engine.d.ts +28 -0
  87. package/dist/capture-transition-engine.js +292 -0
  88. package/dist/capture-variant-state.d.ts +56 -0
  89. package/dist/capture-variant-state.js +182 -0
  90. package/dist/capture-verification.d.ts +35 -0
  91. package/dist/capture-verification.js +95 -0
  92. package/dist/capture-viewport-lock.d.ts +48 -0
  93. package/dist/capture-viewport-lock.js +74 -0
  94. package/dist/circuit-breaker.d.ts +42 -0
  95. package/dist/circuit-breaker.js +119 -0
  96. package/dist/cli-config.d.ts +8 -1
  97. package/dist/cli-config.js +62 -6
  98. package/dist/cli-contract.d.ts +15 -0
  99. package/dist/cli-contract.js +167 -0
  100. package/dist/cli-runner-local.d.ts +12 -0
  101. package/dist/cli-runner-local.js +102 -0
  102. package/dist/cli-runner.d.ts +34 -0
  103. package/dist/cli-runner.js +433 -0
  104. package/dist/cli-utils.d.ts +0 -1
  105. package/dist/cli-utils.js +2 -5
  106. package/dist/cli.js +1005 -252
  107. package/dist/clip-orchestrator.d.ts +148 -0
  108. package/dist/clip-orchestrator.js +957 -0
  109. package/dist/clip-postprocess.d.ts +42 -0
  110. package/dist/clip-postprocess.js +201 -0
  111. package/dist/cookie-dismiss.d.ts +2 -0
  112. package/dist/cookie-dismiss.js +48 -13
  113. package/dist/cost-logging.d.ts +35 -0
  114. package/dist/cost-logging.js +242 -0
  115. package/dist/cost-resolution-monitor.d.ts +16 -0
  116. package/dist/cost-resolution-monitor.js +34 -0
  117. package/dist/credential-templates.d.ts +5 -0
  118. package/dist/credential-templates.js +60 -0
  119. package/dist/cursor-overlay-script.d.ts +6 -0
  120. package/dist/cursor-overlay-script.js +169 -0
  121. package/dist/dom-css-purger.d.ts +65 -0
  122. package/dist/dom-css-purger.js +333 -0
  123. package/dist/dom-font-inliner.d.ts +45 -0
  124. package/dist/dom-font-inliner.js +148 -0
  125. package/dist/dom-patch-resolver.d.ts +52 -0
  126. package/dist/dom-patch-resolver.js +242 -0
  127. package/dist/dom-serializer.d.ts +82 -0
  128. package/dist/dom-serializer.js +378 -0
  129. package/dist/element-capture.d.ts +13 -0
  130. package/dist/element-capture.js +522 -0
  131. package/dist/env-validation.d.ts +5 -0
  132. package/dist/env-validation.js +29 -0
  133. package/dist/execution-schema.d.ts +4423 -0
  134. package/dist/execution-schema.js +507 -0
  135. package/dist/execution-types.d.ts +886 -0
  136. package/dist/execution-types.js +65 -0
  137. package/dist/fonts-loader.d.ts +14 -0
  138. package/dist/fonts-loader.js +55 -0
  139. package/dist/hybrid-navigator.d.ts +138 -0
  140. package/dist/hybrid-navigator.js +468 -0
  141. package/dist/index.d.ts +18 -0
  142. package/dist/index.js +17 -0
  143. package/dist/legacy/agent-action-recovery.d.ts +45 -0
  144. package/dist/legacy/agent-action-recovery.js +370 -0
  145. package/dist/legacy/agent-message-utils.d.ts +21 -0
  146. package/dist/legacy/agent-message-utils.js +77 -0
  147. package/dist/legacy/agent-url-utils.d.ts +30 -0
  148. package/dist/legacy/agent-url-utils.js +138 -0
  149. package/dist/legacy/agent.d.ts +226 -0
  150. package/dist/legacy/agent.js +6666 -0
  151. package/dist/legacy/clip-orchestrator.d.ts +148 -0
  152. package/dist/legacy/clip-orchestrator.js +957 -0
  153. package/dist/legacy/credential-templates.d.ts +5 -0
  154. package/dist/legacy/credential-templates.js +60 -0
  155. package/dist/legacy/hybrid-navigator.d.ts +138 -0
  156. package/dist/legacy/hybrid-navigator.js +468 -0
  157. package/dist/legacy/llm-usage.d.ts +17 -0
  158. package/dist/legacy/llm-usage.js +45 -0
  159. package/dist/legacy/prompt-cache.d.ts +10 -0
  160. package/dist/legacy/prompt-cache.js +24 -0
  161. package/dist/legacy/prompts.d.ts +175 -0
  162. package/dist/legacy/prompts.js +1038 -0
  163. package/dist/legacy/tools.d.ts +4 -0
  164. package/dist/legacy/tools.js +216 -0
  165. package/dist/legacy/video-agent.d.ts +143 -0
  166. package/dist/legacy/video-agent.js +4788 -0
  167. package/dist/legacy/video-observation.d.ts +36 -0
  168. package/dist/legacy/video-observation.js +192 -0
  169. package/dist/legacy/video-planner.d.ts +12 -0
  170. package/dist/legacy/video-planner.js +501 -0
  171. package/dist/legacy/video-prompts.d.ts +37 -0
  172. package/dist/legacy/video-prompts.js +569 -0
  173. package/dist/legacy/video-tools.d.ts +3 -0
  174. package/dist/legacy/video-tools.js +59 -0
  175. package/dist/legacy/video-variant-state.d.ts +29 -0
  176. package/dist/legacy/video-variant-state.js +80 -0
  177. package/dist/legacy/vision-model.d.ts +17 -0
  178. package/dist/legacy/vision-model.js +74 -0
  179. package/dist/llm-healer.d.ts +63 -0
  180. package/dist/llm-healer.js +166 -0
  181. package/dist/llm-provider.d.ts +29 -0
  182. package/dist/llm-provider.js +80 -0
  183. package/dist/llm-usage.d.ts +17 -0
  184. package/dist/llm-usage.js +45 -0
  185. package/dist/logger.d.ts +6 -2
  186. package/dist/logger.js +15 -1
  187. package/dist/mockup-html.d.ts +119 -0
  188. package/dist/mockup-html.js +263 -0
  189. package/dist/mockup.d.ts +187 -0
  190. package/dist/mockup.js +869 -0
  191. package/dist/mouse-animation.d.ts +46 -0
  192. package/dist/mouse-animation.js +114 -0
  193. package/dist/opcode-actions.d.ts +42 -0
  194. package/dist/opcode-actions.js +511 -0
  195. package/dist/opcode-runner.d.ts +51 -0
  196. package/dist/opcode-runner.js +770 -0
  197. package/dist/openrouter-client.d.ts +40 -0
  198. package/dist/openrouter-client.js +16 -0
  199. package/dist/overlay-engine.d.ts +24 -0
  200. package/dist/overlay-engine.js +176 -0
  201. package/dist/overlay-utils.d.ts +14 -0
  202. package/dist/overlay-utils.js +13 -0
  203. package/dist/postcondition.d.ts +16 -0
  204. package/dist/postcondition.js +269 -0
  205. package/dist/posthog.d.ts +4 -0
  206. package/dist/posthog.js +26 -0
  207. package/dist/program-patcher.d.ts +25 -0
  208. package/dist/program-patcher.js +44 -0
  209. package/dist/prompt-cache.d.ts +10 -0
  210. package/dist/prompt-cache.js +24 -0
  211. package/dist/prompts.d.ts +175 -0
  212. package/dist/prompts.js +1038 -0
  213. package/dist/provider-config.d.ts +12 -0
  214. package/dist/provider-config.js +15 -0
  215. package/dist/recovery-chain.d.ts +37 -0
  216. package/dist/recovery-chain.js +350 -0
  217. package/dist/remote-browser.d.ts +215 -0
  218. package/dist/remote-browser.js +360 -0
  219. package/dist/safari-browser-bar.d.ts +15 -0
  220. package/dist/safari-browser-bar.js +95 -0
  221. package/dist/safari-toolbar-asset.d.ts +15 -0
  222. package/dist/safari-toolbar-asset.js +12 -0
  223. package/dist/security.d.ts +21 -0
  224. package/dist/security.js +608 -0
  225. package/dist/selector-resolver.d.ts +34 -0
  226. package/dist/selector-resolver.js +181 -0
  227. package/dist/semantic-resolver.d.ts +35 -0
  228. package/dist/semantic-resolver.js +161 -0
  229. package/dist/server-capture-runtime.d.ts +125 -0
  230. package/dist/server-capture-runtime.js +585 -0
  231. package/dist/server-credit-usage.d.ts +12 -0
  232. package/dist/server-credit-usage.js +41 -0
  233. package/dist/server-posthog.d.ts +2 -0
  234. package/dist/server-posthog.js +16 -0
  235. package/dist/server-project-webhooks.d.ts +59 -0
  236. package/dist/server-project-webhooks.js +123 -0
  237. package/dist/server-screenshot-watermark.d.ts +7 -0
  238. package/dist/server-screenshot-watermark.js +60 -0
  239. package/dist/session-profile.d.ts +86 -0
  240. package/dist/session-profile.js +1536 -0
  241. package/dist/sf-pro-fonts.d.ts +4 -0
  242. package/dist/sf-pro-fonts.js +7 -0
  243. package/dist/sf-pro-symbols.d.ts +1 -0
  244. package/dist/sf-pro-symbols.js +55 -0
  245. package/dist/skill-packaging.d.ts +28 -0
  246. package/dist/skill-packaging.js +169 -0
  247. package/dist/smart-wait.d.ts +27 -0
  248. package/dist/smart-wait.js +81 -0
  249. package/dist/status-bar-l10n.d.ts +14 -0
  250. package/dist/status-bar-l10n.js +177 -0
  251. package/dist/status-bar-render.d.ts +20 -0
  252. package/dist/status-bar-render.js +410 -0
  253. package/dist/status-bar.d.ts +53 -0
  254. package/dist/status-bar.js +620 -0
  255. package/dist/svg-browser-bar.d.ts +33 -0
  256. package/dist/svg-browser-bar.js +206 -0
  257. package/dist/svg-status-bar.d.ts +36 -0
  258. package/dist/svg-status-bar.js +597 -0
  259. package/dist/svg-text.d.ts +61 -0
  260. package/dist/svg-text.js +118 -0
  261. package/dist/tools.d.ts +4 -0
  262. package/dist/tools.js +216 -0
  263. package/dist/types.d.ts +240 -5
  264. package/dist/types.js +23 -1
  265. package/dist/v2/action-verifier.d.ts +29 -0
  266. package/dist/v2/action-verifier.js +133 -0
  267. package/dist/v2/alt-text.d.ts +26 -0
  268. package/dist/v2/alt-text.js +55 -0
  269. package/dist/v2/benchmark.d.ts +59 -0
  270. package/dist/v2/benchmark.js +135 -0
  271. package/dist/v2/capture-strategy.d.ts +30 -0
  272. package/dist/v2/capture-strategy.js +67 -0
  273. package/dist/v2/capture-verification.d.ts +35 -0
  274. package/dist/v2/capture-verification.js +95 -0
  275. package/dist/v2/circuit-breaker.d.ts +42 -0
  276. package/dist/v2/circuit-breaker.js +119 -0
  277. package/dist/v2/cli-runner-local.d.ts +11 -0
  278. package/dist/v2/cli-runner-local.js +91 -0
  279. package/dist/v2/cli-runner.d.ts +34 -0
  280. package/dist/v2/cli-runner.js +300 -0
  281. package/dist/v2/compiler-prompts.d.ts +27 -0
  282. package/dist/v2/compiler-prompts.js +123 -0
  283. package/dist/v2/compiler.d.ts +37 -0
  284. package/dist/v2/compiler.js +147 -0
  285. package/dist/v2/explorer.d.ts +41 -0
  286. package/dist/v2/explorer.js +56 -0
  287. package/dist/v2/index.d.ts +37 -0
  288. package/dist/v2/index.js +31 -0
  289. package/dist/v2/llm-healer.d.ts +62 -0
  290. package/dist/v2/llm-healer.js +166 -0
  291. package/dist/v2/llm-provider.d.ts +29 -0
  292. package/dist/v2/llm-provider.js +80 -0
  293. package/dist/v2/opcode-runner.d.ts +47 -0
  294. package/dist/v2/opcode-runner.js +634 -0
  295. package/dist/v2/overlay-engine.d.ts +24 -0
  296. package/dist/v2/overlay-engine.js +150 -0
  297. package/dist/v2/postcondition.d.ts +16 -0
  298. package/dist/v2/postcondition.js +249 -0
  299. package/dist/v2/program-patcher.d.ts +25 -0
  300. package/dist/v2/program-patcher.js +44 -0
  301. package/dist/v2/recovery-chain.d.ts +30 -0
  302. package/dist/v2/recovery-chain.js +368 -0
  303. package/dist/v2/schema.d.ts +2580 -0
  304. package/dist/v2/schema.js +295 -0
  305. package/dist/v2/selector-resolver.d.ts +34 -0
  306. package/dist/v2/selector-resolver.js +181 -0
  307. package/dist/v2/semantic-resolver.d.ts +35 -0
  308. package/dist/v2/semantic-resolver.js +161 -0
  309. package/dist/v2/smart-wait.d.ts +27 -0
  310. package/dist/v2/smart-wait.js +81 -0
  311. package/dist/v2/types.d.ts +444 -0
  312. package/dist/v2/types.js +19 -0
  313. package/dist/v2/web-playwright-local.d.ts +69 -0
  314. package/dist/v2/web-playwright-local.js +392 -0
  315. package/dist/version.d.ts +1 -0
  316. package/dist/version.js +5 -0
  317. package/dist/video-agent.d.ts +143 -0
  318. package/dist/video-agent.js +4788 -0
  319. package/dist/video-observation.d.ts +36 -0
  320. package/dist/video-observation.js +192 -0
  321. package/dist/video-planner.d.ts +12 -0
  322. package/dist/video-planner.js +501 -0
  323. package/dist/video-prompts.d.ts +37 -0
  324. package/dist/video-prompts.js +554 -0
  325. package/dist/video-tools.d.ts +3 -0
  326. package/dist/video-tools.js +59 -0
  327. package/dist/video-variant-state.d.ts +29 -0
  328. package/dist/video-variant-state.js +80 -0
  329. package/dist/vision-model.d.ts +17 -0
  330. package/dist/vision-model.js +74 -0
  331. package/dist/web-playwright-local.d.ts +126 -0
  332. package/dist/web-playwright-local.js +819 -0
  333. package/dist/ws-auth.d.ts +20 -0
  334. package/dist/ws-auth.js +70 -0
  335. package/dist/ws-broadcast.d.ts +34 -0
  336. package/dist/ws-broadcast.js +85 -0
  337. package/dist/ws-connection-limits.d.ts +12 -0
  338. package/dist/ws-connection-limits.js +44 -0
  339. package/dist/ws-handler-utils.d.ts +32 -0
  340. package/dist/ws-handler-utils.js +139 -0
  341. package/dist/ws-handler.d.ts +10 -0
  342. package/dist/ws-handler.js +1793 -0
  343. package/dist/ws-metrics-server.d.ts +9 -0
  344. package/dist/ws-metrics-server.js +31 -0
  345. package/dist/ws-server.d.ts +9 -0
  346. package/dist/ws-server.js +92 -0
  347. package/package.json +142 -71
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Status bar PNG renderer — uses satori (CSS flexbox engine) + resvg for
3
+ * pixel-perfect parity with the HTML status bar used on the client.
4
+ *
5
+ * The layout code mirrors generateStatusBarHtml() from status-bar.ts exactly:
6
+ * same flex containers, gaps, font sizes, and icon dimensions. satori measures
7
+ * text widths using the actual SF Pro font metrics (via opentype.js), so
8
+ * spacing is identical to what a browser produces.
9
+ *
10
+ * Fonts are decompressed from woff2 → TTF on first use (wawoff2) and cached.
11
+ */
12
+ import { SF_PRO_TEXT_REGULAR, SF_PRO_TEXT_SEMIBOLD, SF_PRO_DISPLAY_REGULAR, SF_PRO_DISPLAY_SEMIBOLD, } from './sf-pro-fonts.js';
13
+ import { SF_PRO_SYMBOLS } from './sf-pro-symbols.js';
14
+ let fontCache = null;
15
+ async function getSatoriFonts() {
16
+ if (fontCache)
17
+ return fontCache;
18
+ const { decompress } = await import('wawoff2');
19
+ async function decompressFont(base64DataUri) {
20
+ const raw = base64DataUri.replace(/^data:font\/woff2;base64,/, '');
21
+ const woff2 = Buffer.from(raw, 'base64');
22
+ const ttf = await decompress(woff2);
23
+ return ttf.buffer.slice(ttf.byteOffset, ttf.byteOffset + ttf.byteLength);
24
+ }
25
+ // SF Pro subset fonts may be variable fonts (fvar table). opentype.js
26
+ // (used by satori) crashes on some fvar entries. We strip the fvar
27
+ // table from the decompressed TTF to work around this.
28
+ async function decompressFontSafe(base64DataUri) {
29
+ const data = await decompressFont(base64DataUri);
30
+ return stripFvarTable(data);
31
+ }
32
+ fontCache = [
33
+ { name: 'SF Pro Text', data: await decompressFontSafe(SF_PRO_TEXT_REGULAR), weight: 400, style: 'normal' },
34
+ { name: 'SF Pro Text', data: await decompressFontSafe(SF_PRO_TEXT_SEMIBOLD), weight: 600, style: 'normal' },
35
+ { name: 'SF Pro Display', data: await decompressFontSafe(SF_PRO_DISPLAY_REGULAR), weight: 400, style: 'normal' },
36
+ { name: 'SF Pro Display', data: await decompressFontSafe(SF_PRO_DISPLAY_SEMIBOLD), weight: 600, style: 'normal' },
37
+ { name: 'SF Pro Symbols', data: await decompressFontSafe(SF_PRO_SYMBOLS), weight: 400, style: 'normal' },
38
+ ];
39
+ return fontCache;
40
+ }
41
+ /**
42
+ * Strip the 'fvar' (and related 'gvar', 'STAT') tables from an sfnt font.
43
+ * opentype.js crashes on variable font fvar tables with missing name entries.
44
+ * Removing fvar makes the font static, which is fine for our fixed-weight subsets.
45
+ */
46
+ function stripFvarTable(data) {
47
+ const view = new DataView(data);
48
+ // sfnt header: sfVersion(4) + numTables(2) + searchRange(2) + entrySelector(2) + rangeShift(2)
49
+ const numTables = view.getUint16(4);
50
+ const RECORD_SIZE = 16; // Each table record: tag(4) + checksum(4) + offset(4) + length(4)
51
+ const headerSize = 12;
52
+ // Collect table records, filtering out fvar/gvar/STAT
53
+ const tagsToStrip = new Set(['fvar', 'gvar', 'STAT']);
54
+ const keptRecords = [];
55
+ for (let i = 0; i < numTables; i++) {
56
+ const recordOffset = headerSize + i * RECORD_SIZE;
57
+ const tagBytes = new Uint8Array(data, recordOffset, 4);
58
+ const tag = String.fromCharCode(...tagBytes);
59
+ if (!tagsToStrip.has(tag)) {
60
+ keptRecords.push({
61
+ tag,
62
+ checksum: view.getUint32(recordOffset + 4),
63
+ offset: view.getUint32(recordOffset + 8),
64
+ length: view.getUint32(recordOffset + 12),
65
+ });
66
+ }
67
+ }
68
+ if (keptRecords.length === numTables)
69
+ return data; // Nothing to strip
70
+ // Rebuild the font: header + new table records + table data
71
+ const newNumTables = keptRecords.length;
72
+ const newHeaderSize = 12 + newNumTables * RECORD_SIZE;
73
+ // Compute total size
74
+ let totalSize = newHeaderSize;
75
+ for (const rec of keptRecords) {
76
+ // Align to 4 bytes
77
+ totalSize = (totalSize + 3) & ~3;
78
+ totalSize += rec.length;
79
+ }
80
+ const out = new ArrayBuffer(totalSize);
81
+ const outView = new DataView(out);
82
+ const outBytes = new Uint8Array(out);
83
+ // Copy sfnt version
84
+ outView.setUint32(0, view.getUint32(0));
85
+ outView.setUint16(4, newNumTables);
86
+ // Compute search params
87
+ const entrySelector = Math.floor(Math.log2(newNumTables));
88
+ const searchRange = (1 << entrySelector) * 16;
89
+ const rangeShift = newNumTables * 16 - searchRange;
90
+ outView.setUint16(6, searchRange);
91
+ outView.setUint16(8, entrySelector);
92
+ outView.setUint16(10, rangeShift);
93
+ // Write table records and data
94
+ let dataOffset = newHeaderSize;
95
+ for (let i = 0; i < keptRecords.length; i++) {
96
+ const rec = keptRecords[i];
97
+ const recordPos = 12 + i * RECORD_SIZE;
98
+ // Align data offset
99
+ dataOffset = (dataOffset + 3) & ~3;
100
+ // Write record
101
+ for (let j = 0; j < 4; j++)
102
+ outBytes[recordPos + j] = rec.tag.charCodeAt(j);
103
+ outView.setUint32(recordPos + 4, rec.checksum);
104
+ outView.setUint32(recordPos + 8, dataOffset);
105
+ outView.setUint32(recordPos + 12, rec.length);
106
+ // Copy table data
107
+ outBytes.set(new Uint8Array(data, rec.offset, rec.length), dataOffset);
108
+ dataOffset += rec.length;
109
+ }
110
+ return out;
111
+ }
112
+ // ── SVG icon helpers ────────────────────────────────────────────────────
113
+ // Convert inline SVG strings to data URI <img> elements for satori.
114
+ function svgToImg(svgString, width, height) {
115
+ // Clean up multi-line SVGs — satori's img handler works best with compact SVGs.
116
+ // Also ensure xmlns is present for standalone SVG rendering.
117
+ let clean = svgString.replace(/\n\s*/g, ' ').trim();
118
+ if (!clean.includes('xmlns=')) {
119
+ clean = clean.replace('<svg ', '<svg xmlns="http://www.w3.org/2000/svg" ');
120
+ }
121
+ const encoded = Buffer.from(clean).toString('base64');
122
+ return {
123
+ type: 'img',
124
+ props: {
125
+ src: `data:image/svg+xml;base64,${encoded}`,
126
+ width,
127
+ height,
128
+ style: { display: 'block' },
129
+ },
130
+ };
131
+ }
132
+ // ── Icon SVG generators (same paths as status-bar.ts) ────────────────────
133
+ // Imported from status-bar.ts — these are the same SVG path constants
134
+ const SIGNAL_BAR_PATHS = [
135
+ 'M2.13333 7.53962H1.06667C0.477563 7.53962 0 8.06421 0 8.71132V11.0547C0 11.7018 0.477563 12.2264 1.06667 12.2264H2.13333C2.72244 12.2264 3.2 11.7018 3.2 11.0547V8.71132C3.2 8.06421 2.72244 7.53962 2.13333 7.53962Z',
136
+ 'M7.43411 5.09433H6.36745C5.77834 5.09433 5.30078 5.62652 5.30078 6.28301V11.0377C5.30078 11.6942 5.77834 12.2264 6.36745 12.2264H7.43411C8.02322 12.2264 8.50078 11.6942 8.50078 11.0377V6.28301C8.50078 5.62652 8.02322 5.09433 7.43411 5.09433Z',
137
+ 'M11.7659 2.44528H12.8326C13.4217 2.44528 13.8992 2.97078 13.8992 3.61902V11.0527C13.8992 11.7009 13.4217 12.2264 12.8326 12.2264H11.7659C11.1768 12.2264 10.6992 11.7009 10.6992 11.0527V3.61902C10.6992 2.97078 11.1768 2.44528 11.7659 2.44528Z',
138
+ 'M19.2 1.14623C19.2 0.513183 18.7224 0 18.1333 0H17.0667C16.4776 0 16 0.513183 16 1.14623V11.0802C16 11.7132 16.4776 12.2264 17.0667 12.2264H18.1333C18.7224 12.2264 19.2 11.7132 19.2 11.0802V1.14623Z',
139
+ ];
140
+ const WIFI_TIER_PATHS = [
141
+ 'M8.5713 2.46628C11.0584 2.46639 13.4504 3.38847 15.2529 5.04195C15.3887 5.1696 15.6056 5.16799 15.7393 5.03834L17.0368 3.77487C17.1045 3.70911 17.1422 3.62004 17.1417 3.52735C17.1411 3.43467 17.1023 3.34603 17.0338 3.28104C12.3028 -1.09368 4.83907 -1.09368 0.108056 3.28104C0.039524 3.34598 0.000639766 3.4346 7.82398e-06 3.52728C-0.000624118 3.61996 0.0370483 3.70906 0.104689 3.77487L1.40255 5.03834C1.53615 5.16819 1.75327 5.1698 1.88893 5.04195C3.69167 3.38836 6.08395 2.46628 8.5713 2.46628Z',
142
+ 'M8.56795 6.68656C9.92527 6.68647 11.2341 7.19821 12.2403 8.12234C12.3763 8.2535 12.5907 8.25065 12.7234 8.11593L14.0106 6.79663C14.0784 6.72742 14.1161 6.63355 14.1151 6.536C14.1141 6.43844 14.0746 6.34536 14.0054 6.27757C10.9416 3.38672 6.19688 3.38672 3.13305 6.27757C3.06384 6.34536 3.02435 6.43849 3.02345 6.53607C3.02254 6.63366 3.06028 6.72752 3.12822 6.79663L4.41513 8.11593C4.54778 8.25065 4.76215 8.2535 4.89823 8.12234C5.90368 7.19882 7.21152 6.68713 8.56795 6.68656Z',
143
+ 'M11.0924 9.48011C11.0943 9.58546 11.0572 9.68703 10.9899 9.76084L8.81327 12.2156C8.74946 12.2877 8.66247 12.3283 8.5717 12.3283C8.48093 12.3283 8.39394 12.2877 8.33013 12.2156L6.1531 9.76084C6.08585 9.68697 6.04886 9.58537 6.05085 9.48002C6.05284 9.37467 6.09365 9.27491 6.16364 9.20429C7.55374 7.8904 9.58966 7.8904 10.9798 9.20429C11.0497 9.27497 11.0904 9.37476 11.0924 9.48011Z',
144
+ ];
145
+ function makeSignalSvg(strength, color, size) {
146
+ const viewW = 20, viewH = 13;
147
+ const h = size * (viewH / viewW);
148
+ const paths = SIGNAL_BAR_PATHS.map((d, i) => `<path d="${d}" fill="${color}" opacity="${i < strength ? 1 : 0.25}"/>`).join('');
149
+ return `<svg width="${size}" height="${h}" viewBox="0 0 ${viewW} ${viewH}" fill="none" xmlns="http://www.w3.org/2000/svg">${paths}</svg>`;
150
+ }
151
+ function makeWifiSvg(strength, color, size) {
152
+ const viewW = 18, viewH = 13;
153
+ const h = size * (viewH / viewW);
154
+ const tiers = WIFI_TIER_PATHS.map((d, i) => `<path d="${d}" fill="${color}" opacity="${strength >= (3 - i) ? 1 : 0.25}"/>`).join('');
155
+ return `<svg width="${size}" height="${h}" viewBox="0 0 ${viewW} ${viewH}" fill="none" xmlns="http://www.w3.org/2000/svg">${tiers}</svg>`;
156
+ }
157
+ // Reuse the existing renderBattery from status-bar.ts (it already returns a full <svg> string)
158
+ import { renderBattery as renderBatteryIcon } from './status-bar.js';
159
+ // ── Satori element builders ─────────────────────────────────────────────
160
+ // Mirror the exact HTML structure from generateStatusBarHtml() but as
161
+ // satori-compatible element trees.
162
+ const DEFAULT_CONFIG = {
163
+ time: '9:41',
164
+ date: 'Sat 1 Mar',
165
+ menuBarApp: 'Safari',
166
+ menuBarItems: ['File', 'Edit', 'View', 'History', 'Bookmarks', 'Window', 'Help'],
167
+ signalStrength: 4,
168
+ showNetworkType: false,
169
+ networkType: '5G',
170
+ wifiStrength: 3,
171
+ batteryLevel: 100,
172
+ batteryCharging: false,
173
+ showBatteryPercentage: true,
174
+ colorScheme: 'light',
175
+ carrierName: 'Carrier',
176
+ autoLocale: true,
177
+ };
178
+ const DEFAULT_LAYOUTS = {
179
+ 'iphone-dynamic-island': {
180
+ leftInset: 56, rightInset: 36,
181
+ centerGap: { left: 128, right: 274 },
182
+ fontSize: { time: 17, networkType: 13 },
183
+ iconSize: { signal: 20, wifi: 18, battery: 28 },
184
+ iconGap: 7,
185
+ },
186
+ 'iphone-notch': {
187
+ leftInset: 56, rightInset: 36,
188
+ centerGap: { left: 128, right: 274 },
189
+ fontSize: { time: 17, networkType: 13 },
190
+ iconSize: { signal: 20, wifi: 18, battery: 28 },
191
+ iconGap: 7,
192
+ },
193
+ 'iphone-home-button': {
194
+ leftInset: 6, rightInset: 6,
195
+ fontSize: { time: 14, networkType: 14 },
196
+ iconSize: { signal: 16, wifi: 14, battery: 24 },
197
+ iconGap: 4,
198
+ },
199
+ 'ipad': {
200
+ leftInset: 24, rightInset: 24,
201
+ fontSize: { time: 15, networkType: 11 },
202
+ iconSize: { signal: 17, wifi: 15, battery: 25 },
203
+ iconGap: 6,
204
+ },
205
+ 'mac-notch': {
206
+ leftInset: 12, rightInset: 12,
207
+ centerGap: { left: 700, right: 936 },
208
+ fontSize: { time: 13, networkType: 11 },
209
+ iconSize: { signal: 0, wifi: 14, battery: 22 },
210
+ iconGap: 8,
211
+ },
212
+ };
213
+ function textNode(text, fontSize, color, opts = {}) {
214
+ const { weight = 400, letterSpacing, fontFamily, maxWidth } = opts;
215
+ const style = {
216
+ fontSize,
217
+ fontWeight: weight,
218
+ color,
219
+ lineHeight: 1,
220
+ whiteSpace: 'nowrap',
221
+ };
222
+ if (letterSpacing != null)
223
+ style.letterSpacing = letterSpacing;
224
+ if (fontFamily)
225
+ style.fontFamily = fontFamily;
226
+ if (maxWidth) {
227
+ style.maxWidth = maxWidth;
228
+ style.overflow = 'hidden';
229
+ style.textOverflow = 'ellipsis';
230
+ }
231
+ return { type: 'span', props: { style, children: text } };
232
+ }
233
+ function flexRow(children, style = {}) {
234
+ const filtered = children.filter(Boolean);
235
+ return {
236
+ type: 'div',
237
+ props: {
238
+ style: { display: 'flex', alignItems: 'center', ...style },
239
+ children: filtered,
240
+ },
241
+ };
242
+ }
243
+ function buildIPhoneElement(cfg, layout, width, height, color, fontFamily) {
244
+ const gap = layout.iconGap;
245
+ const { signal: signalW, wifi: wifiW, battery: batteryW } = layout.iconSize;
246
+ const signalH = signalW * (13 / 20);
247
+ const wifiH = wifiW * (13 / 18);
248
+ const batteryH = batteryW * (16 / 35);
249
+ const leftGroup = flexRow([
250
+ textNode(cfg.time, layout.fontSize.time, color, { weight: 600, letterSpacing: -0.4 }),
251
+ ], { position: 'absolute', left: layout.leftInset, top: 0, height: '100%' });
252
+ const rightChildren = [
253
+ svgToImg(makeSignalSvg(cfg.signalStrength, color, signalW), signalW, signalH),
254
+ cfg.showNetworkType && textNode(cfg.networkType, layout.fontSize.networkType, color, { weight: 600, letterSpacing: 0.2 }),
255
+ svgToImg(makeWifiSvg(cfg.wifiStrength, color, wifiW), wifiW, wifiH),
256
+ svgToImg(renderBatteryIcon(cfg.batteryLevel, cfg.batteryCharging, color, batteryW, cfg.colorScheme === 'dark'), batteryW, batteryH),
257
+ ];
258
+ const rightGroup = flexRow(rightChildren, {
259
+ position: 'absolute', right: layout.rightInset, top: 0, height: '100%', gap,
260
+ });
261
+ return {
262
+ type: 'div',
263
+ props: {
264
+ style: {
265
+ position: 'relative', width, height, fontFamily,
266
+ display: 'flex', overflow: 'hidden',
267
+ },
268
+ children: [leftGroup, rightGroup],
269
+ },
270
+ };
271
+ }
272
+ function buildIPhoneHomeButtonElement(cfg, layout, width, height, color, fontFamily) {
273
+ const gap = layout.iconGap;
274
+ const labelSize = layout.fontSize.networkType;
275
+ const { signal: signalW, wifi: wifiW, battery: batteryW } = layout.iconSize;
276
+ const signalH = signalW * (13 / 20);
277
+ const wifiH = wifiW * (13 / 18);
278
+ const batteryH = batteryW * (16 / 35);
279
+ const leftGroup = flexRow([
280
+ svgToImg(makeSignalSvg(cfg.signalStrength, color, signalW), signalW, signalH),
281
+ textNode(cfg.carrierName, labelSize, color, { maxWidth: 80 }),
282
+ cfg.showNetworkType && textNode(cfg.networkType, labelSize - 1, color, { weight: 600 }),
283
+ svgToImg(makeWifiSvg(cfg.wifiStrength, color, wifiW), wifiW, wifiH),
284
+ ], { position: 'absolute', left: layout.leftInset, top: 0, height: '100%', gap });
285
+ const centerGroup = flexRow([
286
+ textNode(cfg.time, layout.fontSize.time, color, { weight: 600, letterSpacing: -0.4 }),
287
+ ], { position: 'absolute', left: '50%', top: 0, height: '100%', transform: 'translateX(-50%)' });
288
+ const rightGroup = flexRow([
289
+ cfg.showBatteryPercentage && textNode(`${cfg.batteryLevel}%`, labelSize, color),
290
+ svgToImg(renderBatteryIcon(cfg.batteryLevel, cfg.batteryCharging, color, batteryW, cfg.colorScheme === 'dark'), batteryW, batteryH),
291
+ ], { position: 'absolute', right: layout.rightInset, top: 0, height: '100%', gap });
292
+ return {
293
+ type: 'div',
294
+ props: {
295
+ style: { position: 'relative', width, height, fontFamily, display: 'flex', overflow: 'hidden' },
296
+ children: [leftGroup, centerGroup, rightGroup],
297
+ },
298
+ };
299
+ }
300
+ function buildIPadElement(cfg, layout, width, height, color, fontFamily) {
301
+ const gap = layout.iconGap;
302
+ const { signal: signalW, wifi: wifiW, battery: batteryW } = layout.iconSize;
303
+ const signalH = signalW * (13 / 20);
304
+ const wifiH = wifiW * (13 / 18);
305
+ const batteryH = batteryW * (16 / 35);
306
+ const leftChildren = [
307
+ textNode(cfg.time, layout.fontSize.time, color, { letterSpacing: -0.4 }),
308
+ !!cfg.date && {
309
+ type: 'span',
310
+ props: {
311
+ style: { fontSize: layout.fontSize.time, fontWeight: 400, color, lineHeight: 1, letterSpacing: -0.4, marginLeft: 16 },
312
+ children: cfg.date,
313
+ },
314
+ },
315
+ ];
316
+ const leftGroup = flexRow(leftChildren, {
317
+ position: 'absolute', left: layout.leftInset, top: 0, height: '100%',
318
+ });
319
+ const rightGroup = flexRow([
320
+ svgToImg(makeSignalSvg(cfg.signalStrength, color, signalW), signalW, signalH),
321
+ svgToImg(makeWifiSvg(cfg.wifiStrength, color, wifiW), wifiW, wifiH),
322
+ textNode(`${cfg.batteryLevel}%`, layout.fontSize.networkType, color),
323
+ svgToImg(renderBatteryIcon(cfg.batteryLevel, cfg.batteryCharging, color, batteryW, cfg.colorScheme === 'dark'), batteryW, batteryH),
324
+ ], { position: 'absolute', right: layout.rightInset, top: 0, height: '100%', gap });
325
+ return {
326
+ type: 'div',
327
+ props: {
328
+ style: { position: 'relative', width, height, fontFamily, display: 'flex', overflow: 'hidden' },
329
+ children: [leftGroup, rightGroup],
330
+ },
331
+ };
332
+ }
333
+ function buildMacMenuBarElement(cfg, layout, width, height, color) {
334
+ const fontSize = layout.fontSize.time;
335
+ const gap = layout.iconGap;
336
+ const { wifi: wifiW, battery: batteryW } = layout.iconSize;
337
+ const wifiH = wifiW * (13 / 18);
338
+ const batteryH = batteryW * (16 / 35);
339
+ const macFF = "'SF Pro Display','SF Pro Text',system-ui,sans-serif";
340
+ const symbolsFF = "'SF Pro Symbols','SF Pro Text','SF Pro Display',system-ui,sans-serif";
341
+ const menuItemNodes = cfg.menuBarItems.map(item => textNode(item, fontSize, color));
342
+ const leftGroup = flexRow([
343
+ textNode('\uF8FF', fontSize + 3, color, { fontFamily: symbolsFF }),
344
+ textNode(cfg.menuBarApp, fontSize, color, { weight: 700 }),
345
+ flexRow(menuItemNodes, { gap: gap + 10 }),
346
+ ], { position: 'absolute', left: layout.leftInset, top: 0, height: '100%', gap: gap + 6 });
347
+ const batteryGroup = flexRow([
348
+ cfg.showBatteryPercentage && textNode(`${cfg.batteryLevel}%`, fontSize - 1, color),
349
+ svgToImg(renderBatteryIcon(cfg.batteryLevel, cfg.batteryCharging, color, batteryW, cfg.colorScheme === 'dark'), batteryW, batteryH),
350
+ ], { gap: 3 });
351
+ const rightGroup = flexRow([
352
+ svgToImg(makeWifiSvg(cfg.wifiStrength, color, wifiW), wifiW, wifiH),
353
+ batteryGroup,
354
+ textNode('􀊫', fontSize, color, { fontFamily: symbolsFF }),
355
+ textNode('􀜊', fontSize, color, { fontFamily: symbolsFF }),
356
+ textNode('􀉭', fontSize, color, { fontFamily: symbolsFF }),
357
+ cfg.date ? textNode(cfg.date, fontSize, color, { weight: 500 }) : false,
358
+ textNode(cfg.time, fontSize, color, { weight: 500 }),
359
+ ], { position: 'absolute', right: layout.rightInset, top: 0, height: '100%', gap: gap + 2 });
360
+ return {
361
+ type: 'div',
362
+ props: {
363
+ style: { position: 'relative', width, height, fontFamily: macFF, display: 'flex', overflow: 'hidden' },
364
+ children: [leftGroup, rightGroup],
365
+ },
366
+ };
367
+ }
368
+ // ── Public API ────────────────────────────────────────────────────────────
369
+ /**
370
+ * Render the status bar to a PNG buffer using satori (CSS flexbox) + resvg.
371
+ * Produces pixel-perfect output matching the HTML status bar on the client.
372
+ *
373
+ * @param options Same options as generateStatusBarHtml()
374
+ * @param targetWidth Physical pixel width for the output PNG (e.g. logical × outputScale)
375
+ */
376
+ export async function renderStatusBarBuffer(options, targetWidth) {
377
+ const cfg = { ...DEFAULT_CONFIG, ...options.config };
378
+ const layout = options.layout ?? DEFAULT_LAYOUTS[options.deviceType];
379
+ const { width, height } = options;
380
+ const color = cfg.colorScheme === 'dark' ? '#FFFFFF' : '#000000';
381
+ const fontFamily = "'SF Pro Text','SF Pro Display',system-ui,sans-serif";
382
+ let element;
383
+ if (options.deviceType === 'iphone-home-button') {
384
+ element = buildIPhoneHomeButtonElement(cfg, layout, width, height, color, fontFamily);
385
+ }
386
+ else if (options.deviceType === 'iphone-dynamic-island' || options.deviceType === 'iphone-notch') {
387
+ element = buildIPhoneElement(cfg, layout, width, height, color, fontFamily);
388
+ }
389
+ else if (options.deviceType === 'mac-notch') {
390
+ element = buildMacMenuBarElement(cfg, layout, width, height, color);
391
+ }
392
+ else {
393
+ element = buildIPadElement(cfg, layout, width, height, color, fontFamily);
394
+ }
395
+ const fonts = await getSatoriFonts();
396
+ const satori = (await import('satori')).default;
397
+ const svg = await satori(element, {
398
+ width,
399
+ height,
400
+ fonts: fonts,
401
+ });
402
+ // Rasterize at target width (scales up for HiDPI)
403
+ const { Resvg } = await import('@resvg/resvg-js');
404
+ const resvg = new Resvg(svg, {
405
+ fitTo: { mode: 'width', value: targetWidth },
406
+ });
407
+ const rendered = resvg.render();
408
+ return Buffer.from(rendered.asPng());
409
+ }
410
+ //# sourceMappingURL=status-bar-render.js.map
@@ -0,0 +1,53 @@
1
+ export interface StatusBarConfig {
2
+ time?: string;
3
+ date?: string;
4
+ menuBarApp?: string;
5
+ menuBarItems?: string[];
6
+ signalStrength?: number;
7
+ showNetworkType?: boolean;
8
+ networkType?: string;
9
+ wifiStrength?: number;
10
+ batteryLevel?: number;
11
+ batteryCharging?: boolean;
12
+ showBatteryPercentage?: boolean;
13
+ colorScheme?: 'light' | 'dark';
14
+ carrierName?: string;
15
+ autoLocale?: boolean;
16
+ }
17
+ export interface StatusBarLayout {
18
+ leftInset: number;
19
+ rightInset: number;
20
+ centerGap?: {
21
+ left: number;
22
+ right: number;
23
+ };
24
+ fontSize: {
25
+ time: number;
26
+ networkType: number;
27
+ };
28
+ iconSize: {
29
+ signal: number;
30
+ wifi: number;
31
+ battery: number;
32
+ };
33
+ iconGap: number;
34
+ }
35
+ export type StatusBarDeviceType = 'iphone-dynamic-island' | 'iphone-notch' | 'iphone-home-button' | 'ipad' | 'mac-notch';
36
+ export interface StatusBarRenderOptions {
37
+ config: StatusBarConfig;
38
+ width: number;
39
+ height: number;
40
+ scale: number;
41
+ deviceType: StatusBarDeviceType;
42
+ layout?: StatusBarLayout;
43
+ includeFontStyles?: boolean;
44
+ }
45
+ export declare const STATUS_BAR_FONT_CSS: string;
46
+ export declare function generateStatusBarHtml(options: StatusBarRenderOptions): string;
47
+ export declare function renderBattery(level: number, charging: boolean, color: string, size: number, isDark?: boolean): string;
48
+ /**
49
+ * Generate a self-contained SVG string for the status bar.
50
+ * Used by the sharp compositing pipeline (no Playwright).
51
+ * The returned SVG includes embedded SF Pro fonts via @font-face data URIs.
52
+ */
53
+ export declare function generateStatusBarSvg(options: StatusBarRenderOptions): string;