termcast 1.3.9

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 (699) hide show
  1. package/dist/action-utils.d.ts +25 -0
  2. package/dist/action-utils.d.ts.map +1 -0
  3. package/dist/action-utils.js +209 -0
  4. package/dist/action-utils.js.map +1 -0
  5. package/dist/ai.d.ts +104 -0
  6. package/dist/ai.d.ts.map +1 -0
  7. package/dist/ai.js +135 -0
  8. package/dist/ai.js.map +1 -0
  9. package/dist/apis/ai.d.ts +104 -0
  10. package/dist/apis/ai.d.ts.map +1 -0
  11. package/dist/apis/ai.js +135 -0
  12. package/dist/apis/ai.js.map +1 -0
  13. package/dist/apis/cache.d.ts +84 -0
  14. package/dist/apis/cache.d.ts.map +1 -0
  15. package/dist/apis/cache.js +307 -0
  16. package/dist/apis/cache.js.map +1 -0
  17. package/dist/apis/cache.test.d.ts +2 -0
  18. package/dist/apis/cache.test.d.ts.map +1 -0
  19. package/dist/apis/cache.test.js +246 -0
  20. package/dist/apis/cache.test.js.map +1 -0
  21. package/dist/apis/clipboard.d.ts +36 -0
  22. package/dist/apis/clipboard.d.ts.map +1 -0
  23. package/dist/apis/clipboard.js +154 -0
  24. package/dist/apis/clipboard.js.map +1 -0
  25. package/dist/apis/environment.d.ts +63 -0
  26. package/dist/apis/environment.d.ts.map +1 -0
  27. package/dist/apis/environment.js +189 -0
  28. package/dist/apis/environment.js.map +1 -0
  29. package/dist/apis/hud.d.ts +7 -0
  30. package/dist/apis/hud.d.ts.map +1 -0
  31. package/dist/apis/hud.js +45 -0
  32. package/dist/apis/hud.js.map +1 -0
  33. package/dist/apis/localstorage.d.ts +13 -0
  34. package/dist/apis/localstorage.d.ts.map +1 -0
  35. package/dist/apis/localstorage.js +190 -0
  36. package/dist/apis/localstorage.js.map +1 -0
  37. package/dist/apis/localstorage.test.d.ts +2 -0
  38. package/dist/apis/localstorage.test.d.ts.map +1 -0
  39. package/dist/apis/localstorage.test.js +131 -0
  40. package/dist/apis/localstorage.test.js.map +1 -0
  41. package/dist/apis/oauth.d.ts +142 -0
  42. package/dist/apis/oauth.d.ts.map +1 -0
  43. package/dist/apis/oauth.js +551 -0
  44. package/dist/apis/oauth.js.map +1 -0
  45. package/dist/apis/preferences.d.ts +23 -0
  46. package/dist/apis/preferences.d.ts.map +1 -0
  47. package/dist/apis/preferences.js +105 -0
  48. package/dist/apis/preferences.js.map +1 -0
  49. package/dist/apis/toast.d.ts +81 -0
  50. package/dist/apis/toast.d.ts.map +1 -0
  51. package/dist/apis/toast.js +275 -0
  52. package/dist/apis/toast.js.map +1 -0
  53. package/dist/apis/toast.test.d.ts +2 -0
  54. package/dist/apis/toast.test.d.ts.map +1 -0
  55. package/dist/apis/toast.test.js +67 -0
  56. package/dist/apis/toast.test.js.map +1 -0
  57. package/dist/apis/window.d.ts +12 -0
  58. package/dist/apis/window.d.ts.map +1 -0
  59. package/dist/apis/window.js +47 -0
  60. package/dist/apis/window.js.map +1 -0
  61. package/dist/build.d.ts +15 -0
  62. package/dist/build.d.ts.map +1 -0
  63. package/dist/build.js +213 -0
  64. package/dist/build.js.map +1 -0
  65. package/dist/build.test.d.ts +2 -0
  66. package/dist/build.test.d.ts.map +1 -0
  67. package/dist/build.test.js +73 -0
  68. package/dist/build.test.js.map +1 -0
  69. package/dist/cache.d.ts +32 -0
  70. package/dist/cache.d.ts.map +1 -0
  71. package/dist/cache.js +205 -0
  72. package/dist/cache.js.map +1 -0
  73. package/dist/cache.test.d.ts +2 -0
  74. package/dist/cache.test.d.ts.map +1 -0
  75. package/dist/cache.test.js +246 -0
  76. package/dist/cache.test.js.map +1 -0
  77. package/dist/cli.d.ts +2 -0
  78. package/dist/cli.d.ts.map +1 -0
  79. package/dist/cli.js +278 -0
  80. package/dist/cli.js.map +1 -0
  81. package/dist/clipboard.d.ts +36 -0
  82. package/dist/clipboard.d.ts.map +1 -0
  83. package/dist/clipboard.js +154 -0
  84. package/dist/clipboard.js.map +1 -0
  85. package/dist/colors.d.ts +15 -0
  86. package/dist/colors.d.ts.map +1 -0
  87. package/dist/colors.js +13 -0
  88. package/dist/colors.js.map +1 -0
  89. package/dist/components/actions.d.ts +120 -0
  90. package/dist/components/actions.d.ts.map +1 -0
  91. package/dist/components/actions.js +371 -0
  92. package/dist/components/actions.js.map +1 -0
  93. package/dist/components/alert.d.ts +25 -0
  94. package/dist/components/alert.d.ts.map +1 -0
  95. package/dist/components/alert.js +99 -0
  96. package/dist/components/alert.js.map +1 -0
  97. package/dist/components/detail.d.ts +65 -0
  98. package/dist/components/detail.d.ts.map +1 -0
  99. package/dist/components/detail.js +147 -0
  100. package/dist/components/detail.js.map +1 -0
  101. package/dist/components/dropdown.d.ts +40 -0
  102. package/dist/components/dropdown.d.ts.map +1 -0
  103. package/dist/components/dropdown.js +202 -0
  104. package/dist/components/dropdown.js.map +1 -0
  105. package/dist/components/extension-preferences.d.ts +8 -0
  106. package/dist/components/extension-preferences.d.ts.map +1 -0
  107. package/dist/components/extension-preferences.js +139 -0
  108. package/dist/components/extension-preferences.js.map +1 -0
  109. package/dist/components/form/assign-components.d.ts +2 -0
  110. package/dist/components/form/assign-components.d.ts.map +1 -0
  111. package/dist/components/form/assign-components.js +22 -0
  112. package/dist/components/form/assign-components.js.map +1 -0
  113. package/dist/components/form/checkbox.d.ts +7 -0
  114. package/dist/components/form/checkbox.d.ts.map +1 -0
  115. package/dist/components/form/checkbox.js +46 -0
  116. package/dist/components/form/checkbox.js.map +1 -0
  117. package/dist/components/form/date-picker.d.ts +18 -0
  118. package/dist/components/form/date-picker.d.ts.map +1 -0
  119. package/dist/components/form/date-picker.js +69 -0
  120. package/dist/components/form/date-picker.js.map +1 -0
  121. package/dist/components/form/description.d.ts +7 -0
  122. package/dist/components/form/description.d.ts.map +1 -0
  123. package/dist/components/form/description.js +8 -0
  124. package/dist/components/form/description.js.map +1 -0
  125. package/dist/components/form/dropdown.d.ts +25 -0
  126. package/dist/components/form/dropdown.d.ts.map +1 -0
  127. package/dist/components/form/dropdown.js +286 -0
  128. package/dist/components/form/dropdown.js.map +1 -0
  129. package/dist/components/form/file-autocomplete.d.ts +12 -0
  130. package/dist/components/form/file-autocomplete.d.ts.map +1 -0
  131. package/dist/components/form/file-autocomplete.js +84 -0
  132. package/dist/components/form/file-autocomplete.js.map +1 -0
  133. package/dist/components/form/file-picker.d.ts +31 -0
  134. package/dist/components/form/file-picker.d.ts.map +1 -0
  135. package/dist/components/form/file-picker.js +113 -0
  136. package/dist/components/form/file-picker.js.map +1 -0
  137. package/dist/components/form/form-end.d.ts +2 -0
  138. package/dist/components/form/form-end.d.ts.map +1 -0
  139. package/dist/components/form/form-end.js +6 -0
  140. package/dist/components/form/form-end.js.map +1 -0
  141. package/dist/components/form/form-type-only.d.ts +174 -0
  142. package/dist/components/form/form-type-only.d.ts.map +1 -0
  143. package/dist/components/form/form-type-only.js +2 -0
  144. package/dist/components/form/form-type-only.js.map +1 -0
  145. package/dist/components/form/index.d.ts +46 -0
  146. package/dist/components/form/index.d.ts.map +1 -0
  147. package/dist/components/form/index.js +106 -0
  148. package/dist/components/form/index.js.map +1 -0
  149. package/dist/components/form/password-field.d.ts +7 -0
  150. package/dist/components/form/password-field.d.ts.map +1 -0
  151. package/dist/components/form/password-field.js +34 -0
  152. package/dist/components/form/password-field.js.map +1 -0
  153. package/dist/components/form/separator.d.ts +2 -0
  154. package/dist/components/form/separator.d.ts.map +1 -0
  155. package/dist/components/form/separator.js +8 -0
  156. package/dist/components/form/separator.js.map +1 -0
  157. package/dist/components/form/tagpicker.d.ts +134 -0
  158. package/dist/components/form/tagpicker.d.ts.map +1 -0
  159. package/dist/components/form/tagpicker.js +79 -0
  160. package/dist/components/form/tagpicker.js.map +1 -0
  161. package/dist/components/form/text-area.d.ts +8 -0
  162. package/dist/components/form/text-area.d.ts.map +1 -0
  163. package/dist/components/form/text-area.js +26 -0
  164. package/dist/components/form/text-area.js.map +1 -0
  165. package/dist/components/form/text-field.d.ts +7 -0
  166. package/dist/components/form/text-field.d.ts.map +1 -0
  167. package/dist/components/form/text-field.js +28 -0
  168. package/dist/components/form/text-field.js.map +1 -0
  169. package/dist/components/form/types.d.ts +43 -0
  170. package/dist/components/form/types.d.ts.map +1 -0
  171. package/dist/components/form/types.js +2 -0
  172. package/dist/components/form/types.js.map +1 -0
  173. package/dist/components/form/use-form-handling.d.ts +4 -0
  174. package/dist/components/form/use-form-handling.d.ts.map +1 -0
  175. package/dist/components/form/use-form-handling.js +37 -0
  176. package/dist/components/form/use-form-handling.js.map +1 -0
  177. package/dist/components/form/use-form-navigation.d.ts +8 -0
  178. package/dist/components/form/use-form-navigation.d.ts.map +1 -0
  179. package/dist/components/form/use-form-navigation.js +58 -0
  180. package/dist/components/form/use-form-navigation.js.map +1 -0
  181. package/dist/components/form/with-left-border.d.ts +17 -0
  182. package/dist/components/form/with-left-border.d.ts.map +1 -0
  183. package/dist/components/form/with-left-border.js +10 -0
  184. package/dist/components/form/with-left-border.js.map +1 -0
  185. package/dist/components/icon.d.ts +9 -0
  186. package/dist/components/icon.d.ts.map +1 -0
  187. package/dist/components/icon.js +485 -0
  188. package/dist/components/icon.js.map +1 -0
  189. package/dist/components/image.d.ts +19 -0
  190. package/dist/components/image.d.ts.map +1 -0
  191. package/dist/components/image.js +32 -0
  192. package/dist/components/image.js.map +1 -0
  193. package/dist/components/list.d.ts +234 -0
  194. package/dist/components/list.d.ts.map +1 -0
  195. package/dist/components/list.js +667 -0
  196. package/dist/components/list.js.map +1 -0
  197. package/dist/components/loading-bar.d.ts +8 -0
  198. package/dist/components/loading-bar.d.ts.map +1 -0
  199. package/dist/components/loading-bar.js +107 -0
  200. package/dist/components/loading-bar.js.map +1 -0
  201. package/dist/components/menubar-extra.d.ts +68 -0
  202. package/dist/components/menubar-extra.d.ts.map +1 -0
  203. package/dist/components/menubar-extra.js +39 -0
  204. package/dist/components/menubar-extra.js.map +1 -0
  205. package/dist/descendants.d.ts +25 -0
  206. package/dist/descendants.d.ts.map +1 -0
  207. package/dist/descendants.js +81 -0
  208. package/dist/descendants.js.map +1 -0
  209. package/dist/dev-ui.d.ts +7 -0
  210. package/dist/dev-ui.d.ts.map +1 -0
  211. package/dist/dev-ui.js +118 -0
  212. package/dist/dev-ui.js.map +1 -0
  213. package/dist/e2e-node.d.ts +63 -0
  214. package/dist/e2e-node.d.ts.map +1 -0
  215. package/dist/e2e-node.js +255 -0
  216. package/dist/e2e-node.js.map +1 -0
  217. package/dist/e2e.d.ts +39 -0
  218. package/dist/e2e.d.ts.map +1 -0
  219. package/dist/e2e.js +127 -0
  220. package/dist/e2e.js.map +1 -0
  221. package/dist/environment.d.ts +63 -0
  222. package/dist/environment.d.ts.map +1 -0
  223. package/dist/environment.js +189 -0
  224. package/dist/environment.js.map +1 -0
  225. package/dist/examples/action-show-in-finder.d.ts +2 -0
  226. package/dist/examples/action-show-in-finder.d.ts.map +1 -0
  227. package/dist/examples/action-show-in-finder.js +13 -0
  228. package/dist/examples/action-show-in-finder.js.map +1 -0
  229. package/dist/examples/datepicker.d.ts +2 -0
  230. package/dist/examples/datepicker.d.ts.map +1 -0
  231. package/dist/examples/datepicker.js +344 -0
  232. package/dist/examples/datepicker.js.map +1 -0
  233. package/dist/examples/environment-test.d.ts +2 -0
  234. package/dist/examples/environment-test.d.ts.map +1 -0
  235. package/dist/examples/environment-test.js +28 -0
  236. package/dist/examples/environment-test.js.map +1 -0
  237. package/dist/examples/error-boundary.d.ts +6 -0
  238. package/dist/examples/error-boundary.d.ts.map +1 -0
  239. package/dist/examples/error-boundary.js +67 -0
  240. package/dist/examples/error-boundary.js.map +1 -0
  241. package/dist/examples/form-basic-arrow-keys.vitest.d.ts +2 -0
  242. package/dist/examples/form-basic-arrow-keys.vitest.d.ts.map +1 -0
  243. package/dist/examples/form-basic-arrow-keys.vitest.js +46 -0
  244. package/dist/examples/form-basic-arrow-keys.vitest.js.map +1 -0
  245. package/dist/examples/form-basic.d.ts +2 -0
  246. package/dist/examples/form-basic.d.ts.map +1 -0
  247. package/dist/examples/form-basic.js +21 -0
  248. package/dist/examples/form-basic.js.map +1 -0
  249. package/dist/examples/form-basic.vitest.d.ts +2 -0
  250. package/dist/examples/form-basic.vitest.d.ts.map +1 -0
  251. package/dist/examples/form-basic.vitest.js +995 -0
  252. package/dist/examples/form-basic.vitest.js.map +1 -0
  253. package/dist/examples/form-dropdown-with-sections.d.ts +2 -0
  254. package/dist/examples/form-dropdown-with-sections.d.ts.map +1 -0
  255. package/dist/examples/form-dropdown-with-sections.js +13 -0
  256. package/dist/examples/form-dropdown-with-sections.js.map +1 -0
  257. package/dist/examples/form-dropdown-with-sections.vitest.d.ts +2 -0
  258. package/dist/examples/form-dropdown-with-sections.vitest.d.ts.map +1 -0
  259. package/dist/examples/form-dropdown-with-sections.vitest.js +75 -0
  260. package/dist/examples/form-dropdown-with-sections.vitest.js.map +1 -0
  261. package/dist/examples/form-dropdown.d.ts +2 -0
  262. package/dist/examples/form-dropdown.d.ts.map +1 -0
  263. package/dist/examples/form-dropdown.js +13 -0
  264. package/dist/examples/form-dropdown.js.map +1 -0
  265. package/dist/examples/form-dropdown.vitest.d.ts +2 -0
  266. package/dist/examples/form-dropdown.vitest.d.ts.map +1 -0
  267. package/dist/examples/form-dropdown.vitest.js +722 -0
  268. package/dist/examples/form-dropdown.vitest.js.map +1 -0
  269. package/dist/examples/form-multiselect-dropdown.d.ts +2 -0
  270. package/dist/examples/form-multiselect-dropdown.d.ts.map +1 -0
  271. package/dist/examples/form-multiselect-dropdown.js +13 -0
  272. package/dist/examples/form-multiselect-dropdown.js.map +1 -0
  273. package/dist/examples/form-tagpicker.d.ts +2 -0
  274. package/dist/examples/form-tagpicker.d.ts.map +1 -0
  275. package/dist/examples/form-tagpicker.js +13 -0
  276. package/dist/examples/form-tagpicker.js.map +1 -0
  277. package/dist/examples/form-tagpicker.vitest.d.ts +2 -0
  278. package/dist/examples/form-tagpicker.vitest.d.ts.map +1 -0
  279. package/dist/examples/form-tagpicker.vitest.js +491 -0
  280. package/dist/examples/form-tagpicker.vitest.js.map +1 -0
  281. package/dist/examples/internal/descendants-filtering.d.ts +2 -0
  282. package/dist/examples/internal/descendants-filtering.d.ts.map +1 -0
  283. package/dist/examples/internal/descendants-filtering.js +144 -0
  284. package/dist/examples/internal/descendants-filtering.js.map +1 -0
  285. package/dist/examples/internal/descendants.d.ts +2 -0
  286. package/dist/examples/internal/descendants.d.ts.map +1 -0
  287. package/dist/examples/internal/descendants.js +134 -0
  288. package/dist/examples/internal/descendants.js.map +1 -0
  289. package/dist/examples/internal/nested-boxes.d.ts +2 -0
  290. package/dist/examples/internal/nested-boxes.d.ts.map +1 -0
  291. package/dist/examples/internal/nested-boxes.js +7 -0
  292. package/dist/examples/internal/nested-boxes.js.map +1 -0
  293. package/dist/examples/internal/scrollbox-demo.d.ts +2 -0
  294. package/dist/examples/internal/scrollbox-demo.d.ts.map +1 -0
  295. package/dist/examples/internal/scrollbox-demo.js +104 -0
  296. package/dist/examples/internal/scrollbox-demo.js.map +1 -0
  297. package/dist/examples/internal/simple-dialog.d.ts +2 -0
  298. package/dist/examples/internal/simple-dialog.d.ts.map +1 -0
  299. package/dist/examples/internal/simple-dialog.js +43 -0
  300. package/dist/examples/internal/simple-dialog.js.map +1 -0
  301. package/dist/examples/internal/text-stacking.d.ts +2 -0
  302. package/dist/examples/internal/text-stacking.d.ts.map +1 -0
  303. package/dist/examples/internal/text-stacking.js +53 -0
  304. package/dist/examples/internal/text-stacking.js.map +1 -0
  305. package/dist/examples/internal/unicode-square-repro.d.ts +2 -0
  306. package/dist/examples/internal/unicode-square-repro.d.ts.map +1 -0
  307. package/dist/examples/internal/unicode-square-repro.js +7 -0
  308. package/dist/examples/internal/unicode-square-repro.js.map +1 -0
  309. package/dist/examples/list-dropdown-default.d.ts +2 -0
  310. package/dist/examples/list-dropdown-default.d.ts.map +1 -0
  311. package/dist/examples/list-dropdown-default.js +14 -0
  312. package/dist/examples/list-dropdown-default.js.map +1 -0
  313. package/dist/examples/list-dropdown-default.vitest.d.ts +2 -0
  314. package/dist/examples/list-dropdown-default.vitest.d.ts.map +1 -0
  315. package/dist/examples/list-dropdown-default.vitest.js +164 -0
  316. package/dist/examples/list-dropdown-default.vitest.js.map +1 -0
  317. package/dist/examples/list-fetch-data.d.ts +2 -0
  318. package/dist/examples/list-fetch-data.d.ts.map +1 -0
  319. package/dist/examples/list-fetch-data.js +87 -0
  320. package/dist/examples/list-fetch-data.js.map +1 -0
  321. package/dist/examples/list-fetch-data.vitest.d.ts +2 -0
  322. package/dist/examples/list-fetch-data.vitest.d.ts.map +1 -0
  323. package/dist/examples/list-fetch-data.vitest.js +103 -0
  324. package/dist/examples/list-fetch-data.vitest.js.map +1 -0
  325. package/dist/examples/list-filter-navigation.d.ts +2 -0
  326. package/dist/examples/list-filter-navigation.d.ts.map +1 -0
  327. package/dist/examples/list-filter-navigation.js +8 -0
  328. package/dist/examples/list-filter-navigation.js.map +1 -0
  329. package/dist/examples/list-with-detail.d.ts +2 -0
  330. package/dist/examples/list-with-detail.d.ts.map +1 -0
  331. package/dist/examples/list-with-detail.js +94 -0
  332. package/dist/examples/list-with-detail.js.map +1 -0
  333. package/dist/examples/list-with-detail.vitest.d.ts +2 -0
  334. package/dist/examples/list-with-detail.vitest.d.ts.map +1 -0
  335. package/dist/examples/list-with-detail.vitest.js +438 -0
  336. package/dist/examples/list-with-detail.vitest.js.map +1 -0
  337. package/dist/examples/list-with-dropdown.d.ts +2 -0
  338. package/dist/examples/list-with-dropdown.d.ts.map +1 -0
  339. package/dist/examples/list-with-dropdown.js +43 -0
  340. package/dist/examples/list-with-dropdown.js.map +1 -0
  341. package/dist/examples/list-with-dropdown.vitest.d.ts +2 -0
  342. package/dist/examples/list-with-dropdown.vitest.d.ts.map +1 -0
  343. package/dist/examples/list-with-dropdown.vitest.js +297 -0
  344. package/dist/examples/list-with-dropdown.vitest.js.map +1 -0
  345. package/dist/examples/list-with-sections.d.ts +2 -0
  346. package/dist/examples/list-with-sections.d.ts.map +1 -0
  347. package/dist/examples/list-with-sections.js +67 -0
  348. package/dist/examples/list-with-sections.js.map +1 -0
  349. package/dist/examples/list-with-sections.vitest.d.ts +2 -0
  350. package/dist/examples/list-with-sections.vitest.d.ts.map +1 -0
  351. package/dist/examples/list-with-sections.vitest.js +441 -0
  352. package/dist/examples/list-with-sections.vitest.js.map +1 -0
  353. package/dist/examples/miscellaneous.d.ts +2 -0
  354. package/dist/examples/miscellaneous.d.ts.map +1 -0
  355. package/dist/examples/miscellaneous.js +313 -0
  356. package/dist/examples/miscellaneous.js.map +1 -0
  357. package/dist/examples/nested-navigation.d.ts +2 -0
  358. package/dist/examples/nested-navigation.d.ts.map +1 -0
  359. package/dist/examples/nested-navigation.js +35 -0
  360. package/dist/examples/nested-navigation.js.map +1 -0
  361. package/dist/examples/preferences-test.d.ts +2 -0
  362. package/dist/examples/preferences-test.d.ts.map +1 -0
  363. package/dist/examples/preferences-test.js +43 -0
  364. package/dist/examples/preferences-test.js.map +1 -0
  365. package/dist/examples/simple-dropdown.d.ts +2 -0
  366. package/dist/examples/simple-dropdown.d.ts.map +1 -0
  367. package/dist/examples/simple-dropdown.js +15 -0
  368. package/dist/examples/simple-dropdown.js.map +1 -0
  369. package/dist/examples/simple-file-picker.d.ts +2 -0
  370. package/dist/examples/simple-file-picker.d.ts.map +1 -0
  371. package/dist/examples/simple-file-picker.js +21 -0
  372. package/dist/examples/simple-file-picker.js.map +1 -0
  373. package/dist/examples/simple-file-picker.vitest.d.ts +2 -0
  374. package/dist/examples/simple-file-picker.vitest.d.ts.map +1 -0
  375. package/dist/examples/simple-file-picker.vitest.js +277 -0
  376. package/dist/examples/simple-file-picker.vitest.js.map +1 -0
  377. package/dist/examples/simple-grid.d.ts +2 -0
  378. package/dist/examples/simple-grid.d.ts.map +1 -0
  379. package/dist/examples/simple-grid.js +51 -0
  380. package/dist/examples/simple-grid.js.map +1 -0
  381. package/dist/examples/simple-grid.vitest.d.ts +2 -0
  382. package/dist/examples/simple-grid.vitest.d.ts.map +1 -0
  383. package/dist/examples/simple-grid.vitest.js +498 -0
  384. package/dist/examples/simple-grid.vitest.js.map +1 -0
  385. package/dist/examples/simple-hud.d.ts +2 -0
  386. package/dist/examples/simple-hud.d.ts.map +1 -0
  387. package/dist/examples/simple-hud.js +18 -0
  388. package/dist/examples/simple-hud.js.map +1 -0
  389. package/dist/examples/simple-list-search.d.ts +2 -0
  390. package/dist/examples/simple-list-search.d.ts.map +1 -0
  391. package/dist/examples/simple-list-search.js +26 -0
  392. package/dist/examples/simple-list-search.js.map +1 -0
  393. package/dist/examples/simple-list.d.ts +2 -0
  394. package/dist/examples/simple-list.d.ts.map +1 -0
  395. package/dist/examples/simple-list.js +50 -0
  396. package/dist/examples/simple-list.js.map +1 -0
  397. package/dist/examples/simple-navigation.d.ts +2 -0
  398. package/dist/examples/simple-navigation.d.ts.map +1 -0
  399. package/dist/examples/simple-navigation.js +36 -0
  400. package/dist/examples/simple-navigation.js.map +1 -0
  401. package/dist/examples/simple-navigation.vitest.d.ts +2 -0
  402. package/dist/examples/simple-navigation.vitest.d.ts.map +1 -0
  403. package/dist/examples/simple-navigation.vitest.js +522 -0
  404. package/dist/examples/simple-navigation.vitest.js.map +1 -0
  405. package/dist/examples/store.d.ts +2 -0
  406. package/dist/examples/store.d.ts.map +1 -0
  407. package/dist/examples/store.js +5 -0
  408. package/dist/examples/store.js.map +1 -0
  409. package/dist/examples/store.vitest.d.ts +2 -0
  410. package/dist/examples/store.vitest.d.ts.map +1 -0
  411. package/dist/examples/store.vitest.js +52 -0
  412. package/dist/examples/store.vitest.js.map +1 -0
  413. package/dist/examples/tanstack-demo.d.ts +2 -0
  414. package/dist/examples/tanstack-demo.d.ts.map +1 -0
  415. package/dist/examples/tanstack-demo.js +51 -0
  416. package/dist/examples/tanstack-demo.js.map +1 -0
  417. package/dist/examples/use-promise-demo.d.ts +2 -0
  418. package/dist/examples/use-promise-demo.d.ts.map +1 -0
  419. package/dist/examples/use-promise-demo.js +45 -0
  420. package/dist/examples/use-promise-demo.js.map +1 -0
  421. package/dist/extensions/dev.d.ts +7 -0
  422. package/dist/extensions/dev.d.ts.map +1 -0
  423. package/dist/extensions/dev.js +124 -0
  424. package/dist/extensions/dev.js.map +1 -0
  425. package/dist/extensions/home.d.ts +8 -0
  426. package/dist/extensions/home.d.ts.map +1 -0
  427. package/dist/extensions/home.js +184 -0
  428. package/dist/extensions/home.js.map +1 -0
  429. package/dist/extensions/store.d.ts +6 -0
  430. package/dist/extensions/store.d.ts.map +1 -0
  431. package/dist/extensions/store.js +203 -0
  432. package/dist/extensions/store.js.map +1 -0
  433. package/dist/globals.d.ts +9 -0
  434. package/dist/globals.d.ts.map +1 -0
  435. package/dist/globals.js +21 -0
  436. package/dist/globals.js.map +1 -0
  437. package/dist/home-command.d.ts +8 -0
  438. package/dist/home-command.d.ts.map +1 -0
  439. package/dist/home-command.js +181 -0
  440. package/dist/home-command.js.map +1 -0
  441. package/dist/hooks/hooks.test.d.ts +2 -0
  442. package/dist/hooks/hooks.test.d.ts.map +1 -0
  443. package/dist/hooks/hooks.test.js +37 -0
  444. package/dist/hooks/hooks.test.js.map +1 -0
  445. package/dist/hooks/index.d.ts +6 -0
  446. package/dist/hooks/index.d.ts.map +1 -0
  447. package/dist/hooks/index.js +6 -0
  448. package/dist/hooks/index.js.map +1 -0
  449. package/dist/hooks/use-action-panel.d.ts +16 -0
  450. package/dist/hooks/use-action-panel.d.ts.map +1 -0
  451. package/dist/hooks/use-action-panel.js +19 -0
  452. package/dist/hooks/use-action-panel.js.map +1 -0
  453. package/dist/hooks/use-id.d.ts +9 -0
  454. package/dist/hooks/use-id.d.ts.map +1 -0
  455. package/dist/hooks/use-id.js +17 -0
  456. package/dist/hooks/use-id.js.map +1 -0
  457. package/dist/hooks/use-unstable-ai.d.ts +9 -0
  458. package/dist/hooks/use-unstable-ai.d.ts.map +1 -0
  459. package/dist/hooks/use-unstable-ai.js +13 -0
  460. package/dist/hooks/use-unstable-ai.js.map +1 -0
  461. package/dist/hooks.d.ts +10 -0
  462. package/dist/hooks.d.ts.map +1 -0
  463. package/dist/hooks.js +20 -0
  464. package/dist/hooks.js.map +1 -0
  465. package/dist/hover-repro.d.ts +2 -0
  466. package/dist/hover-repro.d.ts.map +1 -0
  467. package/dist/hover-repro.js +20 -0
  468. package/dist/hover-repro.js.map +1 -0
  469. package/dist/index.d.ts +58 -0
  470. package/dist/index.d.ts.map +1 -0
  471. package/dist/index.js +71 -0
  472. package/dist/index.js.map +1 -0
  473. package/dist/internal/date-picker-widget.d.ts +9 -0
  474. package/dist/internal/date-picker-widget.d.ts.map +1 -0
  475. package/dist/internal/date-picker-widget.js +380 -0
  476. package/dist/internal/date-picker-widget.js.map +1 -0
  477. package/dist/internal/dialog.d.ts +21 -0
  478. package/dist/internal/dialog.d.ts.map +1 -0
  479. package/dist/internal/dialog.js +122 -0
  480. package/dist/internal/dialog.js.map +1 -0
  481. package/dist/internal/error-handler.d.ts +2 -0
  482. package/dist/internal/error-handler.d.ts.map +1 -0
  483. package/dist/internal/error-handler.js +29 -0
  484. package/dist/internal/error-handler.js.map +1 -0
  485. package/dist/internal/focus-context.d.ts +10 -0
  486. package/dist/internal/focus-context.d.ts.map +1 -0
  487. package/dist/internal/focus-context.js +12 -0
  488. package/dist/internal/focus-context.js.map +1 -0
  489. package/dist/internal/navigation.d.ts +18 -0
  490. package/dist/internal/navigation.d.ts.map +1 -0
  491. package/dist/internal/navigation.js +83 -0
  492. package/dist/internal/navigation.js.map +1 -0
  493. package/dist/internal/providers.d.ts +8 -0
  494. package/dist/internal/providers.d.ts.map +1 -0
  495. package/dist/internal/providers.js +262 -0
  496. package/dist/internal/providers.js.map +1 -0
  497. package/dist/localstorage.d.ts +13 -0
  498. package/dist/localstorage.d.ts.map +1 -0
  499. package/dist/localstorage.js +190 -0
  500. package/dist/localstorage.js.map +1 -0
  501. package/dist/localstorage.test.d.ts +2 -0
  502. package/dist/localstorage.test.d.ts.map +1 -0
  503. package/dist/localstorage.test.js +131 -0
  504. package/dist/localstorage.test.js.map +1 -0
  505. package/dist/logger.d.ts +7 -0
  506. package/dist/logger.d.ts.map +1 -0
  507. package/dist/logger.js +70 -0
  508. package/dist/logger.js.map +1 -0
  509. package/dist/oauth.d.ts +142 -0
  510. package/dist/oauth.d.ts.map +1 -0
  511. package/dist/oauth.js +551 -0
  512. package/dist/oauth.js.map +1 -0
  513. package/dist/package-json.d.ts +84 -0
  514. package/dist/package-json.d.ts.map +1 -0
  515. package/dist/package-json.js +77 -0
  516. package/dist/package-json.js.map +1 -0
  517. package/dist/preferences.d.ts +23 -0
  518. package/dist/preferences.d.ts.map +1 -0
  519. package/dist/preferences.js +105 -0
  520. package/dist/preferences.js.map +1 -0
  521. package/dist/preload.d.ts +2 -0
  522. package/dist/preload.d.ts.map +1 -0
  523. package/dist/preload.js +28 -0
  524. package/dist/preload.js.map +1 -0
  525. package/dist/state.d.ts +26 -0
  526. package/dist/state.d.ts.map +1 -0
  527. package/dist/state.js +18 -0
  528. package/dist/state.js.map +1 -0
  529. package/dist/store-api/download.d.ts +8 -0
  530. package/dist/store-api/download.d.ts.map +1 -0
  531. package/dist/store-api/download.js +37 -0
  532. package/dist/store-api/download.js.map +1 -0
  533. package/dist/store-api/download.test.d.ts +2 -0
  534. package/dist/store-api/download.test.d.ts.map +1 -0
  535. package/dist/store-api/download.test.js +36 -0
  536. package/dist/store-api/download.test.js.map +1 -0
  537. package/dist/store-api/extension.d.ts +87 -0
  538. package/dist/store-api/extension.d.ts.map +1 -0
  539. package/dist/store-api/extension.js +23 -0
  540. package/dist/store-api/extension.js.map +1 -0
  541. package/dist/store-api/extension.test.d.ts +2 -0
  542. package/dist/store-api/extension.test.d.ts.map +1 -0
  543. package/dist/store-api/extension.test.js +22 -0
  544. package/dist/store-api/extension.test.js.map +1 -0
  545. package/dist/store-api/search.d.ts +101 -0
  546. package/dist/store-api/search.d.ts.map +1 -0
  547. package/dist/store-api/search.js +29 -0
  548. package/dist/store-api/search.js.map +1 -0
  549. package/dist/store-api/search.test.d.ts +2 -0
  550. package/dist/store-api/search.test.d.ts.map +1 -0
  551. package/dist/store-api/search.test.js +45 -0
  552. package/dist/store-api/search.test.js.map +1 -0
  553. package/dist/store.d.ts +21 -0
  554. package/dist/store.d.ts.map +1 -0
  555. package/dist/store.js +84 -0
  556. package/dist/store.js.map +1 -0
  557. package/dist/theme.d.ts +20 -0
  558. package/dist/theme.d.ts.map +1 -0
  559. package/dist/theme.js +26 -0
  560. package/dist/theme.js.map +1 -0
  561. package/dist/toast.d.ts +44 -0
  562. package/dist/toast.d.ts.map +1 -0
  563. package/dist/toast.js +221 -0
  564. package/dist/toast.js.map +1 -0
  565. package/dist/utils/file-system.d.ts +11 -0
  566. package/dist/utils/file-system.d.ts.map +1 -0
  567. package/dist/utils/file-system.js +66 -0
  568. package/dist/utils/file-system.js.map +1 -0
  569. package/dist/utils.d.ts +234 -0
  570. package/dist/utils.d.ts.map +1 -0
  571. package/dist/utils.js +473 -0
  572. package/dist/utils.js.map +1 -0
  573. package/dist/utils.test.d.ts +2 -0
  574. package/dist/utils.test.d.ts.map +1 -0
  575. package/dist/utils.test.js +152 -0
  576. package/dist/utils.test.js.map +1 -0
  577. package/dist/window.d.ts +12 -0
  578. package/dist/window.d.ts.map +1 -0
  579. package/dist/window.js +48 -0
  580. package/dist/window.js.map +1 -0
  581. package/package.json +56 -0
  582. package/src/action-utils.tsx +207 -0
  583. package/src/apis/ai.tsx +177 -0
  584. package/src/apis/cache.test.ts +311 -0
  585. package/src/apis/cache.tsx +394 -0
  586. package/src/apis/clipboard.tsx +200 -0
  587. package/src/apis/environment.tsx +239 -0
  588. package/src/apis/hud.tsx +86 -0
  589. package/src/apis/localstorage.test.ts +164 -0
  590. package/src/apis/localstorage.tsx +215 -0
  591. package/src/apis/oauth.tsx +744 -0
  592. package/src/apis/preferences.tsx +140 -0
  593. package/src/apis/toast.tsx +388 -0
  594. package/src/apis/window.tsx +61 -0
  595. package/src/build.test.tsx +78 -0
  596. package/src/build.tsx +273 -0
  597. package/src/cli.tsx +328 -0
  598. package/src/colors.tsx +15 -0
  599. package/src/components/actions.tsx +718 -0
  600. package/src/components/alert.tsx +205 -0
  601. package/src/components/detail.tsx +359 -0
  602. package/src/components/dropdown.tsx +438 -0
  603. package/src/components/extension-preferences.tsx +269 -0
  604. package/src/components/form/assign-components.tsx +22 -0
  605. package/src/components/form/checkbox.tsx +96 -0
  606. package/src/components/form/date-picker.tsx +125 -0
  607. package/src/components/form/description.tsx +30 -0
  608. package/src/components/form/dropdown.tsx +512 -0
  609. package/src/components/form/file-autocomplete.tsx +141 -0
  610. package/src/components/form/file-picker.tsx +233 -0
  611. package/src/components/form/form-end.tsx +6 -0
  612. package/src/components/form/index.tsx +242 -0
  613. package/src/components/form/password-field.tsx +87 -0
  614. package/src/components/form/separator.tsx +15 -0
  615. package/src/components/form/tagpicker.tsx +245 -0
  616. package/src/components/form/text-area.tsx +82 -0
  617. package/src/components/form/text-field.tsx +82 -0
  618. package/src/components/form/types.tsx +49 -0
  619. package/src/components/form/use-form-navigation.tsx +65 -0
  620. package/src/components/form/with-left-border.tsx +53 -0
  621. package/src/components/icon.tsx +496 -0
  622. package/src/components/image.tsx +54 -0
  623. package/src/components/list.tsx +1564 -0
  624. package/src/components/loading-bar.tsx +141 -0
  625. package/src/components/menubar-extra.tsx +181 -0
  626. package/src/descendants.tsx +134 -0
  627. package/src/e2e-node.tsx +303 -0
  628. package/src/e2e.tsx +147 -0
  629. package/src/examples/action-show-in-finder.tsx +80 -0
  630. package/src/examples/environment-test.tsx +50 -0
  631. package/src/examples/error-boundary.tsx +217 -0
  632. package/src/examples/form-basic.tsx +122 -0
  633. package/src/examples/form-basic.vitest.tsx +1035 -0
  634. package/src/examples/form-dropdown.tsx +102 -0
  635. package/src/examples/form-dropdown.vitest.tsx +758 -0
  636. package/src/examples/form-tagpicker.tsx +66 -0
  637. package/src/examples/form-tagpicker.vitest.tsx +523 -0
  638. package/src/examples/internal/descendants-filtering.tsx +223 -0
  639. package/src/examples/internal/descendants.tsx +208 -0
  640. package/src/examples/internal/scrollbox-demo.tsx +149 -0
  641. package/src/examples/internal/simple-dialog.tsx +124 -0
  642. package/src/examples/internal/text-stacking.tsx +90 -0
  643. package/src/examples/list-dropdown-default.tsx +69 -0
  644. package/src/examples/list-dropdown-default.vitest.tsx +187 -0
  645. package/src/examples/list-fetch-data.tsx +123 -0
  646. package/src/examples/list-fetch-data.vitest.tsx +110 -0
  647. package/src/examples/list-with-detail.tsx +161 -0
  648. package/src/examples/list-with-detail.vitest.tsx +468 -0
  649. package/src/examples/list-with-dropdown.tsx +97 -0
  650. package/src/examples/list-with-dropdown.vitest.tsx +324 -0
  651. package/src/examples/list-with-sections.tsx +196 -0
  652. package/src/examples/list-with-sections.vitest.tsx +479 -0
  653. package/src/examples/miscellaneous.tsx +780 -0
  654. package/src/examples/nested-navigation.tsx +118 -0
  655. package/src/examples/preferences-test.tsx +82 -0
  656. package/src/examples/simple-dropdown.tsx +95 -0
  657. package/src/examples/simple-file-picker.tsx +75 -0
  658. package/src/examples/simple-file-picker.vitest.tsx +306 -0
  659. package/src/examples/simple-grid.tsx +149 -0
  660. package/src/examples/simple-grid.vitest.tsx +535 -0
  661. package/src/examples/simple-hud.tsx +60 -0
  662. package/src/examples/simple-list-search.tsx +93 -0
  663. package/src/examples/simple-list.tsx +149 -0
  664. package/src/examples/simple-navigation.tsx +89 -0
  665. package/src/examples/simple-navigation.vitest.tsx +571 -0
  666. package/src/examples/store.tsx +4 -0
  667. package/src/examples/store.vitest.tsx +59 -0
  668. package/src/examples/tanstack-demo.tsx +104 -0
  669. package/src/examples/use-promise-demo.tsx +96 -0
  670. package/src/extensions/dev.tsx +215 -0
  671. package/src/extensions/home.tsx +332 -0
  672. package/src/extensions/store.tsx +375 -0
  673. package/src/globals.ts +34 -0
  674. package/src/hooks/index.tsx +8 -0
  675. package/src/hooks/use-action-panel.tsx +28 -0
  676. package/src/hooks/use-id.tsx +19 -0
  677. package/src/hooks/use-unstable-ai.tsx +15 -0
  678. package/src/hooks.tsx +22 -0
  679. package/src/index.tsx +240 -0
  680. package/src/internal/date-picker-widget.tsx +500 -0
  681. package/src/internal/dialog.tsx +202 -0
  682. package/src/internal/error-handler.tsx +32 -0
  683. package/src/internal/focus-context.tsx +23 -0
  684. package/src/internal/navigation.tsx +149 -0
  685. package/src/internal/providers.tsx +430 -0
  686. package/src/logger.tsx +84 -0
  687. package/src/package-json.tsx +197 -0
  688. package/src/preload.tsx +32 -0
  689. package/src/state.tsx +49 -0
  690. package/src/store-api/download.test.tsx +38 -0
  691. package/src/store-api/download.tsx +52 -0
  692. package/src/store-api/extension.test.tsx +24 -0
  693. package/src/store-api/extension.tsx +123 -0
  694. package/src/store-api/search.test.tsx +50 -0
  695. package/src/store-api/search.tsx +146 -0
  696. package/src/theme.tsx +31 -0
  697. package/src/utils/file-system.ts +87 -0
  698. package/src/utils.test.tsx +204 -0
  699. package/src/utils.tsx +657 -0
@@ -0,0 +1,311 @@
1
+ import { describe, test, expect, beforeEach, afterAll, jest } from 'bun:test'
2
+ import { Cache } from './cache'
3
+ import * as os from 'os'
4
+ import * as path from 'path'
5
+ import * as fs from 'fs'
6
+
7
+ describe('Cache', () => {
8
+ let cache: Cache
9
+
10
+ beforeEach(() => {
11
+ cache = new Cache({ namespace: `test-${Date.now()}-${Math.random()}` })
12
+ })
13
+
14
+ afterAll(() => {
15
+ // Optional: Clean up test databases after all tests
16
+ // const testDbPattern = path.join(os.homedir(), '.termcast-cache*.db')
17
+ // You could implement cleanup here if needed
18
+ })
19
+
20
+ describe('constructor', () => {
21
+ test('creates cache with default capacity', () => {
22
+ const cache = new Cache()
23
+ expect(Cache.DEFAULT_CAPACITY).toBe(10 * 1024 * 1024)
24
+ })
25
+
26
+ test('creates cache with custom capacity', () => {
27
+ const cache = new Cache({ capacity: 1024 })
28
+ expect(cache).toBeDefined()
29
+ })
30
+
31
+ test('creates cache with namespace', () => {
32
+ const cache = new Cache({ namespace: 'test-namespace' })
33
+ expect(cache.storageDirectory).toContain('test-namespace')
34
+ })
35
+ })
36
+
37
+ describe('get and set', () => {
38
+ test('stores and retrieves data', () => {
39
+ cache.set('key1', 'value1')
40
+ const result = cache.get('key1')
41
+ expect(result).toBe('value1')
42
+ })
43
+
44
+ test('returns undefined for non-existent key', () => {
45
+ const result = cache.get('non-existent')
46
+ expect(result).toBeUndefined()
47
+ })
48
+
49
+ test('overwrites existing values', () => {
50
+ cache.set('key', 'initial')
51
+ cache.set('key', 'updated')
52
+ const result = cache.get('key')
53
+ expect(result).toBe('updated')
54
+ })
55
+
56
+ test('stores JSON stringified data', () => {
57
+ const data = { items: ['a', 'b', 'c'], count: 3 }
58
+ cache.set('json-data', JSON.stringify(data))
59
+ const result = cache.get('json-data')
60
+ expect(JSON.parse(result!)).toEqual(data)
61
+ })
62
+ })
63
+
64
+ describe('has', () => {
65
+ test('returns true for existing key', () => {
66
+ cache.set('exists', 'value')
67
+ expect(cache.has('exists')).toBe(true)
68
+ })
69
+
70
+ test('returns false for non-existent key', () => {
71
+ expect(cache.has('non-existent')).toBe(false)
72
+ })
73
+
74
+ test('does not affect LRU order', () => {
75
+ cache.set('key1', 'value1')
76
+ cache.set('key2', 'value2')
77
+
78
+ // has() should not affect LRU, so key1 is still oldest
79
+ cache.has('key1')
80
+ cache.has('key1')
81
+ cache.has('key1')
82
+
83
+ // Add more data to potentially trigger eviction
84
+ // key1 should still be first to be evicted since has() doesn't update LRU
85
+ expect(cache.has('key1')).toBe(true)
86
+ })
87
+ })
88
+
89
+ describe('isEmpty', () => {
90
+ test('returns true for empty cache', () => {
91
+ expect(cache.isEmpty).toBe(true)
92
+ })
93
+
94
+ test('returns false when cache has data', () => {
95
+ cache.set('key', 'value')
96
+ expect(cache.isEmpty).toBe(false)
97
+ })
98
+
99
+ test('returns true after clearing cache', () => {
100
+ cache.set('key', 'value')
101
+ cache.clear()
102
+ expect(cache.isEmpty).toBe(true)
103
+ })
104
+ })
105
+
106
+ describe('remove', () => {
107
+ test('removes existing key', () => {
108
+ cache.set('to-remove', 'value')
109
+ const removed = cache.remove('to-remove')
110
+ expect(removed).toBe(true)
111
+ expect(cache.get('to-remove')).toBeUndefined()
112
+ })
113
+
114
+ test('returns false when removing non-existent key', () => {
115
+ const removed = cache.remove('non-existent')
116
+ expect(removed).toBe(false)
117
+ })
118
+ })
119
+
120
+ describe('clear', () => {
121
+ test('removes all cached data', () => {
122
+ cache.set('key1', 'value1')
123
+ cache.set('key2', 'value2')
124
+ cache.set('key3', 'value3')
125
+
126
+ cache.clear()
127
+
128
+ expect(cache.get('key1')).toBeUndefined()
129
+ expect(cache.get('key2')).toBeUndefined()
130
+ expect(cache.get('key3')).toBeUndefined()
131
+ expect(cache.isEmpty).toBe(true)
132
+ })
133
+ })
134
+
135
+ describe('subscribe', () => {
136
+ test('notifies subscriber on set', () => {
137
+ const subscriber = jest.fn()
138
+ cache.subscribe(subscriber)
139
+
140
+ cache.set('key', 'value')
141
+
142
+ expect(subscriber).toHaveBeenCalledWith('key', 'value')
143
+ })
144
+
145
+ test('notifies subscriber on remove', () => {
146
+ const subscriber = jest.fn()
147
+ cache.set('key', 'value')
148
+ cache.subscribe(subscriber)
149
+
150
+ cache.remove('key')
151
+
152
+ expect(subscriber).toHaveBeenCalledWith('key', undefined)
153
+ })
154
+
155
+ test('notifies subscriber on clear', () => {
156
+ const subscriber = jest.fn()
157
+ cache.set('key', 'value')
158
+ cache.subscribe(subscriber)
159
+
160
+ cache.clear()
161
+
162
+ expect(subscriber).toHaveBeenCalledWith(undefined, undefined)
163
+ })
164
+
165
+ test('does not notify when clear called with notifySubscribers: false', () => {
166
+ const subscriber = jest.fn()
167
+ cache.set('key', 'value')
168
+ cache.subscribe(subscriber)
169
+
170
+ cache.clear({ notifySubscribers: false })
171
+
172
+ expect(subscriber).not.toHaveBeenCalled()
173
+ })
174
+
175
+ test('unsubscribe stops notifications', () => {
176
+ const subscriber = jest.fn()
177
+ const unsubscribe = cache.subscribe(subscriber)
178
+
179
+ cache.set('key1', 'value1')
180
+ expect(subscriber).toHaveBeenCalledTimes(1)
181
+
182
+ unsubscribe()
183
+
184
+ cache.set('key2', 'value2')
185
+ expect(subscriber).toHaveBeenCalledTimes(1) // Still 1, not called again
186
+ })
187
+
188
+ test('handles multiple subscribers', () => {
189
+ const subscriber1 = jest.fn()
190
+ const subscriber2 = jest.fn()
191
+
192
+ cache.subscribe(subscriber1)
193
+ cache.subscribe(subscriber2)
194
+
195
+ cache.set('key', 'value')
196
+
197
+ expect(subscriber1).toHaveBeenCalledWith('key', 'value')
198
+ expect(subscriber2).toHaveBeenCalledWith('key', 'value')
199
+ })
200
+
201
+ test('handles subscriber errors gracefully', () => {
202
+ const errorSubscriber = jest.fn(() => {
203
+ throw new Error('Subscriber error')
204
+ })
205
+ const normalSubscriber = jest.fn()
206
+
207
+ cache.subscribe(errorSubscriber)
208
+ cache.subscribe(normalSubscriber)
209
+
210
+ // Should not throw, and normal subscriber should still be called
211
+ expect(() => cache.set('key', 'value')).not.toThrow()
212
+ expect(normalSubscriber).toHaveBeenCalledWith('key', 'value')
213
+ })
214
+ })
215
+
216
+ describe('capacity management', () => {
217
+ test('evicts least recently used items when capacity exceeded', () => {
218
+ const smallCache = new Cache({
219
+ capacity: 100,
220
+ namespace: `capacity-test-${Date.now()}`,
221
+ })
222
+
223
+ // Add items that together exceed capacity
224
+ smallCache.set('old', 'x'.repeat(40))
225
+ smallCache.set('medium', 'y'.repeat(40))
226
+ smallCache.set('new', 'z'.repeat(40)) // This should trigger eviction
227
+
228
+ // Old item should be evicted
229
+ expect(smallCache.get('old')).toBeUndefined()
230
+ expect(smallCache.get('medium')).toBe('y'.repeat(40))
231
+ expect(smallCache.get('new')).toBe('z'.repeat(40))
232
+ })
233
+
234
+ test('updates LRU order on get', () => {
235
+ const smallCache = new Cache({
236
+ capacity: 100,
237
+ namespace: `lru-test-${Date.now()}`,
238
+ })
239
+
240
+ smallCache.set('first', 'x'.repeat(30))
241
+ smallCache.set('second', 'y'.repeat(30))
242
+
243
+ // Access first item to make it more recent
244
+ smallCache.get('first')
245
+
246
+ // Add new item that triggers eviction
247
+ smallCache.set('third', 'z'.repeat(50))
248
+
249
+ // Second should be evicted, not first (because we accessed first after second)
250
+ expect(smallCache.get('first')).toBe('x'.repeat(30))
251
+ expect(smallCache.get('second')).toBeUndefined()
252
+ expect(smallCache.get('third')).toBe('z'.repeat(50))
253
+ })
254
+ })
255
+
256
+ describe('edge cases', () => {
257
+ test('handles empty string data', () => {
258
+ cache.set('empty', '')
259
+ expect(cache.get('empty')).toBe('')
260
+ })
261
+
262
+ test('handles large data', () => {
263
+ const largeData = 'x'.repeat(10000)
264
+ cache.set('large', largeData)
265
+ expect(cache.get('large')).toBe(largeData)
266
+ })
267
+
268
+ test('handles special characters in keys', () => {
269
+ const specialKey = 'key-!@#$%^&*()_+={}[]|\\:";\'<>?,./with spaces'
270
+ cache.set(specialKey, 'value')
271
+ expect(cache.get(specialKey)).toBe('value')
272
+ })
273
+
274
+ test('handles special characters in data', () => {
275
+ const specialData = 'data with !@#$%^&*()_+={}[]|\\:";\'<>?,./\n\t\r'
276
+ cache.set('key', specialData)
277
+ expect(cache.get('key')).toBe(specialData)
278
+ })
279
+
280
+ test('handles unicode data', () => {
281
+ const unicodeData = '测试数据 🎉 𝓗𝓮𝓵𝓵𝓸'
282
+ cache.set('unicode', unicodeData)
283
+ expect(cache.get('unicode')).toBe(unicodeData)
284
+ })
285
+ })
286
+
287
+ describe('storageDirectory', () => {
288
+ test('returns default directory without namespace', () => {
289
+ const cache = new Cache()
290
+ expect(cache.storageDirectory).toContain('.termcast-bundle')
291
+ expect(cache.storageDirectory).toContain('cache')
292
+ })
293
+
294
+ test('returns namespaced directory with namespace', () => {
295
+ const cache = new Cache({ namespace: 'my-command' })
296
+ expect(cache.storageDirectory).toContain('.termcast-bundle')
297
+ expect(cache.storageDirectory).toContain('cache')
298
+ expect(cache.storageDirectory).toContain('my-command')
299
+ })
300
+ })
301
+
302
+ describe('static properties', () => {
303
+ test('STORAGE_DIRECTORY_NAME is correct', () => {
304
+ expect(Cache.STORAGE_DIRECTORY_NAME).toBe('.termcast-cache')
305
+ })
306
+
307
+ test('DEFAULT_CAPACITY is 10MB', () => {
308
+ expect(Cache.DEFAULT_CAPACITY).toBe(10 * 1024 * 1024)
309
+ })
310
+ })
311
+ })
@@ -0,0 +1,394 @@
1
+ import { Database } from 'bun:sqlite'
2
+ import * as path from 'path'
3
+ import * as os from 'os'
4
+ import * as fs from 'fs'
5
+ import { logger } from '../logger'
6
+ import { useStore } from '../state'
7
+
8
+ function getCurrentDatabasePath(): string {
9
+ const extensionPath = useStore.getState().extensionPath
10
+
11
+ if (extensionPath) {
12
+ // Use same shared database as localstorage
13
+ return path.join(extensionPath, '.termcast-bundle', 'data.db')
14
+ } else {
15
+ return path.join(os.homedir(), '.termcast', '.termcast-bundle', 'data.db')
16
+ }
17
+ }
18
+
19
+ function getCurrentCacheDir(namespace?: string): string {
20
+ const extensionPath = useStore.getState().extensionPath
21
+
22
+ if (extensionPath) {
23
+ return namespace
24
+ ? path.join(extensionPath, '.termcast-bundle', 'cache', namespace)
25
+ : path.join(extensionPath, '.termcast-bundle', 'cache')
26
+ } else {
27
+ return namespace
28
+ ? path.join(
29
+ os.homedir(),
30
+ '.termcast',
31
+ '.termcast-bundle',
32
+ 'cache',
33
+ namespace,
34
+ )
35
+ : path.join(os.homedir(), '.termcast', '.termcast-bundle', 'cache')
36
+ }
37
+ }
38
+
39
+ export class Cache {
40
+ static get STORAGE_DIRECTORY_NAME(): string {
41
+ const extensionPath = useStore.getState().extensionPath
42
+ return extensionPath ? 'cache' : '.termcast-cache'
43
+ }
44
+
45
+ static get DEFAULT_CAPACITY(): number {
46
+ return 10 * 1024 * 1024 // 10 MB
47
+ }
48
+
49
+ private db: Database
50
+ private capacity: number
51
+ private namespace?: string
52
+ private tableName: string
53
+ private subscribers: Cache.Subscriber[] = []
54
+ private currentSize: number = 0
55
+
56
+ constructor(options?: Cache.Options) {
57
+ this.capacity = options?.capacity || Cache.DEFAULT_CAPACITY
58
+ this.namespace = options?.namespace
59
+ // Replace non-alphanumeric characters with underscores for valid SQL table names
60
+ const safeNamespace = this.namespace?.replace(/[^a-zA-Z0-9]/g, '_')
61
+ this.tableName = safeNamespace ? `cache_${safeNamespace}` : 'cache'
62
+
63
+ const dbPath = getCurrentDatabasePath()
64
+
65
+ // Ensure parent directory exists
66
+ const dbDir = path.dirname(dbPath)
67
+ if (!fs.existsSync(dbDir)) {
68
+ fs.mkdirSync(dbDir, { recursive: true })
69
+ }
70
+
71
+ // Open with options to reduce file usage
72
+ this.db = new Database(dbPath, {
73
+ create: true,
74
+ readwrite: true,
75
+ })
76
+
77
+ // Use WAL mode and optimize for single file usage
78
+ this.db.exec('PRAGMA journal_mode = WAL')
79
+ this.db.exec('PRAGMA wal_autocheckpoint = 1000')
80
+ this.db.exec('PRAGMA synchronous = NORMAL')
81
+
82
+ // Use rowid for ordering - it auto-increments and provides natural LRU order
83
+ this.db.exec(`
84
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
85
+ rowid INTEGER PRIMARY KEY AUTOINCREMENT,
86
+ key TEXT UNIQUE NOT NULL,
87
+ data TEXT NOT NULL,
88
+ size INTEGER NOT NULL
89
+ )
90
+ `)
91
+
92
+ // Create index on key for fast lookups
93
+ this.db.exec(`
94
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_key ON ${this.tableName}(key)
95
+ `)
96
+
97
+ // Calculate initial size
98
+ const row = this.db
99
+ .prepare(`SELECT SUM(size) as total FROM ${this.tableName}`)
100
+ .get() as { total: number | null } | undefined
101
+ this.currentSize = row?.total || 0
102
+
103
+ // Bind all methods to this instance
104
+ this.get = this.get.bind(this)
105
+ this.has = this.has.bind(this)
106
+ this.set = this.set.bind(this)
107
+ this.remove = this.remove.bind(this)
108
+ this.clear = this.clear.bind(this)
109
+ this.subscribe = this.subscribe.bind(this)
110
+ this.maintainCapacity = this.maintainCapacity.bind(this)
111
+ this.notifySubscribers = this.notifySubscribers.bind(this)
112
+ }
113
+
114
+ get storageDirectory(): string {
115
+ return getCurrentCacheDir(this.namespace)
116
+ }
117
+
118
+ get(key: string): string | undefined {
119
+ const row = this.db
120
+ .prepare(`SELECT rowid, data, size FROM ${this.tableName} WHERE key = ?`)
121
+ .get(key) as { rowid: number; data: string; size: number } | undefined
122
+
123
+ if (row) {
124
+ // Move to end of LRU by deleting and reinserting (gets new rowid)
125
+ const tx = this.db.transaction(() => {
126
+ this.db.prepare(`DELETE FROM ${this.tableName} WHERE key = ?`).run(key)
127
+ this.db
128
+ .prepare(
129
+ `INSERT INTO ${this.tableName} (key, data, size) VALUES (?, ?, ?)`,
130
+ )
131
+ .run(key, row.data, row.size)
132
+ })
133
+ tx()
134
+
135
+ return row.data
136
+ }
137
+
138
+ return undefined
139
+ }
140
+
141
+ has(key: string): boolean {
142
+ const row = this.db
143
+ .prepare(`SELECT 1 FROM ${this.tableName} WHERE key = ?`)
144
+ .get(key)
145
+ return !!row
146
+ }
147
+
148
+ get isEmpty(): boolean {
149
+ const row = this.db
150
+ .prepare(`SELECT COUNT(*) as count FROM ${this.tableName}`)
151
+ .get() as { count: number }
152
+ return row.count === 0
153
+ }
154
+
155
+ set(key: string, data: string): void {
156
+ const dataSize = Buffer.byteLength(data, 'utf8')
157
+
158
+ // Get existing size if any
159
+ const existingRow = this.db
160
+ .prepare(`SELECT size FROM ${this.tableName} WHERE key = ?`)
161
+ .get(key) as { size: number } | undefined
162
+ const oldSize = existingRow?.size || 0
163
+ const newTotalSize = this.currentSize - oldSize + dataSize
164
+
165
+ if (newTotalSize > this.capacity) {
166
+ this.maintainCapacity(newTotalSize - this.capacity)
167
+ }
168
+
169
+ // Insert or update the cache entry
170
+ this.db
171
+ .prepare(
172
+ `INSERT OR REPLACE INTO ${this.tableName} (key, data, size) VALUES (?, ?, ?)`,
173
+ )
174
+ .run(key, data, dataSize)
175
+
176
+ this.currentSize = this.currentSize - oldSize + dataSize
177
+ this.notifySubscribers(key, data)
178
+ }
179
+
180
+ remove(key: string): boolean {
181
+ // Check if key exists and get its size
182
+ const row = this.db
183
+ .prepare(`SELECT size FROM ${this.tableName} WHERE key = ?`)
184
+ .get(key) as { size: number } | undefined
185
+
186
+ if (row) {
187
+ // Delete the key
188
+ this.db.prepare(`DELETE FROM ${this.tableName} WHERE key = ?`).run(key)
189
+
190
+ this.currentSize -= row.size
191
+ this.notifySubscribers(key, undefined)
192
+ return true
193
+ }
194
+
195
+ return false
196
+ }
197
+
198
+ clear(options?: { notifySubscribers: boolean }): void {
199
+ this.db.exec(`DELETE FROM ${this.tableName}`)
200
+ this.currentSize = 0
201
+
202
+ if (options?.notifySubscribers !== false) {
203
+ this.notifySubscribers(undefined, undefined)
204
+ }
205
+ }
206
+
207
+ subscribe(subscriber: Cache.Subscriber): Cache.Subscription {
208
+ this.subscribers.push(subscriber)
209
+ return () => {
210
+ const index = this.subscribers.indexOf(subscriber)
211
+ if (index > -1) {
212
+ this.subscribers.splice(index, 1)
213
+ }
214
+ }
215
+ }
216
+
217
+ private maintainCapacity(bytesToFree: number): void {
218
+ // Order by rowid ASC to get oldest entries first
219
+ const rows = this.db
220
+ .prepare(`SELECT key, size FROM ${this.tableName} ORDER BY rowid ASC`)
221
+ .all() as Array<{ key: string; size: number }>
222
+
223
+ let freedBytes = 0
224
+ const keysToRemove: string[] = []
225
+
226
+ for (const row of rows) {
227
+ if (freedBytes >= bytesToFree) {
228
+ break
229
+ }
230
+ keysToRemove.push(row.key)
231
+ freedBytes += row.size
232
+ }
233
+
234
+ if (keysToRemove.length > 0) {
235
+ const placeholders = keysToRemove.map(() => '?').join(',')
236
+ const stmt = this.db.prepare(
237
+ `DELETE FROM ${this.tableName} WHERE key IN (${placeholders})`,
238
+ )
239
+ stmt.run(...(keysToRemove as [string, ...string[]]))
240
+ this.currentSize -= freedBytes
241
+ }
242
+ }
243
+
244
+ private notifySubscribers(
245
+ key: string | undefined,
246
+ data: string | undefined,
247
+ ): void {
248
+ for (const subscriber of this.subscribers) {
249
+ try {
250
+ subscriber(key, data)
251
+ } catch (error) {
252
+ logger.error('Cache subscriber error:', error)
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ export namespace Cache {
259
+ export interface Options {
260
+ namespace?: string
261
+ capacity?: number
262
+ }
263
+
264
+ export type Subscriber = (
265
+ key: string | undefined,
266
+ data: string | undefined,
267
+ ) => void
268
+ export type Subscription = () => void
269
+ }
270
+
271
+ interface CacheMetadata {
272
+ timestamp: number
273
+ value: any
274
+ }
275
+
276
+ const functionCacheMap = new Map<string, Cache>()
277
+ const functionCacheData = new Map<string, Map<string, CacheMetadata>>()
278
+
279
+ /**
280
+ * Wraps an async function with caching capabilities.
281
+ *
282
+ * This higher-order function adds automatic caching to any async function. Results are
283
+ * cached both in memory and persistently on disk, with support for cache expiration
284
+ * and validation. Each unique set of arguments creates a separate cache entry.
285
+ *
286
+ * @param fn - The async function to wrap with caching
287
+ * @param options - Caching options
288
+ * @param options.validate - Function to check if cached data is still valid (called before returning cached data)
289
+ * @param options.maxAge - Maximum age in milliseconds before cached data expires (default: Infinity)
290
+ * @returns The wrapped function with an additional `clearCache()` method
291
+ * @template Fn - Type of the async function being wrapped
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * // Basic caching
296
+ * const fetchUser = async (userId: string) => {
297
+ * const response = await fetch(`/api/users/${userId}`)
298
+ * return response.json()
299
+ * }
300
+ * const cachedFetchUser = withCache(fetchUser)
301
+ *
302
+ * // First call fetches from API
303
+ * const user1 = await cachedFetchUser("123") // Makes API call
304
+ * // Subsequent calls return from cache
305
+ * const user2 = await cachedFetchUser("123") // Returns cached data
306
+ *
307
+ * // With expiration (5 minutes)
308
+ * const cachedSearch = withCache(searchAPI, {
309
+ * maxAge: 5 * 60 * 1000
310
+ * })
311
+ *
312
+ * // With validation
313
+ * const cachedGetConfig = withCache(getConfig, {
314
+ * validate: (config) => config.version === currentVersion
315
+ * })
316
+ *
317
+ * // Clear cache manually
318
+ * cachedFetchUser.clearCache()
319
+ *
320
+ * // Different arguments are cached separately
321
+ * await cachedFetchUser("123") // Cached
322
+ * await cachedFetchUser("456") // Different cache entry
323
+ * ```
324
+ */
325
+ export function withCache<Fn extends (...args: any[]) => Promise<any>>(
326
+ fn: Fn,
327
+ options?: {
328
+ validate?: (data: Awaited<ReturnType<Fn>>) => boolean
329
+ maxAge?: number
330
+ },
331
+ ): Fn & { clearCache: () => void } {
332
+ const fnKey = fn.toString()
333
+ const maxAge = options?.maxAge || Infinity
334
+ const validate = options?.validate || (() => true)
335
+
336
+ if (!functionCacheMap.has(fnKey)) {
337
+ functionCacheMap.set(fnKey, new Cache({ namespace: `fn-${Date.now()}` }))
338
+ functionCacheData.set(fnKey, new Map())
339
+ }
340
+
341
+ const cache = functionCacheMap.get(fnKey)!
342
+ const cacheData = functionCacheData.get(fnKey)!
343
+
344
+ const cachedFn = (async (...args: Parameters<Fn>) => {
345
+ const cacheKey = JSON.stringify(args)
346
+
347
+ // Check memory cache first
348
+ const cached = cacheData.get(cacheKey)
349
+ if (cached) {
350
+ const age = Date.now() - cached.timestamp
351
+ if (age < maxAge && validate(cached.value)) {
352
+ return cached.value
353
+ }
354
+ }
355
+
356
+ // Check persistent cache
357
+ const persistentCached = cache.get(cacheKey)
358
+ if (persistentCached) {
359
+ try {
360
+ const metadata = JSON.parse(persistentCached) as CacheMetadata
361
+ const age = Date.now() - metadata.timestamp
362
+ if (age < maxAge && validate(metadata.value)) {
363
+ // Update memory cache
364
+ cacheData.set(cacheKey, metadata)
365
+ return metadata.value
366
+ }
367
+ } catch {
368
+ // Invalid cache entry, ignore
369
+ }
370
+ }
371
+
372
+ // Call the original function
373
+ const result = await fn(...args)
374
+
375
+ // Cache the result
376
+ const metadata: CacheMetadata = {
377
+ timestamp: Date.now(),
378
+ value: result,
379
+ }
380
+
381
+ // Update both caches
382
+ cacheData.set(cacheKey, metadata)
383
+ cache.set(cacheKey, JSON.stringify(metadata))
384
+
385
+ return result
386
+ }) as any
387
+
388
+ cachedFn.clearCache = () => {
389
+ cache.clear()
390
+ cacheData.clear()
391
+ }
392
+
393
+ return cachedFn as Fn & { clearCache: () => void }
394
+ }