@overcrow/mcp 0.0.0 → 0.1.0

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 (461) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -1
  3. package/dist/audit/index.js +103 -0
  4. package/dist/audit/lexer.js +417 -0
  5. package/dist/audit/project.js +200 -0
  6. package/dist/audit/rules.js +661 -0
  7. package/dist/bootstrap/download.js +229 -0
  8. package/dist/bootstrap/install.js +280 -0
  9. package/dist/bootstrap/pin.js +85 -0
  10. package/dist/bootstrap/pin.json +119 -0
  11. package/dist/bootstrap/zip.js +258 -0
  12. package/dist/cli.js +200 -0
  13. package/dist/confine.js +244 -0
  14. package/dist/content/docs/en/cli.md +353 -0
  15. package/dist/content/docs/en/dev-channel.md +130 -0
  16. package/dist/content/docs/en/elements.md +469 -0
  17. package/dist/content/docs/en/forms.md +328 -0
  18. package/dist/content/docs/en/guide.md +253 -0
  19. package/dist/content/docs/en/index.md +85 -0
  20. package/dist/content/docs/en/limits.md +241 -0
  21. package/dist/content/docs/en/logic.md +446 -0
  22. package/dist/content/docs/en/manifest.md +381 -0
  23. package/dist/content/docs/en/mcp.md +165 -0
  24. package/dist/content/docs/en/package.md +131 -0
  25. package/dist/content/docs/en/publishing.md +162 -0
  26. package/dist/content/docs/en/reference.md +55 -0
  27. package/dist/content/docs/en/result-shapes.md +332 -0
  28. package/dist/content/docs/en/sdk.md +295 -0
  29. package/dist/content/docs/en/security.md +115 -0
  30. package/dist/content/docs/en/service-reference.md +344 -0
  31. package/dist/content/docs/en/services.md +517 -0
  32. package/dist/content/docs/en/style-properties.md +270 -0
  33. package/dist/content/docs/en/style.md +266 -0
  34. package/dist/content/docs/en/testing.md +400 -0
  35. package/dist/content/docs/en/view.md +338 -0
  36. package/dist/content/docs/en/widgets.md +76 -0
  37. package/dist/content/docs/fr/cli.md +367 -0
  38. package/dist/content/docs/fr/dev-channel.md +140 -0
  39. package/dist/content/docs/fr/elements.md +475 -0
  40. package/dist/content/docs/fr/forms.md +341 -0
  41. package/dist/content/docs/fr/guide.md +264 -0
  42. package/dist/content/docs/fr/index.md +90 -0
  43. package/dist/content/docs/fr/limits.md +244 -0
  44. package/dist/content/docs/fr/logic.md +461 -0
  45. package/dist/content/docs/fr/manifest.md +392 -0
  46. package/dist/content/docs/fr/mcp.md +173 -0
  47. package/dist/content/docs/fr/package.md +139 -0
  48. package/dist/content/docs/fr/publishing.md +172 -0
  49. package/dist/content/docs/fr/reference.md +59 -0
  50. package/dist/content/docs/fr/result-shapes.md +333 -0
  51. package/dist/content/docs/fr/sdk.md +301 -0
  52. package/dist/content/docs/fr/security.md +129 -0
  53. package/dist/content/docs/fr/service-reference.md +346 -0
  54. package/dist/content/docs/fr/services.md +540 -0
  55. package/dist/content/docs/fr/style-properties.md +272 -0
  56. package/dist/content/docs/fr/style.md +281 -0
  57. package/dist/content/docs/fr/testing.md +417 -0
  58. package/dist/content/docs/fr/view.md +352 -0
  59. package/dist/content/docs/fr/widgets.md +81 -0
  60. package/dist/content/examples/clock/LICENSE +21 -0
  61. package/dist/content/examples/clock/README.md +75 -0
  62. package/dist/content/examples/clock/listing.json +19 -0
  63. package/dist/content/examples/clock/locales/en.json +4 -0
  64. package/dist/content/examples/clock/locales/fr.json +4 -0
  65. package/dist/content/examples/clock/logic.ts +85 -0
  66. package/dist/content/examples/clock/manifest.json +44 -0
  67. package/dist/content/examples/clock/package.json +16 -0
  68. package/dist/content/examples/clock/style.ocss +26 -0
  69. package/dist/content/examples/clock/tests/hidden.scenario.json +68 -0
  70. package/dist/content/examples/clock/tests/load-logic.mjs +22 -0
  71. package/dist/content/examples/clock/tests/logic.test.mjs +89 -0
  72. package/dist/content/examples/clock/tests/options.scenario.json +108 -0
  73. package/dist/content/examples/clock/tests/preview.scenario.json +25 -0
  74. package/dist/content/examples/clock/tests/render.scenario.json +94 -0
  75. package/dist/content/examples/clock/tests/summer-time.scenario.json +74 -0
  76. package/dist/content/examples/clock/tests/ticks.scenario.json +120 -0
  77. package/dist/content/examples/clock/tsconfig.json +16 -0
  78. package/dist/content/examples/clock/view.ocml +8 -0
  79. package/dist/content/examples/countdown/LICENSE +20 -0
  80. package/dist/content/examples/countdown/listing.json +10 -0
  81. package/dist/content/examples/countdown/locales/en.json +15 -0
  82. package/dist/content/examples/countdown/locales/fr.json +15 -0
  83. package/dist/content/examples/countdown/logic.ts +179 -0
  84. package/dist/content/examples/countdown/manifest.json +34 -0
  85. package/dist/content/examples/countdown/package.json +15 -0
  86. package/dist/content/examples/countdown/style.ocss +94 -0
  87. package/dist/content/examples/countdown/tsconfig.json +16 -0
  88. package/dist/content/examples/countdown/view.ocml +42 -0
  89. package/dist/content/examples/fps/LICENSE +21 -0
  90. package/dist/content/examples/fps/README.md +64 -0
  91. package/dist/content/examples/fps/listing.json +19 -0
  92. package/dist/content/examples/fps/locales/en.json +11 -0
  93. package/dist/content/examples/fps/locales/fr.json +11 -0
  94. package/dist/content/examples/fps/logic.ts +64 -0
  95. package/dist/content/examples/fps/manifest.json +30 -0
  96. package/dist/content/examples/fps/package.json +16 -0
  97. package/dist/content/examples/fps/style.ocss +31 -0
  98. package/dist/content/examples/fps/tests/label.scenario.json +63 -0
  99. package/dist/content/examples/fps/tests/load-logic.mjs +22 -0
  100. package/dist/content/examples/fps/tests/logic.test.mjs +60 -0
  101. package/dist/content/examples/fps/tests/preview.scenario.json +29 -0
  102. package/dist/content/examples/fps/tests/refused.scenario.json +20 -0
  103. package/dist/content/examples/fps/tests/render.scenario.json +96 -0
  104. package/dist/content/examples/fps/tests/stale.scenario.json +91 -0
  105. package/dist/content/examples/fps/tests/unavailable.scenario.json +111 -0
  106. package/dist/content/examples/fps/tsconfig.json +16 -0
  107. package/dist/content/examples/fps/view.ocml +11 -0
  108. package/dist/content/examples/media/LICENSE +21 -0
  109. package/dist/content/examples/media/README.md +147 -0
  110. package/dist/content/examples/media/listing.json +19 -0
  111. package/dist/content/examples/media/locales/en.json +11 -0
  112. package/dist/content/examples/media/locales/fr.json +11 -0
  113. package/dist/content/examples/media/logic.ts +191 -0
  114. package/dist/content/examples/media/manifest.json +35 -0
  115. package/dist/content/examples/media/package.json +16 -0
  116. package/dist/content/examples/media/style.ocss +148 -0
  117. package/dist/content/examples/media/tests/covers.scenario.json +144 -0
  118. package/dist/content/examples/media/tests/gesture.scenario.json +173 -0
  119. package/dist/content/examples/media/tests/load-logic.mjs +22 -0
  120. package/dist/content/examples/media/tests/logic.test.mjs +176 -0
  121. package/dist/content/examples/media/tests/marquee.scenario.json +127 -0
  122. package/dist/content/examples/media/tests/preview.scenario.json +52 -0
  123. package/dist/content/examples/media/tests/read-only.scenario.json +53 -0
  124. package/dist/content/examples/media/tests/refused.scenario.json +22 -0
  125. package/dist/content/examples/media/tests/refused.test.mjs +31 -0
  126. package/dist/content/examples/media/tests/render.scenario.json +136 -0
  127. package/dist/content/examples/media/tests/states.scenario.json +257 -0
  128. package/dist/content/examples/media/tests/unavailable.scenario.json +120 -0
  129. package/dist/content/examples/media/tsconfig.json +16 -0
  130. package/dist/content/examples/media/view.ocml +41 -0
  131. package/dist/content/examples/notes/LICENSE +21 -0
  132. package/dist/content/examples/notes/README.md +219 -0
  133. package/dist/content/examples/notes/listing.json +19 -0
  134. package/dist/content/examples/notes/locales/en.json +25 -0
  135. package/dist/content/examples/notes/locales/fr.json +25 -0
  136. package/dist/content/examples/notes/logic.ts +799 -0
  137. package/dist/content/examples/notes/manifest.json +40 -0
  138. package/dist/content/examples/notes/package.json +16 -0
  139. package/dist/content/examples/notes/style.ocss +469 -0
  140. package/dist/content/examples/notes/tests/checks.scenario.json +237 -0
  141. package/dist/content/examples/notes/tests/create.scenario.json +260 -0
  142. package/dist/content/examples/notes/tests/delete.scenario.json +342 -0
  143. package/dist/content/examples/notes/tests/drafts.scenario.json +714 -0
  144. package/dist/content/examples/notes/tests/editor.scenario.json +232 -0
  145. package/dist/content/examples/notes/tests/frame.scenario.json +93 -0
  146. package/dist/content/examples/notes/tests/interactive.scenario.json +344 -0
  147. package/dist/content/examples/notes/tests/limits.scenario.json +1351 -0
  148. package/dist/content/examples/notes/tests/load-logic.mjs +22 -0
  149. package/dist/content/examples/notes/tests/logic.test.mjs +514 -0
  150. package/dist/content/examples/notes/tests/preview.scenario.json +99 -0
  151. package/dist/content/examples/notes/tests/read-only.scenario.json +105 -0
  152. package/dist/content/examples/notes/tests/refused.scenario.json +33 -0
  153. package/dist/content/examples/notes/tests/save.scenario.json +378 -0
  154. package/dist/content/examples/notes/tests/states.scenario.json +640 -0
  155. package/dist/content/examples/notes/tests/typing.scenario.json +562 -0
  156. package/dist/content/examples/notes/tests/unavailable.scenario.json +246 -0
  157. package/dist/content/examples/notes/tsconfig.json +16 -0
  158. package/dist/content/examples/notes/view.ocml +154 -0
  159. package/dist/content/examples/performance/LICENSE +21 -0
  160. package/dist/content/examples/performance/README.md +134 -0
  161. package/dist/content/examples/performance/listing.json +19 -0
  162. package/dist/content/examples/performance/locales/en.json +20 -0
  163. package/dist/content/examples/performance/locales/fr.json +20 -0
  164. package/dist/content/examples/performance/logic.ts +210 -0
  165. package/dist/content/examples/performance/manifest.json +83 -0
  166. package/dist/content/examples/performance/package.json +16 -0
  167. package/dist/content/examples/performance/style.ocss +75 -0
  168. package/dist/content/examples/performance/tests/fahrenheit.scenario.json +110 -0
  169. package/dist/content/examples/performance/tests/horizontal.scenario.json +96 -0
  170. package/dist/content/examples/performance/tests/load-logic.mjs +22 -0
  171. package/dist/content/examples/performance/tests/logic.test.mjs +226 -0
  172. package/dist/content/examples/performance/tests/menu.scenario.json +170 -0
  173. package/dist/content/examples/performance/tests/no-fps-source.scenario.json +47 -0
  174. package/dist/content/examples/performance/tests/preview.scenario.json +45 -0
  175. package/dist/content/examples/performance/tests/refused.scenario.json +20 -0
  176. package/dist/content/examples/performance/tests/refused.test.mjs +19 -0
  177. package/dist/content/examples/performance/tests/region.scenario.json +89 -0
  178. package/dist/content/examples/performance/tests/render.scenario.json +112 -0
  179. package/dist/content/examples/performance/tests/sources.scenario.json +151 -0
  180. package/dist/content/examples/performance/tests/stale.scenario.json +111 -0
  181. package/dist/content/examples/performance/tests/telemetry-only.scenario.json +44 -0
  182. package/dist/content/examples/performance/tests/thresholds.scenario.json +147 -0
  183. package/dist/content/examples/performance/tests/waiting.scenario.json +105 -0
  184. package/dist/content/examples/performance/tsconfig.json +16 -0
  185. package/dist/content/examples/performance/view.ocml +18 -0
  186. package/dist/content/examples/playervox-journal/LICENSE +21 -0
  187. package/dist/content/examples/playervox-journal/README.md +150 -0
  188. package/dist/content/examples/playervox-journal/listing.json +19 -0
  189. package/dist/content/examples/playervox-journal/locales/en.json +25 -0
  190. package/dist/content/examples/playervox-journal/locales/fr.json +25 -0
  191. package/dist/content/examples/playervox-journal/logic.ts +556 -0
  192. package/dist/content/examples/playervox-journal/manifest.json +19 -0
  193. package/dist/content/examples/playervox-journal/package.json +16 -0
  194. package/dist/content/examples/playervox-journal/style.ocss +142 -0
  195. package/dist/content/examples/playervox-journal/tests/changes.scenario.json +482 -0
  196. package/dist/content/examples/playervox-journal/tests/delete.scenario.json +432 -0
  197. package/dist/content/examples/playervox-journal/tests/frame.scenario.json +169 -0
  198. package/dist/content/examples/playervox-journal/tests/load-logic.mjs +22 -0
  199. package/dist/content/examples/playervox-journal/tests/logic.test.mjs +349 -0
  200. package/dist/content/examples/playervox-journal/tests/paging.scenario.json +428 -0
  201. package/dist/content/examples/playervox-journal/tests/preview.scenario.json +184 -0
  202. package/dist/content/examples/playervox-journal/tests/read-only.scenario.json +157 -0
  203. package/dist/content/examples/playervox-journal/tests/refused.scenario.json +39 -0
  204. package/dist/content/examples/playervox-journal/tests/scale.scenario.json +286 -0
  205. package/dist/content/examples/playervox-journal/tests/signed-out.scenario.json +134 -0
  206. package/dist/content/examples/playervox-journal/tests/states.scenario.json +741 -0
  207. package/dist/content/examples/playervox-journal/tests/unavailable.scenario.json +183 -0
  208. package/dist/content/examples/playervox-journal/tsconfig.json +16 -0
  209. package/dist/content/examples/playervox-journal/view.ocml +52 -0
  210. package/dist/content/examples/playervox-rating/LICENSE +21 -0
  211. package/dist/content/examples/playervox-rating/README.md +166 -0
  212. package/dist/content/examples/playervox-rating/listing.json +19 -0
  213. package/dist/content/examples/playervox-rating/locales/en.json +35 -0
  214. package/dist/content/examples/playervox-rating/locales/fr.json +35 -0
  215. package/dist/content/examples/playervox-rating/logic.ts +581 -0
  216. package/dist/content/examples/playervox-rating/manifest.json +19 -0
  217. package/dist/content/examples/playervox-rating/package.json +16 -0
  218. package/dist/content/examples/playervox-rating/style.ocss +333 -0
  219. package/dist/content/examples/playervox-rating/tests/account.scenario.json +125 -0
  220. package/dist/content/examples/playervox-rating/tests/bounds.scenario.json +73 -0
  221. package/dist/content/examples/playervox-rating/tests/draft.scenario.json +199 -0
  222. package/dist/content/examples/playervox-rating/tests/form.scenario.json +142 -0
  223. package/dist/content/examples/playervox-rating/tests/load-logic.mjs +22 -0
  224. package/dist/content/examples/playervox-rating/tests/logic.test.mjs +346 -0
  225. package/dist/content/examples/playervox-rating/tests/offline.scenario.json +142 -0
  226. package/dist/content/examples/playervox-rating/tests/preview.scenario.json +44 -0
  227. package/dist/content/examples/playervox-rating/tests/publish-keyboard.scenario.json +221 -0
  228. package/dist/content/examples/playervox-rating/tests/publish-pointer.scenario.json +314 -0
  229. package/dist/content/examples/playervox-rating/tests/read-only.scenario.json +70 -0
  230. package/dist/content/examples/playervox-rating/tests/refused.scenario.json +45 -0
  231. package/dist/content/examples/playervox-rating/tests/states.scenario.json +362 -0
  232. package/dist/content/examples/playervox-rating/tsconfig.json +16 -0
  233. package/dist/content/examples/playervox-rating/view.ocml +62 -0
  234. package/dist/content/examples/playervox-reviews/LICENSE +21 -0
  235. package/dist/content/examples/playervox-reviews/README.md +194 -0
  236. package/dist/content/examples/playervox-reviews/listing.json +19 -0
  237. package/dist/content/examples/playervox-reviews/locales/en.json +32 -0
  238. package/dist/content/examples/playervox-reviews/locales/fr.json +32 -0
  239. package/dist/content/examples/playervox-reviews/logic.ts +822 -0
  240. package/dist/content/examples/playervox-reviews/manifest.json +30 -0
  241. package/dist/content/examples/playervox-reviews/package.json +16 -0
  242. package/dist/content/examples/playervox-reviews/style.ocss +260 -0
  243. package/dist/content/examples/playervox-reviews/tests/account.scenario.json +249 -0
  244. package/dist/content/examples/playervox-reviews/tests/bounds.scenario.json +336 -0
  245. package/dist/content/examples/playervox-reviews/tests/changes.scenario.json +515 -0
  246. package/dist/content/examples/playervox-reviews/tests/filter.scenario.json +400 -0
  247. package/dist/content/examples/playervox-reviews/tests/frame.scenario.json +185 -0
  248. package/dist/content/examples/playervox-reviews/tests/keyboard.scenario.json +188 -0
  249. package/dist/content/examples/playervox-reviews/tests/load-logic.mjs +22 -0
  250. package/dist/content/examples/playervox-reviews/tests/logic.test.mjs +559 -0
  251. package/dist/content/examples/playervox-reviews/tests/offline-start.scenario.json +152 -0
  252. package/dist/content/examples/playervox-reviews/tests/offline.scenario.json +311 -0
  253. package/dist/content/examples/playervox-reviews/tests/paging.scenario.json +497 -0
  254. package/dist/content/examples/playervox-reviews/tests/preview.scenario.json +286 -0
  255. package/dist/content/examples/playervox-reviews/tests/reading.scenario.json +591 -0
  256. package/dist/content/examples/playervox-reviews/tests/refused.scenario.json +54 -0
  257. package/dist/content/examples/playervox-reviews/tests/scale.scenario.json +303 -0
  258. package/dist/content/examples/playervox-reviews/tests/states.scenario.json +700 -0
  259. package/dist/content/examples/playervox-reviews/tests/unavailable.scenario.json +192 -0
  260. package/dist/content/examples/playervox-reviews/tsconfig.json +16 -0
  261. package/dist/content/examples/playervox-reviews/view.ocml +110 -0
  262. package/dist/content/examples/playervox-score/LICENSE +21 -0
  263. package/dist/content/examples/playervox-score/README.md +131 -0
  264. package/dist/content/examples/playervox-score/listing.json +19 -0
  265. package/dist/content/examples/playervox-score/locales/en.json +23 -0
  266. package/dist/content/examples/playervox-score/locales/fr.json +23 -0
  267. package/dist/content/examples/playervox-score/logic.ts +430 -0
  268. package/dist/content/examples/playervox-score/manifest.json +47 -0
  269. package/dist/content/examples/playervox-score/package.json +16 -0
  270. package/dist/content/examples/playervox-score/style.ocss +247 -0
  271. package/dist/content/examples/playervox-score/tests/grades.scenario.json +279 -0
  272. package/dist/content/examples/playervox-score/tests/load-logic.mjs +22 -0
  273. package/dist/content/examples/playervox-score/tests/logic.test.mjs +229 -0
  274. package/dist/content/examples/playervox-score/tests/options.scenario.json +302 -0
  275. package/dist/content/examples/playervox-score/tests/preview.scenario.json +68 -0
  276. package/dist/content/examples/playervox-score/tests/pulse.scenario.json +157 -0
  277. package/dist/content/examples/playervox-score/tests/refused.scenario.json +21 -0
  278. package/dist/content/examples/playervox-score/tests/signed-out.scenario.json +46 -0
  279. package/dist/content/examples/playervox-score/tests/states.scenario.json +450 -0
  280. package/dist/content/examples/playervox-score/tests/unavailable.scenario.json +84 -0
  281. package/dist/content/examples/playervox-score/tsconfig.json +16 -0
  282. package/dist/content/examples/playervox-score/view.ocml +51 -0
  283. package/dist/content/examples/session/LICENSE +21 -0
  284. package/dist/content/examples/session/README.md +57 -0
  285. package/dist/content/examples/session/listing.json +19 -0
  286. package/dist/content/examples/session/locales/en.json +3 -0
  287. package/dist/content/examples/session/locales/fr.json +3 -0
  288. package/dist/content/examples/session/logic.ts +26 -0
  289. package/dist/content/examples/session/manifest.json +19 -0
  290. package/dist/content/examples/session/package.json +16 -0
  291. package/dist/content/examples/session/style.ocss +16 -0
  292. package/dist/content/examples/session/tests/hidden.scenario.json +45 -0
  293. package/dist/content/examples/session/tests/load-logic.mjs +22 -0
  294. package/dist/content/examples/session/tests/logic.test.mjs +37 -0
  295. package/dist/content/examples/session/tests/preview.scenario.json +28 -0
  296. package/dist/content/examples/session/tests/refused.scenario.json +20 -0
  297. package/dist/content/examples/session/tests/refused.test.mjs +16 -0
  298. package/dist/content/examples/session/tests/render.scenario.json +95 -0
  299. package/dist/content/examples/session/tests/ticks.scenario.json +139 -0
  300. package/dist/content/examples/session/tests/unknown.scenario.json +37 -0
  301. package/dist/content/examples/session/tsconfig.json +16 -0
  302. package/dist/content/examples/session/view.ocml +11 -0
  303. package/dist/content/examples/stopwatch/LICENSE +21 -0
  304. package/dist/content/examples/stopwatch/README.md +99 -0
  305. package/dist/content/examples/stopwatch/listing.json +19 -0
  306. package/dist/content/examples/stopwatch/locales/en.json +8 -0
  307. package/dist/content/examples/stopwatch/locales/fr.json +8 -0
  308. package/dist/content/examples/stopwatch/logic.ts +93 -0
  309. package/dist/content/examples/stopwatch/manifest.json +19 -0
  310. package/dist/content/examples/stopwatch/package.json +16 -0
  311. package/dist/content/examples/stopwatch/style.ocss +54 -0
  312. package/dist/content/examples/stopwatch/tests/errors.scenario.json +121 -0
  313. package/dist/content/examples/stopwatch/tests/gesture.scenario.json +154 -0
  314. package/dist/content/examples/stopwatch/tests/hidden.scenario.json +57 -0
  315. package/dist/content/examples/stopwatch/tests/hundredths.scenario.json +173 -0
  316. package/dist/content/examples/stopwatch/tests/load-logic.mjs +22 -0
  317. package/dist/content/examples/stopwatch/tests/logic.test.mjs +99 -0
  318. package/dist/content/examples/stopwatch/tests/preview.scenario.json +36 -0
  319. package/dist/content/examples/stopwatch/tests/read-only.scenario.json +42 -0
  320. package/dist/content/examples/stopwatch/tests/read-only.test.mjs +18 -0
  321. package/dist/content/examples/stopwatch/tests/refused.scenario.json +22 -0
  322. package/dist/content/examples/stopwatch/tests/refused.test.mjs +18 -0
  323. package/dist/content/examples/stopwatch/tests/render.scenario.json +105 -0
  324. package/dist/content/examples/stopwatch/tests/states.scenario.json +246 -0
  325. package/dist/content/examples/stopwatch/tests/unknown.scenario.json +40 -0
  326. package/dist/content/examples/stopwatch/tsconfig.json +16 -0
  327. package/dist/content/examples/stopwatch/view.ocml +29 -0
  328. package/dist/content/examples/twitch-chat/LICENSE +21 -0
  329. package/dist/content/examples/twitch-chat/README.md +283 -0
  330. package/dist/content/examples/twitch-chat/listing.json +19 -0
  331. package/dist/content/examples/twitch-chat/locales/en.json +52 -0
  332. package/dist/content/examples/twitch-chat/locales/fr.json +52 -0
  333. package/dist/content/examples/twitch-chat/logic.ts +887 -0
  334. package/dist/content/examples/twitch-chat/manifest.json +33 -0
  335. package/dist/content/examples/twitch-chat/package.json +16 -0
  336. package/dist/content/examples/twitch-chat/style.ocss +544 -0
  337. package/dist/content/examples/twitch-chat/tests/account.scenario.json +325 -0
  338. package/dist/content/examples/twitch-chat/tests/burst.scenario.json +1866 -0
  339. package/dist/content/examples/twitch-chat/tests/channel-refused.scenario.json +372 -0
  340. package/dist/content/examples/twitch-chat/tests/channel.scenario.json +480 -0
  341. package/dist/content/examples/twitch-chat/tests/draft.scenario.json +279 -0
  342. package/dist/content/examples/twitch-chat/tests/fade.scenario.json +269 -0
  343. package/dist/content/examples/twitch-chat/tests/failures.scenario.json +420 -0
  344. package/dist/content/examples/twitch-chat/tests/favorites.scenario.json +376 -0
  345. package/dist/content/examples/twitch-chat/tests/frame.scenario.json +152 -0
  346. package/dist/content/examples/twitch-chat/tests/lifetime.scenario.json +186 -0
  347. package/dist/content/examples/twitch-chat/tests/load-logic.mjs +22 -0
  348. package/dist/content/examples/twitch-chat/tests/logic.test.mjs +1053 -0
  349. package/dist/content/examples/twitch-chat/tests/passive.scenario.json +536 -0
  350. package/dist/content/examples/twitch-chat/tests/preview.scenario.json +147 -0
  351. package/dist/content/examples/twitch-chat/tests/read-only.scenario.json +202 -0
  352. package/dist/content/examples/twitch-chat/tests/read-only.test.mjs +63 -0
  353. package/dist/content/examples/twitch-chat/tests/refused.scenario.json +65 -0
  354. package/dist/content/examples/twitch-chat/tests/refused.test.mjs +43 -0
  355. package/dist/content/examples/twitch-chat/tests/render.scenario.json +347 -0
  356. package/dist/content/examples/twitch-chat/tests/reply.scenario.json +384 -0
  357. package/dist/content/examples/twitch-chat/tests/send-refused.scenario.json +383 -0
  358. package/dist/content/examples/twitch-chat/tests/send.scenario.json +300 -0
  359. package/dist/content/examples/twitch-chat/tests/states.scenario.json +455 -0
  360. package/dist/content/examples/twitch-chat/tests/unavailable.scenario.json +256 -0
  361. package/dist/content/examples/twitch-chat/tests/unread.scenario.json +997 -0
  362. package/dist/content/examples/twitch-chat/tsconfig.json +16 -0
  363. package/dist/content/examples/twitch-chat/view.ocml +141 -0
  364. package/dist/content/examples/warframe-market/LICENSE +21 -0
  365. package/dist/content/examples/warframe-market/README.md +176 -0
  366. package/dist/content/examples/warframe-market/listing.json +19 -0
  367. package/dist/content/examples/warframe-market/locales/en.json +44 -0
  368. package/dist/content/examples/warframe-market/locales/fr.json +44 -0
  369. package/dist/content/examples/warframe-market/logic.ts +1265 -0
  370. package/dist/content/examples/warframe-market/manifest.json +92 -0
  371. package/dist/content/examples/warframe-market/package.json +16 -0
  372. package/dist/content/examples/warframe-market/style.ocss +422 -0
  373. package/dist/content/examples/warframe-market/tests/bounds.scenario.json +60 -0
  374. package/dist/content/examples/warframe-market/tests/cached.scenario.json +70 -0
  375. package/dist/content/examples/warframe-market/tests/detail.scenario.json +251 -0
  376. package/dist/content/examples/warframe-market/tests/errors.scenario.json +105 -0
  377. package/dist/content/examples/warframe-market/tests/fixtures.json +295 -0
  378. package/dist/content/examples/warframe-market/tests/load-logic.mjs +22 -0
  379. package/dist/content/examples/warframe-market/tests/logic.test.mjs +505 -0
  380. package/dist/content/examples/warframe-market/tests/no-clipboard.scenario.json +104 -0
  381. package/dist/content/examples/warframe-market/tests/passive.scenario.json +87 -0
  382. package/dist/content/examples/warframe-market/tests/preview.scenario.json +146 -0
  383. package/dist/content/examples/warframe-market/tests/refresh.scenario.json +56 -0
  384. package/dist/content/examples/warframe-market/tests/refused.scenario.json +74 -0
  385. package/dist/content/examples/warframe-market/tests/render.scenario.json +210 -0
  386. package/dist/content/examples/warframe-market/tests/search.scenario.json +189 -0
  387. package/dist/content/examples/warframe-market/tests/unavailable.scenario.json +54 -0
  388. package/dist/content/examples/warframe-market/tsconfig.json +16 -0
  389. package/dist/content/examples/warframe-market/view.ocml +116 -0
  390. package/dist/content/examples/weather/LICENSE +20 -0
  391. package/dist/content/examples/weather/listing.json +10 -0
  392. package/dist/content/examples/weather/locales/en.json +9 -0
  393. package/dist/content/examples/weather/locales/fr.json +9 -0
  394. package/dist/content/examples/weather/logic.ts +62 -0
  395. package/dist/content/examples/weather/manifest.json +51 -0
  396. package/dist/content/examples/weather/package.json +15 -0
  397. package/dist/content/examples/weather/style.ocss +29 -0
  398. package/dist/content/examples/weather/tsconfig.json +16 -0
  399. package/dist/content/examples/weather/view.ocml +12 -0
  400. package/dist/content/index.json +3601 -0
  401. package/dist/content/reference/errors.json +1712 -0
  402. package/dist/content/reference/limits.json +1154 -0
  403. package/dist/content/reference/manifest.md +223 -0
  404. package/dist/content/reference/permissions.json +413 -0
  405. package/dist/content/templates/blank/locales/en.json +3 -0
  406. package/dist/content/templates/blank/locales/fr.json +3 -0
  407. package/dist/content/templates/blank/logic.ts +7 -0
  408. package/dist/content/templates/blank/manifest.json +16 -0
  409. package/dist/content/templates/blank/style.ocss +10 -0
  410. package/dist/content/templates/blank/tests/example.scenario.json +10 -0
  411. package/dist/content/templates/blank/view.ocml +6 -0
  412. package/dist/content/templates/chart/locales/en.json +3 -0
  413. package/dist/content/templates/chart/locales/fr.json +3 -0
  414. package/dist/content/templates/chart/logic.ts +27 -0
  415. package/dist/content/templates/chart/manifest.json +16 -0
  416. package/dist/content/templates/chart/style.ocss +27 -0
  417. package/dist/content/templates/chart/tests/example.scenario.json +10 -0
  418. package/dist/content/templates/chart/view.ocml +10 -0
  419. package/dist/content/templates/counter/locales/en.json +4 -0
  420. package/dist/content/templates/counter/locales/fr.json +4 -0
  421. package/dist/content/templates/counter/logic.ts +20 -0
  422. package/dist/content/templates/counter/manifest.json +16 -0
  423. package/dist/content/templates/counter/style.ocss +26 -0
  424. package/dist/content/templates/counter/tests/example.scenario.json +11 -0
  425. package/dist/content/templates/counter/view.ocml +13 -0
  426. package/dist/content/templates/list/locales/en.json +8 -0
  427. package/dist/content/templates/list/locales/fr.json +8 -0
  428. package/dist/content/templates/list/logic.ts +35 -0
  429. package/dist/content/templates/list/manifest.json +16 -0
  430. package/dist/content/templates/list/style.ocss +42 -0
  431. package/dist/content/templates/list/tests/example.scenario.json +10 -0
  432. package/dist/content/templates/list/view.ocml +17 -0
  433. package/dist/content/templates/shared/LICENSE +20 -0
  434. package/dist/content/templates/shared/package.json +14 -0
  435. package/dist/content/templates/shared/tsconfig.json +16 -0
  436. package/dist/content.js +68 -0
  437. package/dist/env.js +156 -0
  438. package/dist/fingerprint.js +32 -0
  439. package/dist/ids.js +27 -0
  440. package/dist/index.js +82 -0
  441. package/dist/knowledge.js +222 -0
  442. package/dist/npm.js +149 -0
  443. package/dist/prompts.js +47 -0
  444. package/dist/resources.js +82 -0
  445. package/dist/run.js +120 -0
  446. package/dist/server.js +43 -0
  447. package/dist/session.js +205 -0
  448. package/dist/sources.js +218 -0
  449. package/dist/text.js +80 -0
  450. package/dist/texts.js +44 -0
  451. package/dist/tools/audit.js +105 -0
  452. package/dist/tools/build.js +453 -0
  453. package/dist/tools/common.js +122 -0
  454. package/dist/tools/docs.js +196 -0
  455. package/dist/tools/preview.js +87 -0
  456. package/dist/tools/project.js +178 -0
  457. package/dist/tools/setup.js +146 -0
  458. package/dist/tools/submission.js +369 -0
  459. package/dist/version.js +3 -0
  460. package/npm-shrinkwrap.json +402 -0
  461. package/package.json +50 -4
@@ -0,0 +1,517 @@
1
+ # Services and permissions
2
+
3
+ A PlayerVox OverCrow widget has no access of its own: no network, no file,
4
+ no clipboard, no data about the game. Everything outside its own state
5
+ comes from a **service** of OverCrow, which the logic calls through
6
+ `@overcrow/sdk`. A service answers only when the widget declared the
7
+ matching permission in its manifest and the user granted it.
8
+
9
+ <!-- source: widgets/session/logic.ts -->
10
+ ```ts
11
+ // Without the grant the host would refuse the subscription: show the
12
+ // unknown duration instead of asking.
13
+ if (hasGrant("session.read")) {
14
+ session.subscribe((update) => {
15
+ state.session = anchor(update);
16
+ });
17
+ }
18
+ ```
19
+
20
+ That is the whole use of a service in the Session widget: it declares the
21
+ `session.read` capability, checks that the user granted it, and subscribes.
22
+
23
+ ## Declare, then ask the user
24
+
25
+ Two kinds of authority exist, both declared in `permissions` of
26
+ [the manifest](manifest.md#permissions):
27
+
28
+ - four **permissions** for general services: `network`, `storage`,
29
+ `clipboardWrite` and `gameEvents`;
30
+ - **capabilities**, listed under `permissions.capabilities`, for the data
31
+ and actions of OverCrow itself and of the user's accounts: the frame
32
+ rate, the media player, notes, PlayerVox ratings, Twitch chat…
33
+
34
+ <!-- source: docs/content/examples/weather/manifest.json -->
35
+ ```json
36
+ "permissions": {
37
+ "network": [
38
+ {
39
+ "origin": "https://api.example.com",
40
+ "method": "GET",
41
+ "path": "/v1/forecast/{city}",
42
+ "pathParams": { "city": { "type": "slug", "maxLength": 32 } },
43
+ "queryParams": {
44
+ "units": { "type": "enum", "values": ["metric", "imperial"], "required": true }
45
+ }
46
+ }
47
+ ],
48
+ "storage": true
49
+ },
50
+ ```
51
+
52
+ A declaration grants nothing by itself. The Control Center shows the user
53
+ what the widget asks for; the user may uncheck an item, or take it back
54
+ later, which restarts the widget without it. The widgets tagged `built-in` in the
55
+ signed catalog (PlayerVox widgets only) start with their declared
56
+ permissions granted. Declare the least you need: reviewers read every
57
+ permission, and users see them before they consent.
58
+
59
+ `hasGrant(capability)` tells whether a capability was granted. Check it
60
+ before you subscribe, and show a useful state when it is missing: a refused
61
+ widget must still look right.
62
+
63
+ <!-- source: widgets/fps/logic.ts -->
64
+ ```ts
65
+ if (hasGrant("fps.read")) {
66
+ fps.subscribe((update) => {
67
+ Object.assign(state, reading(update));
68
+ });
69
+ } else {
70
+ state.status = "unavailable";
71
+ }
72
+ ```
73
+
74
+ ## Calls and subscriptions
75
+
76
+ A service is one of two kinds.
77
+
78
+ **A call** asks once and returns a promise:
79
+
80
+ <!-- source: widgets/warframe-market/logic.ts -->
81
+ ```ts
82
+ async function readStored(key: string): Promise<JsonValue | undefined> {
83
+ try {
84
+ return await storage.get({ key });
85
+ } catch {
86
+ state.error = "storage_unavailable";
87
+ return undefined;
88
+ }
89
+ }
90
+ ```
91
+
92
+ **A subscription** takes a listener. OverCrow calls it with the current
93
+ value at once, then with each new value, until you `cancel()` it or it
94
+ ends with a failure. The listener comes last; a service with parameters
95
+ takes them first.
96
+
97
+ <!-- source: widgets/media/logic.ts -->
98
+ ```ts
99
+ const current = media.subscribe({ cover: state.showCover }, (update) => {
100
+ if (update.ok) {
101
+ state.media = update.value;
102
+ state.unavailable = false;
103
+ return;
104
+ }
105
+ // The subscription ended: the host's source failed. Show it and ask
106
+ // again later; hidden, the timer waits until the widget shows.
107
+ if (subscription === current) {
108
+ subscription = null;
109
+ state.media = null;
110
+ state.unavailable = true;
111
+ retry = timers.after(RETRY_MS, subscribe);
112
+ }
113
+ });
114
+ ```
115
+
116
+ Each update is `{ ok: true, value, final }` or
117
+ `{ ok: false, error, final: true }`. A failed update is always the last
118
+ one: the subscription is over.
119
+
120
+ Services are grouped in namespaces of the SDK: `storage`, `http`,
121
+ `clipboard`, `gameEvents`, and one per data source (`fps`, `telemetry`,
122
+ `session`, `media`, `stopwatch`, `notes`, `playervox`, `journal`,
123
+ `twitch`). Every service, with its parameters and its result, is in the
124
+ [service reference](service-reference.md).
125
+
126
+ OverCrow checks every call when it arrives, in this order: the permission
127
+ or capability, the parameters, the user action when the service needs one,
128
+ then the account when it needs one. The SDK's types help you call a
129
+ service right; they are not what enforces the rules.
130
+
131
+ ## Errors
132
+
133
+ A failed call rejects with a `ServiceError`, whose `code` says why. A
134
+ subscription that fails delivers the same error in its last update.
135
+
136
+ <!-- source: docs/content/examples/weather/logic.ts -->
137
+ ```ts
138
+ try {
139
+ const url = `https://api.example.com/v1/forecast/${state.city}?units=${state.units}`;
140
+ const { status, body } = await http.fetch(url, { as: "json" });
141
+ const value = (body as { temperature?: unknown } | null)?.temperature;
142
+ if (status !== 200 || typeof value !== "number") {
143
+ state.status = "unavailable";
144
+ return;
145
+ }
146
+ state.temperature = value;
147
+ state.status = "updated";
148
+ await storage.set({ key, value });
149
+ } catch (error) {
150
+ // permission_denied until the user consents, transport_failed offline…
151
+ state.status = error instanceof ServiceError ? "unavailable" : "failed";
152
+ }
153
+ ```
154
+
155
+ <!-- generated:error-codes -->
156
+ | Code | Meaning |
157
+ | --- | --- |
158
+ | `invalid_request` | The parameters are not what the service takes: a member is missing or unknown, has the wrong type or is out of bounds. |
159
+ | `permission_denied` | The permission or capability is not declared in the manifest, or the user has not granted it. For `http.fetch`, no network rule allows this URL and method. A write through a form can also get it from the account's provider, for a write it does not allow. |
160
+ | `gesture_required` | The service can be called only during a user action, and this call was not made while one was handled, or that action already allowed another call. |
161
+ | `not_connected` | The service needs the user's PlayerVox or Twitch account, which is not connected at the moment. |
162
+ | `stale_context` | What the call was about changed before the answer: another game, another account, another media player, an object deleted meanwhile. Read the current state again. |
163
+ | `unavailable` | OverCrow's source for this data failed, or cannot act right now. A subscription that ends with it can be started again later. |
164
+ | `busy` | Too much is in progress: a confirmation is already open, a queue or the budget of network responses is full, or the provider asks to wait. Try again later. |
165
+ | `cancelled` | The user declined the confirmation, or left Interactive mode while it was open. |
166
+ | `quota_exceeded` | A quota is full: the storage, the timers, the notes, the favourite channels. |
167
+ | `unsupported` | The target cannot do this: a media player that does not offer the command, for instance. |
168
+ | `url_invalid` | `http.fetch`: the URL is not an absolute HTTPS URL that OverCrow accepts. |
169
+ | `resolve_failed` | `http.fetch`: the host name could not be resolved. |
170
+ | `address_denied` | `http.fetch`: the host name resolves to a local, private or otherwise non-public address. |
171
+ | `too_many_addresses` | `http.fetch`: the host name resolves to more addresses than OverCrow accepts. |
172
+ | `peer_mismatch` | `http.fetch`: the server that answered is not at one of the addresses that were resolved and checked. |
173
+ | `redirect_denied` | `http.fetch`: the server answered with a redirection. OverCrow follows none: declare and request the final URL. |
174
+ | `encoding_denied` | `http.fetch`: the response is compressed or encoded in a way OverCrow does not accept, or its body does not decode as `as` asks (invalid JSON or text). |
175
+ | `content_type_denied` | `http.fetch`: the media type of the response is not one that OverCrow accepts for this request. |
176
+ | `response_metadata_limit` | `http.fetch`: the status line or the headers of the response are malformed or exceed OverCrow's bounds. |
177
+ | `request_body_limit` | `http.fetch`: the request body is larger than 256 KiB. |
178
+ | `response_body_limit` | `http.fetch`: the response body is larger than the bound of the network rule (`maxResponseBytes`, or 1 MiB without it and for `as: "image"`). |
179
+ | `image_invalid` | `http.fetch` with `as: "image"`: the response is not a PNG, JPEG or WebP image within the image limits. |
180
+ | `timeout` | `http.fetch`: the exchange took longer than 30 seconds. |
181
+ | `transport_failed` | `http.fetch`: the connection failed: no network, a TLS error, a connection closed by the server. |
182
+ <!-- /generated:error-codes -->
183
+
184
+ Three habits cover most cases:
185
+
186
+ - **Show a state, not an error message.** The codes are for your logic;
187
+ the user sees "Forecast unavailable", not `transport_failed`.
188
+ - **Retry a subscription that ended.** A source of OverCrow can fail while
189
+ the widget runs (the media player's session, for instance): the
190
+ subscription ends with `unavailable`. Subscribe again a few seconds later
191
+ with `timers.after`; OverCrow restarts the source for the new
192
+ subscription. The Media widget waits five seconds:
193
+
194
+ <!-- source: widgets/media/logic.ts -->
195
+ ```ts
196
+ // The subscription ended: the host's source failed. Show it and ask
197
+ // again later; hidden, the timer waits until the widget shows.
198
+ if (subscription === current) {
199
+ subscription = null;
200
+ state.media = null;
201
+ state.unavailable = true;
202
+ retry = timers.after(RETRY_MS, subscribe);
203
+ }
204
+ ```
205
+
206
+ - **Do not retry in a loop.** `busy` and `quota_exceeded` mean that a bound
207
+ is reached: wait, or do less.
208
+
209
+ ## Calls that need a user action
210
+
211
+ Services that change something for the user, or put something where other
212
+ programs read it, can be called **only during a user action**: while the
213
+ logic handles one of these events of the view.
214
+
215
+ <!-- generated:gesture-events -->
216
+ `activate`, `contextmenu`, `keydown`, `input`, `change`, `submit`.
217
+ <!-- /generated:gesture-events -->
218
+
219
+ <!-- source: widgets/stopwatch/logic.ts -->
220
+ ```ts
221
+ export function toggle(): void {
222
+ command(() => stopwatch.toggle());
223
+ }
224
+ ```
225
+
226
+ `toggle` is the `on:activate` handler of the stopwatch's button: the click
227
+ is the user action, and `stopwatch.toggle()` is called while it is handled.
228
+ The same call from a timer, from the answer of another service, from
229
+ `onHost` or from a row of the options menu is refused with
230
+ `gesture_required`.
231
+
232
+ - One user action allows one protected call. Call the service directly in
233
+ the handler, not after an `await` on something else.
234
+ - Widgets receive input only in OverCrow's Interactive mode, so a protected
235
+ call can only happen there.
236
+ - `notes.delete` and `journal.delete` also ask the user to confirm, in a
237
+ dialog drawn by OverCrow; a declined confirmation is `cancelled`.
238
+
239
+ The tables below say, for each service, when it can be called.
240
+
241
+ ## Permissions
242
+
243
+ <!-- generated:permission-list -->
244
+ | Permission | Meaning | With a sensitive capability |
245
+ | --- | --- | --- |
246
+ | `network` | Exact HTTPS routes reachable through the host broker, at most 32 rules. | manifest rejected |
247
+ | `storage` | Host-managed key-value storage partitioned by widget ID, within 256 KiB. | process-lifetime data only |
248
+ | `clipboardWrite` | Text clipboard writes, during a user action in Interactive mode. | manifest rejected |
249
+ | `gameEvents` | Named semantic game events `overcrow.game.<name>.v1`, at most 32. | allowed |
250
+ | `capabilities` | Host services listed with the capabilities. | allowed |
251
+ <!-- /generated:permission-list -->
252
+
253
+ <!-- generated:permissions -->
254
+ | Permission | Service | When it can be called |
255
+ | --- | --- | --- |
256
+ | `network` | `http.fetch` | At any time |
257
+ | `storage` | `storage.get` | At any time |
258
+ | `storage` | `storage.set` | At any time |
259
+ | `storage` | `storage.remove` | At any time |
260
+ | `storage` | `storage.keys` | At any time |
261
+ | `clipboardWrite` | `clipboard.writeText` | Only during a user action |
262
+ | `gameEvents` | `gameEvents.subscribe` | At any time |
263
+
264
+ “Only during a user action” is explained in [Calls that need a user action](services.md#calls-that-need-a-user-action).
265
+ <!-- /generated:permissions -->
266
+
267
+ ### Network rules
268
+
269
+ `network` is a list of rules. A rule allows requests to exactly one HTTPS
270
+ origin, one method and one path; a `{name}` segment of the path is a typed
271
+ parameter, and only the declared query parameters are accepted.
272
+
273
+ <!-- source: widgets/warframe-market/manifest.json -->
274
+ ```json
275
+ "permissions": {
276
+ "network": [
277
+ {
278
+ "origin": "https://api.warframe.market",
279
+ "method": "GET",
280
+ "path": "/v2/versions",
281
+ "maxResponseBytes": 4096
282
+ },
283
+ {
284
+ "origin": "https://api.warframe.market",
285
+ "method": "GET",
286
+ "path": "/v2/items",
287
+ "maxResponseBytes": 3145728
288
+ },
289
+ {
290
+ "origin": "https://api.warframe.market",
291
+ "method": "GET",
292
+ "path": "/v2/orders/item/{slug}",
293
+ "pathParams": {
294
+ "slug": {
295
+ "type": "slug",
296
+ "maxLength": 96
297
+ }
298
+ },
299
+ "maxResponseBytes": 2097152
300
+ }
301
+ ],
302
+ "storage": true,
303
+ "clipboardWrite": true
304
+ },
305
+ ```
306
+
307
+ <!-- generated:network-rule-fields -->
308
+ | Field | Type | Required | Meaning |
309
+ | --- | --- | --- | --- |
310
+ | `origin` | `origin` | yes | Canonical `https://host[:port]` origin, host ≤ 253 bytes with labels ≤ 63 bytes; no credentials, IP literal or local name. |
311
+ | `method` | `GET` \| `POST` \| `PUT` \| `PATCH` \| `DELETE` | yes | One method. |
312
+ | `path` | text ≤ 1 KiB | yes | Complete path; `{name}` segments are typed path parameters. |
313
+ | `pathParams` | `name → ParameterConstraint` | no | Constraint of every `{name}` segment, at most 8. |
314
+ | `queryParams` | `name → ParameterConstraint` | no | Allowed query parameters, at most 16, each optionally `required`; others are refused. |
315
+ | `maxResponseBytes` | integer 1 to 3145728 | no | Largest response body of this route, from 1 to 3 MiB; 1 MiB when absent. Not for `as: "image"`, which keeps 1 MiB. When several rules allow a request, the largest bound applies. |
316
+ <!-- /generated:network-rule-fields -->
317
+
318
+ Each path and query parameter has a constraint:
319
+
320
+ <!-- generated:parameter-constraints -->
321
+ | Type | Shape | Accepts |
322
+ | --- | --- | --- |
323
+ | `integer` | `{ min, max }` | Decimal without leading zero, from 0 to 2^53 - 1. |
324
+ | `slug` | `{ maxLength }` | ASCII letters of either case, digits, `_` and `-`, at least one character; `maxLength` from 1 to 128 bytes. |
325
+ | `enum` | list of `literal segment` ≤ 32 | One of the listed values, each ≤ 128 bytes. |
326
+ | `string` | `{ maxLength }` | Query parameters only; any text without control characters; `maxLength` from 1 to 256 bytes. |
327
+ <!-- /generated:parameter-constraints -->
328
+
329
+ The request leaves through OverCrow's broker, never from the widget's
330
+ process. The broker:
331
+
332
+ - refuses any URL that no rule allows (`permission_denied`), before any
333
+ DNS query;
334
+ - follows no redirection, and sends no cookie, credential or proxy
335
+ header;
336
+ - refuses local and private addresses, so a widget cannot reach the user's
337
+ router or another program of the machine;
338
+ - bounds each exchange: 256 KiB for a request body, 30 seconds in all, and
339
+ 1 MiB for a response body unless the rule declares a larger
340
+ `maxResponseBytes`, up to 3 MiB. Reviewers and users see that bound.
341
+
342
+ `http.fetch(url, { as })` decodes the body as you ask: `"json"`, `"text"`,
343
+ `"bytes"` (an `ArrayBuffer`) or `"image"`, which gives an image handle to
344
+ bind to an `image` element instead of the bytes. A string `body` is sent as
345
+ `text/plain` and any other value as JSON, unless `contentType` says
346
+ otherwise. An HTTP error status is not a failure of the call: check
347
+ `status`.
348
+
349
+ <!-- source: docs/content/examples/weather/logic.ts -->
350
+ ```ts
351
+ const url = `https://api.example.com/v1/forecast/${state.city}?units=${state.units}`;
352
+ const { status, body } = await http.fetch(url, { as: "json" });
353
+ const value = (body as { temperature?: unknown } | null)?.temperature;
354
+ if (status !== 200 || typeof value !== "number") {
355
+ state.status = "unavailable";
356
+ return;
357
+ }
358
+ ```
359
+
360
+ At most four requests of a widget are in flight at once, and they share a
361
+ budget of response bytes: a request that does not fit fails with `busy` at
362
+ once.
363
+
364
+ ### Storage
365
+
366
+ `storage` is a key-value store that OverCrow keeps for your widget only:
367
+ `storage.get({ key })`, `storage.set({ key, value })`,
368
+ `storage.remove({ key })` and `storage.keys()`. A value is any JSON value.
369
+ There is no file access.
370
+
371
+ <!-- source: docs/content/examples/countdown/logic.ts -->
372
+ ```ts
373
+ function setRounds(rounds: number): void {
374
+ state.rounds = rounds;
375
+ paint();
376
+ // Storage needs the user's consent: without it the count lasts as long
377
+ // as the widget runs.
378
+ storage.set({ key: "rounds", value: rounds }).catch(() => {});
379
+ }
380
+ ```
381
+
382
+ The store holds at most 512 keys and 256 KiB in all, 64 KiB per value;
383
+ beyond, `storage.set` fails with `quota_exceeded` and changes nothing. A
384
+ write is answered once it is on disk. Uninstalling the widget erases its
385
+ store, and a development session (`overcrow-widget dev`) never reads or
386
+ writes the store of an installed widget.
387
+
388
+ ### Clipboard
389
+
390
+ `clipboard.writeText({ text })` puts text on the clipboard, only during a
391
+ user action. A widget cannot read the clipboard.
392
+
393
+ <!-- source: widgets/warframe-market/logic.ts -->
394
+ ```ts
395
+ clipboard.writeText({ text: whisperLine(order, detail.name) }).then(
396
+ () => {
397
+ if (mine === selection) state.copy = { side, id, state: "copied" };
398
+ },
399
+ () => {
400
+ if (mine === selection) state.copy = { side, id, state: "failed" };
401
+ },
402
+ );
403
+ ```
404
+
405
+ Text that the user selects in a `text` element with the `selectable`
406
+ attribute is copied by OverCrow itself, and needs no permission.
407
+
408
+ ### Game events
409
+
410
+ `gameEvents` lists the named game events the widget wants, each of the form
411
+ `overcrow.game.<name>.v1`. `gameEvents.subscribe(listener)` then delivers
412
+ `{ event, at }` for each one that happens.
413
+
414
+ ## Capabilities
415
+
416
+ A capability gives access to data or actions that OverCrow holds: what the
417
+ game's use of the machine, the media player, the user's notes, their
418
+ PlayerVox and Twitch accounts.
419
+
420
+ <!-- generated:capability-list -->
421
+ | Capability | Sensitive | Account | Meaning |
422
+ | --- | --- | --- | --- |
423
+ | `telemetry.read` | no | — | CPU, RAM and temperature samples of the active game. |
424
+ | `fps.read` | no | — | Frame rate of the active game when the host has a source. |
425
+ | `media.read` | **yes** | — | Now-playing metadata and the image of its cover art. |
426
+ | `media.control` | **yes** | — | Previous, play/pause and next. |
427
+ | `session.read` | no | — | Duration of the active game session, without the game identity. |
428
+ | `stopwatch.read` | no | — | State of the host's single manual stopwatch and its shortcuts. |
429
+ | `stopwatch.control` | no | — | Start, pause and reset the host's single manual stopwatch. |
430
+ | `notes.read` | **yes** | — | The user's notes and checklists: one document shared by every game. |
431
+ | `notes.write` | **yes** | — | Create, select, save, check and delete notes; text only through a form bound to a write intent. |
432
+ | `playervox.score.read` | **yes** | — | Public PlayerVox score of the active game; sensitive because it reveals the game. |
433
+ | `playervox.rating.read` | **yes** | PlayerVox | The user's own rating of the active game. |
434
+ | `playervox.rating.write` | **yes** | PlayerVox | Publish a rating and review through a form bound to a write intent. |
435
+ | `playervox.reviews.read` | **yes** | PlayerVox | Paged player reviews of the active game, optionally from followed players only. |
436
+ | `journal.read` | **yes** | — | Play sessions of the active game: local ones, plus cloud ones while PlayerVox is connected. |
437
+ | `journal.delete` | **yes** | — | Delete a journal session after a confirmation asked by the host; cloud sessions need PlayerVox. |
438
+ | `twitch.chat.read` | **yes** | Twitch | Join, read and leave a Twitch channel chat, and keep favourite channels. |
439
+ | `twitch.chat.compose` | **yes** | Twitch | Send a chat message through a form bound to a write intent; the host allows 20 messages per 30 s and answers `busy` beyond. |
440
+ <!-- /generated:capability-list -->
441
+
442
+ <!-- generated:capabilities -->
443
+ | Capability | Sensitive | Service | When it can be called |
444
+ | --- | --- | --- | --- |
445
+ | `telemetry.read` | no | `telemetry.subscribe` | At any time |
446
+ | `fps.read` | no | `fps.subscribe` | At any time |
447
+ | `media.read` | **yes** | `media.subscribe` | At any time |
448
+ | `media.control` | **yes** | `media.previous` | Only during a user action |
449
+ | `media.control` | **yes** | `media.playPause` | Only during a user action |
450
+ | `media.control` | **yes** | `media.next` | Only during a user action |
451
+ | `session.read` | no | `session.subscribe` | At any time |
452
+ | `stopwatch.read` | no | `stopwatch.subscribe` | At any time |
453
+ | `stopwatch.control` | no | `stopwatch.toggle` | Only during a user action |
454
+ | `stopwatch.control` | no | `stopwatch.reset` | Only during a user action |
455
+ | `notes.read` | **yes** | `notes.subscribe` | At any time |
456
+ | `notes.write` | **yes** | `notes.create` | Only during a user action |
457
+ | `notes.write` | **yes** | `notes.select` | Only during a user action |
458
+ | `notes.write` | **yes** | `notes.setItem` | Only during a user action |
459
+ | `notes.write` | **yes** | `notes.delete` | Only during a user action |
460
+ | `notes.write` | **yes** | [form `notes.save`](forms.md#notessave) | When the user submits the form |
461
+ | `playervox.score.read` | **yes** | `playervox.score.subscribe` | At any time |
462
+ | `playervox.rating.read` | **yes** | `playervox.rating.subscribe` | At any time |
463
+ | `playervox.rating.write` | **yes** | [form `playervox.rating.publish`](forms.md#playervoxratingpublish) | When the user submits the form |
464
+ | `playervox.reviews.read` | **yes** | `playervox.reviews.subscribe` | At any time |
465
+ | `playervox.reviews.read` | **yes** | `playervox.reviews.page` | At any time |
466
+ | `journal.read` | **yes** | `journal.subscribe` | At any time |
467
+ | `journal.read` | **yes** | `journal.page` | At any time |
468
+ | `journal.delete` | **yes** | `journal.delete` | Only during a user action |
469
+ | `twitch.chat.read` | **yes** | `twitch.chat.subscribe` | At any time |
470
+ | `twitch.chat.read` | **yes** | `twitch.chat.join` | Only during a user action |
471
+ | `twitch.chat.read` | **yes** | `twitch.chat.leave` | Only during a user action |
472
+ | `twitch.chat.read` | **yes** | `twitch.chat.favorite` | Only during a user action |
473
+ | `twitch.chat.compose` | **yes** | [form `twitch.chat.send`](forms.md#twitchchatsend) | When the user submits the form |
474
+
475
+ “Only during a user action” is explained in [Calls that need a user action](services.md#calls-that-need-a-user-action).
476
+ <!-- /generated:capabilities -->
477
+
478
+ A row whose service is a form is a write that the user types: see
479
+ [forms that write user data](forms.md#forms-that-write-user-data).
480
+
481
+ ### Sensitive capabilities
482
+
483
+ A **sensitive** capability reveals personal data or the game being played.
484
+ A widget that declares one:
485
+
486
+ - cannot also declare `network` or `clipboardWrite`: the manifest is
487
+ refused;
488
+ - has a storage that lasts only as long as its process, and is emptied when
489
+ the widget restarts.
490
+
491
+ So what such a widget reads cannot leave the machine through it. If your
492
+ widget needs both an HTTP API and a sensitive capability, make two widgets.
493
+
494
+ ### Accounts
495
+
496
+ Some capabilities need the user's PlayerVox or Twitch account. The
497
+ connection belongs to OverCrow: it draws the sign-in, keeps the tokens and
498
+ shows its own panel over the widget while the account is signed out. A
499
+ widget never sees a token; it receives only the data its capability
500
+ describes, and its calls fail with `not_connected` while the account is
501
+ not connected.
502
+
503
+ ### Data that changes
504
+
505
+ - A subscription may deliver `null` (no active game, no media player): show
506
+ an empty state.
507
+ - Some subscriptions say *what to read* rather than the data itself.
508
+ `playervox.reviews.subscribe` and `journal.subscribe` deliver a
509
+ `revision`: when it changes, read your page again with
510
+ `playervox.reviews.page` or `journal.page`.
511
+ - `twitch.chat.subscribe` delivers changes rather than the whole chat, at
512
+ most every 100 ms: the new messages, the changed ones (same `id`), the
513
+ IDs of the removed ones, and the whole list when `reset` is set.
514
+ - A timestamp that comes with its own `offsetMinutes` must be formatted
515
+ with it; see [time, dates and numbers](logic.md#time-dates-and-numbers).
516
+
517
+ The shape of every result is in [result shapes](result-shapes.md).