@overcrow/mcp 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +90 -2
- package/dist/audit/index.js +103 -0
- package/dist/audit/lexer.js +417 -0
- package/dist/audit/project.js +200 -0
- package/dist/audit/rules.js +661 -0
- package/dist/bootstrap/download.js +229 -0
- package/dist/bootstrap/install.js +280 -0
- package/dist/bootstrap/pin.js +85 -0
- package/dist/bootstrap/pin.json +119 -0
- package/dist/bootstrap/zip.js +258 -0
- package/dist/cli.js +200 -0
- package/dist/confine.js +244 -0
- package/dist/content/docs/en/cli.md +353 -0
- package/dist/content/docs/en/dev-channel.md +130 -0
- package/dist/content/docs/en/elements.md +469 -0
- package/dist/content/docs/en/forms.md +328 -0
- package/dist/content/docs/en/guide.md +253 -0
- package/dist/content/docs/en/index.md +85 -0
- package/dist/content/docs/en/limits.md +241 -0
- package/dist/content/docs/en/logic.md +446 -0
- package/dist/content/docs/en/manifest.md +381 -0
- package/dist/content/docs/en/mcp.md +165 -0
- package/dist/content/docs/en/package.md +131 -0
- package/dist/content/docs/en/publishing.md +162 -0
- package/dist/content/docs/en/reference.md +55 -0
- package/dist/content/docs/en/result-shapes.md +332 -0
- package/dist/content/docs/en/sdk.md +295 -0
- package/dist/content/docs/en/security.md +115 -0
- package/dist/content/docs/en/service-reference.md +344 -0
- package/dist/content/docs/en/services.md +517 -0
- package/dist/content/docs/en/style-properties.md +270 -0
- package/dist/content/docs/en/style.md +266 -0
- package/dist/content/docs/en/testing.md +400 -0
- package/dist/content/docs/en/view.md +338 -0
- package/dist/content/docs/en/widgets.md +76 -0
- package/dist/content/docs/fr/cli.md +367 -0
- package/dist/content/docs/fr/dev-channel.md +140 -0
- package/dist/content/docs/fr/elements.md +475 -0
- package/dist/content/docs/fr/forms.md +341 -0
- package/dist/content/docs/fr/guide.md +264 -0
- package/dist/content/docs/fr/index.md +90 -0
- package/dist/content/docs/fr/limits.md +244 -0
- package/dist/content/docs/fr/logic.md +461 -0
- package/dist/content/docs/fr/manifest.md +392 -0
- package/dist/content/docs/fr/mcp.md +173 -0
- package/dist/content/docs/fr/package.md +139 -0
- package/dist/content/docs/fr/publishing.md +172 -0
- package/dist/content/docs/fr/reference.md +59 -0
- package/dist/content/docs/fr/result-shapes.md +333 -0
- package/dist/content/docs/fr/sdk.md +301 -0
- package/dist/content/docs/fr/security.md +129 -0
- package/dist/content/docs/fr/service-reference.md +346 -0
- package/dist/content/docs/fr/services.md +540 -0
- package/dist/content/docs/fr/style-properties.md +272 -0
- package/dist/content/docs/fr/style.md +281 -0
- package/dist/content/docs/fr/testing.md +417 -0
- package/dist/content/docs/fr/view.md +352 -0
- package/dist/content/docs/fr/widgets.md +81 -0
- package/dist/content/examples/clock/LICENSE +21 -0
- package/dist/content/examples/clock/README.md +75 -0
- package/dist/content/examples/clock/listing.json +19 -0
- package/dist/content/examples/clock/locales/en.json +4 -0
- package/dist/content/examples/clock/locales/fr.json +4 -0
- package/dist/content/examples/clock/logic.ts +85 -0
- package/dist/content/examples/clock/manifest.json +44 -0
- package/dist/content/examples/clock/package.json +16 -0
- package/dist/content/examples/clock/style.ocss +26 -0
- package/dist/content/examples/clock/tests/hidden.scenario.json +68 -0
- package/dist/content/examples/clock/tests/load-logic.mjs +22 -0
- package/dist/content/examples/clock/tests/logic.test.mjs +89 -0
- package/dist/content/examples/clock/tests/options.scenario.json +108 -0
- package/dist/content/examples/clock/tests/preview.scenario.json +25 -0
- package/dist/content/examples/clock/tests/render.scenario.json +94 -0
- package/dist/content/examples/clock/tests/summer-time.scenario.json +74 -0
- package/dist/content/examples/clock/tests/ticks.scenario.json +120 -0
- package/dist/content/examples/clock/tsconfig.json +16 -0
- package/dist/content/examples/clock/view.ocml +8 -0
- package/dist/content/examples/countdown/LICENSE +20 -0
- package/dist/content/examples/countdown/listing.json +10 -0
- package/dist/content/examples/countdown/locales/en.json +15 -0
- package/dist/content/examples/countdown/locales/fr.json +15 -0
- package/dist/content/examples/countdown/logic.ts +179 -0
- package/dist/content/examples/countdown/manifest.json +34 -0
- package/dist/content/examples/countdown/package.json +15 -0
- package/dist/content/examples/countdown/style.ocss +94 -0
- package/dist/content/examples/countdown/tsconfig.json +16 -0
- package/dist/content/examples/countdown/view.ocml +42 -0
- package/dist/content/examples/fps/LICENSE +21 -0
- package/dist/content/examples/fps/README.md +64 -0
- package/dist/content/examples/fps/listing.json +19 -0
- package/dist/content/examples/fps/locales/en.json +11 -0
- package/dist/content/examples/fps/locales/fr.json +11 -0
- package/dist/content/examples/fps/logic.ts +64 -0
- package/dist/content/examples/fps/manifest.json +30 -0
- package/dist/content/examples/fps/package.json +16 -0
- package/dist/content/examples/fps/style.ocss +31 -0
- package/dist/content/examples/fps/tests/label.scenario.json +63 -0
- package/dist/content/examples/fps/tests/load-logic.mjs +22 -0
- package/dist/content/examples/fps/tests/logic.test.mjs +60 -0
- package/dist/content/examples/fps/tests/preview.scenario.json +29 -0
- package/dist/content/examples/fps/tests/refused.scenario.json +20 -0
- package/dist/content/examples/fps/tests/render.scenario.json +96 -0
- package/dist/content/examples/fps/tests/stale.scenario.json +91 -0
- package/dist/content/examples/fps/tests/unavailable.scenario.json +111 -0
- package/dist/content/examples/fps/tsconfig.json +16 -0
- package/dist/content/examples/fps/view.ocml +11 -0
- package/dist/content/examples/media/LICENSE +21 -0
- package/dist/content/examples/media/README.md +147 -0
- package/dist/content/examples/media/listing.json +19 -0
- package/dist/content/examples/media/locales/en.json +11 -0
- package/dist/content/examples/media/locales/fr.json +11 -0
- package/dist/content/examples/media/logic.ts +191 -0
- package/dist/content/examples/media/manifest.json +35 -0
- package/dist/content/examples/media/package.json +16 -0
- package/dist/content/examples/media/style.ocss +148 -0
- package/dist/content/examples/media/tests/covers.scenario.json +144 -0
- package/dist/content/examples/media/tests/gesture.scenario.json +173 -0
- package/dist/content/examples/media/tests/load-logic.mjs +22 -0
- package/dist/content/examples/media/tests/logic.test.mjs +176 -0
- package/dist/content/examples/media/tests/marquee.scenario.json +127 -0
- package/dist/content/examples/media/tests/preview.scenario.json +52 -0
- package/dist/content/examples/media/tests/read-only.scenario.json +53 -0
- package/dist/content/examples/media/tests/refused.scenario.json +22 -0
- package/dist/content/examples/media/tests/refused.test.mjs +31 -0
- package/dist/content/examples/media/tests/render.scenario.json +136 -0
- package/dist/content/examples/media/tests/states.scenario.json +257 -0
- package/dist/content/examples/media/tests/unavailable.scenario.json +120 -0
- package/dist/content/examples/media/tsconfig.json +16 -0
- package/dist/content/examples/media/view.ocml +41 -0
- package/dist/content/examples/notes/LICENSE +21 -0
- package/dist/content/examples/notes/README.md +219 -0
- package/dist/content/examples/notes/listing.json +19 -0
- package/dist/content/examples/notes/locales/en.json +25 -0
- package/dist/content/examples/notes/locales/fr.json +25 -0
- package/dist/content/examples/notes/logic.ts +799 -0
- package/dist/content/examples/notes/manifest.json +40 -0
- package/dist/content/examples/notes/package.json +16 -0
- package/dist/content/examples/notes/style.ocss +469 -0
- package/dist/content/examples/notes/tests/checks.scenario.json +237 -0
- package/dist/content/examples/notes/tests/create.scenario.json +260 -0
- package/dist/content/examples/notes/tests/delete.scenario.json +342 -0
- package/dist/content/examples/notes/tests/drafts.scenario.json +714 -0
- package/dist/content/examples/notes/tests/editor.scenario.json +232 -0
- package/dist/content/examples/notes/tests/frame.scenario.json +93 -0
- package/dist/content/examples/notes/tests/interactive.scenario.json +344 -0
- package/dist/content/examples/notes/tests/limits.scenario.json +1351 -0
- package/dist/content/examples/notes/tests/load-logic.mjs +22 -0
- package/dist/content/examples/notes/tests/logic.test.mjs +514 -0
- package/dist/content/examples/notes/tests/preview.scenario.json +99 -0
- package/dist/content/examples/notes/tests/read-only.scenario.json +105 -0
- package/dist/content/examples/notes/tests/refused.scenario.json +33 -0
- package/dist/content/examples/notes/tests/save.scenario.json +378 -0
- package/dist/content/examples/notes/tests/states.scenario.json +640 -0
- package/dist/content/examples/notes/tests/typing.scenario.json +562 -0
- package/dist/content/examples/notes/tests/unavailable.scenario.json +246 -0
- package/dist/content/examples/notes/tsconfig.json +16 -0
- package/dist/content/examples/notes/view.ocml +154 -0
- package/dist/content/examples/performance/LICENSE +21 -0
- package/dist/content/examples/performance/README.md +134 -0
- package/dist/content/examples/performance/listing.json +19 -0
- package/dist/content/examples/performance/locales/en.json +20 -0
- package/dist/content/examples/performance/locales/fr.json +20 -0
- package/dist/content/examples/performance/logic.ts +210 -0
- package/dist/content/examples/performance/manifest.json +83 -0
- package/dist/content/examples/performance/package.json +16 -0
- package/dist/content/examples/performance/style.ocss +75 -0
- package/dist/content/examples/performance/tests/fahrenheit.scenario.json +110 -0
- package/dist/content/examples/performance/tests/horizontal.scenario.json +96 -0
- package/dist/content/examples/performance/tests/load-logic.mjs +22 -0
- package/dist/content/examples/performance/tests/logic.test.mjs +226 -0
- package/dist/content/examples/performance/tests/menu.scenario.json +170 -0
- package/dist/content/examples/performance/tests/no-fps-source.scenario.json +47 -0
- package/dist/content/examples/performance/tests/preview.scenario.json +45 -0
- package/dist/content/examples/performance/tests/refused.scenario.json +20 -0
- package/dist/content/examples/performance/tests/refused.test.mjs +19 -0
- package/dist/content/examples/performance/tests/region.scenario.json +89 -0
- package/dist/content/examples/performance/tests/render.scenario.json +112 -0
- package/dist/content/examples/performance/tests/sources.scenario.json +151 -0
- package/dist/content/examples/performance/tests/stale.scenario.json +111 -0
- package/dist/content/examples/performance/tests/telemetry-only.scenario.json +44 -0
- package/dist/content/examples/performance/tests/thresholds.scenario.json +147 -0
- package/dist/content/examples/performance/tests/waiting.scenario.json +105 -0
- package/dist/content/examples/performance/tsconfig.json +16 -0
- package/dist/content/examples/performance/view.ocml +18 -0
- package/dist/content/examples/playervox-journal/LICENSE +21 -0
- package/dist/content/examples/playervox-journal/README.md +150 -0
- package/dist/content/examples/playervox-journal/listing.json +19 -0
- package/dist/content/examples/playervox-journal/locales/en.json +25 -0
- package/dist/content/examples/playervox-journal/locales/fr.json +25 -0
- package/dist/content/examples/playervox-journal/logic.ts +556 -0
- package/dist/content/examples/playervox-journal/manifest.json +19 -0
- package/dist/content/examples/playervox-journal/package.json +16 -0
- package/dist/content/examples/playervox-journal/style.ocss +142 -0
- package/dist/content/examples/playervox-journal/tests/changes.scenario.json +482 -0
- package/dist/content/examples/playervox-journal/tests/delete.scenario.json +432 -0
- package/dist/content/examples/playervox-journal/tests/frame.scenario.json +169 -0
- package/dist/content/examples/playervox-journal/tests/load-logic.mjs +22 -0
- package/dist/content/examples/playervox-journal/tests/logic.test.mjs +349 -0
- package/dist/content/examples/playervox-journal/tests/paging.scenario.json +428 -0
- package/dist/content/examples/playervox-journal/tests/preview.scenario.json +184 -0
- package/dist/content/examples/playervox-journal/tests/read-only.scenario.json +157 -0
- package/dist/content/examples/playervox-journal/tests/refused.scenario.json +39 -0
- package/dist/content/examples/playervox-journal/tests/scale.scenario.json +286 -0
- package/dist/content/examples/playervox-journal/tests/signed-out.scenario.json +134 -0
- package/dist/content/examples/playervox-journal/tests/states.scenario.json +741 -0
- package/dist/content/examples/playervox-journal/tests/unavailable.scenario.json +183 -0
- package/dist/content/examples/playervox-journal/tsconfig.json +16 -0
- package/dist/content/examples/playervox-journal/view.ocml +52 -0
- package/dist/content/examples/playervox-rating/LICENSE +21 -0
- package/dist/content/examples/playervox-rating/README.md +166 -0
- package/dist/content/examples/playervox-rating/listing.json +19 -0
- package/dist/content/examples/playervox-rating/locales/en.json +35 -0
- package/dist/content/examples/playervox-rating/locales/fr.json +35 -0
- package/dist/content/examples/playervox-rating/logic.ts +581 -0
- package/dist/content/examples/playervox-rating/manifest.json +19 -0
- package/dist/content/examples/playervox-rating/package.json +16 -0
- package/dist/content/examples/playervox-rating/style.ocss +333 -0
- package/dist/content/examples/playervox-rating/tests/account.scenario.json +125 -0
- package/dist/content/examples/playervox-rating/tests/bounds.scenario.json +73 -0
- package/dist/content/examples/playervox-rating/tests/draft.scenario.json +199 -0
- package/dist/content/examples/playervox-rating/tests/form.scenario.json +142 -0
- package/dist/content/examples/playervox-rating/tests/load-logic.mjs +22 -0
- package/dist/content/examples/playervox-rating/tests/logic.test.mjs +346 -0
- package/dist/content/examples/playervox-rating/tests/offline.scenario.json +142 -0
- package/dist/content/examples/playervox-rating/tests/preview.scenario.json +44 -0
- package/dist/content/examples/playervox-rating/tests/publish-keyboard.scenario.json +221 -0
- package/dist/content/examples/playervox-rating/tests/publish-pointer.scenario.json +314 -0
- package/dist/content/examples/playervox-rating/tests/read-only.scenario.json +70 -0
- package/dist/content/examples/playervox-rating/tests/refused.scenario.json +45 -0
- package/dist/content/examples/playervox-rating/tests/states.scenario.json +362 -0
- package/dist/content/examples/playervox-rating/tsconfig.json +16 -0
- package/dist/content/examples/playervox-rating/view.ocml +62 -0
- package/dist/content/examples/playervox-reviews/LICENSE +21 -0
- package/dist/content/examples/playervox-reviews/README.md +194 -0
- package/dist/content/examples/playervox-reviews/listing.json +19 -0
- package/dist/content/examples/playervox-reviews/locales/en.json +32 -0
- package/dist/content/examples/playervox-reviews/locales/fr.json +32 -0
- package/dist/content/examples/playervox-reviews/logic.ts +822 -0
- package/dist/content/examples/playervox-reviews/manifest.json +30 -0
- package/dist/content/examples/playervox-reviews/package.json +16 -0
- package/dist/content/examples/playervox-reviews/style.ocss +260 -0
- package/dist/content/examples/playervox-reviews/tests/account.scenario.json +249 -0
- package/dist/content/examples/playervox-reviews/tests/bounds.scenario.json +336 -0
- package/dist/content/examples/playervox-reviews/tests/changes.scenario.json +515 -0
- package/dist/content/examples/playervox-reviews/tests/filter.scenario.json +400 -0
- package/dist/content/examples/playervox-reviews/tests/frame.scenario.json +185 -0
- package/dist/content/examples/playervox-reviews/tests/keyboard.scenario.json +188 -0
- package/dist/content/examples/playervox-reviews/tests/load-logic.mjs +22 -0
- package/dist/content/examples/playervox-reviews/tests/logic.test.mjs +559 -0
- package/dist/content/examples/playervox-reviews/tests/offline-start.scenario.json +152 -0
- package/dist/content/examples/playervox-reviews/tests/offline.scenario.json +311 -0
- package/dist/content/examples/playervox-reviews/tests/paging.scenario.json +497 -0
- package/dist/content/examples/playervox-reviews/tests/preview.scenario.json +286 -0
- package/dist/content/examples/playervox-reviews/tests/reading.scenario.json +591 -0
- package/dist/content/examples/playervox-reviews/tests/refused.scenario.json +54 -0
- package/dist/content/examples/playervox-reviews/tests/scale.scenario.json +303 -0
- package/dist/content/examples/playervox-reviews/tests/states.scenario.json +700 -0
- package/dist/content/examples/playervox-reviews/tests/unavailable.scenario.json +192 -0
- package/dist/content/examples/playervox-reviews/tsconfig.json +16 -0
- package/dist/content/examples/playervox-reviews/view.ocml +110 -0
- package/dist/content/examples/playervox-score/LICENSE +21 -0
- package/dist/content/examples/playervox-score/README.md +131 -0
- package/dist/content/examples/playervox-score/listing.json +19 -0
- package/dist/content/examples/playervox-score/locales/en.json +23 -0
- package/dist/content/examples/playervox-score/locales/fr.json +23 -0
- package/dist/content/examples/playervox-score/logic.ts +430 -0
- package/dist/content/examples/playervox-score/manifest.json +47 -0
- package/dist/content/examples/playervox-score/package.json +16 -0
- package/dist/content/examples/playervox-score/style.ocss +247 -0
- package/dist/content/examples/playervox-score/tests/grades.scenario.json +279 -0
- package/dist/content/examples/playervox-score/tests/load-logic.mjs +22 -0
- package/dist/content/examples/playervox-score/tests/logic.test.mjs +229 -0
- package/dist/content/examples/playervox-score/tests/options.scenario.json +302 -0
- package/dist/content/examples/playervox-score/tests/preview.scenario.json +68 -0
- package/dist/content/examples/playervox-score/tests/pulse.scenario.json +157 -0
- package/dist/content/examples/playervox-score/tests/refused.scenario.json +21 -0
- package/dist/content/examples/playervox-score/tests/signed-out.scenario.json +46 -0
- package/dist/content/examples/playervox-score/tests/states.scenario.json +450 -0
- package/dist/content/examples/playervox-score/tests/unavailable.scenario.json +84 -0
- package/dist/content/examples/playervox-score/tsconfig.json +16 -0
- package/dist/content/examples/playervox-score/view.ocml +51 -0
- package/dist/content/examples/session/LICENSE +21 -0
- package/dist/content/examples/session/README.md +57 -0
- package/dist/content/examples/session/listing.json +19 -0
- package/dist/content/examples/session/locales/en.json +3 -0
- package/dist/content/examples/session/locales/fr.json +3 -0
- package/dist/content/examples/session/logic.ts +26 -0
- package/dist/content/examples/session/manifest.json +19 -0
- package/dist/content/examples/session/package.json +16 -0
- package/dist/content/examples/session/style.ocss +16 -0
- package/dist/content/examples/session/tests/hidden.scenario.json +45 -0
- package/dist/content/examples/session/tests/load-logic.mjs +22 -0
- package/dist/content/examples/session/tests/logic.test.mjs +37 -0
- package/dist/content/examples/session/tests/preview.scenario.json +28 -0
- package/dist/content/examples/session/tests/refused.scenario.json +20 -0
- package/dist/content/examples/session/tests/refused.test.mjs +16 -0
- package/dist/content/examples/session/tests/render.scenario.json +95 -0
- package/dist/content/examples/session/tests/ticks.scenario.json +139 -0
- package/dist/content/examples/session/tests/unknown.scenario.json +37 -0
- package/dist/content/examples/session/tsconfig.json +16 -0
- package/dist/content/examples/session/view.ocml +11 -0
- package/dist/content/examples/stopwatch/LICENSE +21 -0
- package/dist/content/examples/stopwatch/README.md +99 -0
- package/dist/content/examples/stopwatch/listing.json +19 -0
- package/dist/content/examples/stopwatch/locales/en.json +8 -0
- package/dist/content/examples/stopwatch/locales/fr.json +8 -0
- package/dist/content/examples/stopwatch/logic.ts +93 -0
- package/dist/content/examples/stopwatch/manifest.json +19 -0
- package/dist/content/examples/stopwatch/package.json +16 -0
- package/dist/content/examples/stopwatch/style.ocss +54 -0
- package/dist/content/examples/stopwatch/tests/errors.scenario.json +121 -0
- package/dist/content/examples/stopwatch/tests/gesture.scenario.json +154 -0
- package/dist/content/examples/stopwatch/tests/hidden.scenario.json +57 -0
- package/dist/content/examples/stopwatch/tests/hundredths.scenario.json +173 -0
- package/dist/content/examples/stopwatch/tests/load-logic.mjs +22 -0
- package/dist/content/examples/stopwatch/tests/logic.test.mjs +99 -0
- package/dist/content/examples/stopwatch/tests/preview.scenario.json +36 -0
- package/dist/content/examples/stopwatch/tests/read-only.scenario.json +42 -0
- package/dist/content/examples/stopwatch/tests/read-only.test.mjs +18 -0
- package/dist/content/examples/stopwatch/tests/refused.scenario.json +22 -0
- package/dist/content/examples/stopwatch/tests/refused.test.mjs +18 -0
- package/dist/content/examples/stopwatch/tests/render.scenario.json +105 -0
- package/dist/content/examples/stopwatch/tests/states.scenario.json +246 -0
- package/dist/content/examples/stopwatch/tests/unknown.scenario.json +40 -0
- package/dist/content/examples/stopwatch/tsconfig.json +16 -0
- package/dist/content/examples/stopwatch/view.ocml +29 -0
- package/dist/content/examples/twitch-chat/LICENSE +21 -0
- package/dist/content/examples/twitch-chat/README.md +283 -0
- package/dist/content/examples/twitch-chat/listing.json +19 -0
- package/dist/content/examples/twitch-chat/locales/en.json +52 -0
- package/dist/content/examples/twitch-chat/locales/fr.json +52 -0
- package/dist/content/examples/twitch-chat/logic.ts +887 -0
- package/dist/content/examples/twitch-chat/manifest.json +33 -0
- package/dist/content/examples/twitch-chat/package.json +16 -0
- package/dist/content/examples/twitch-chat/style.ocss +544 -0
- package/dist/content/examples/twitch-chat/tests/account.scenario.json +325 -0
- package/dist/content/examples/twitch-chat/tests/burst.scenario.json +1866 -0
- package/dist/content/examples/twitch-chat/tests/channel-refused.scenario.json +372 -0
- package/dist/content/examples/twitch-chat/tests/channel.scenario.json +480 -0
- package/dist/content/examples/twitch-chat/tests/draft.scenario.json +279 -0
- package/dist/content/examples/twitch-chat/tests/fade.scenario.json +269 -0
- package/dist/content/examples/twitch-chat/tests/failures.scenario.json +420 -0
- package/dist/content/examples/twitch-chat/tests/favorites.scenario.json +376 -0
- package/dist/content/examples/twitch-chat/tests/frame.scenario.json +152 -0
- package/dist/content/examples/twitch-chat/tests/lifetime.scenario.json +186 -0
- package/dist/content/examples/twitch-chat/tests/load-logic.mjs +22 -0
- package/dist/content/examples/twitch-chat/tests/logic.test.mjs +1053 -0
- package/dist/content/examples/twitch-chat/tests/passive.scenario.json +536 -0
- package/dist/content/examples/twitch-chat/tests/preview.scenario.json +147 -0
- package/dist/content/examples/twitch-chat/tests/read-only.scenario.json +202 -0
- package/dist/content/examples/twitch-chat/tests/read-only.test.mjs +63 -0
- package/dist/content/examples/twitch-chat/tests/refused.scenario.json +65 -0
- package/dist/content/examples/twitch-chat/tests/refused.test.mjs +43 -0
- package/dist/content/examples/twitch-chat/tests/render.scenario.json +347 -0
- package/dist/content/examples/twitch-chat/tests/reply.scenario.json +384 -0
- package/dist/content/examples/twitch-chat/tests/send-refused.scenario.json +383 -0
- package/dist/content/examples/twitch-chat/tests/send.scenario.json +300 -0
- package/dist/content/examples/twitch-chat/tests/states.scenario.json +455 -0
- package/dist/content/examples/twitch-chat/tests/unavailable.scenario.json +256 -0
- package/dist/content/examples/twitch-chat/tests/unread.scenario.json +997 -0
- package/dist/content/examples/twitch-chat/tsconfig.json +16 -0
- package/dist/content/examples/twitch-chat/view.ocml +141 -0
- package/dist/content/examples/warframe-market/LICENSE +21 -0
- package/dist/content/examples/warframe-market/README.md +176 -0
- package/dist/content/examples/warframe-market/listing.json +19 -0
- package/dist/content/examples/warframe-market/locales/en.json +44 -0
- package/dist/content/examples/warframe-market/locales/fr.json +44 -0
- package/dist/content/examples/warframe-market/logic.ts +1265 -0
- package/dist/content/examples/warframe-market/manifest.json +92 -0
- package/dist/content/examples/warframe-market/package.json +16 -0
- package/dist/content/examples/warframe-market/style.ocss +422 -0
- package/dist/content/examples/warframe-market/tests/bounds.scenario.json +60 -0
- package/dist/content/examples/warframe-market/tests/cached.scenario.json +70 -0
- package/dist/content/examples/warframe-market/tests/detail.scenario.json +251 -0
- package/dist/content/examples/warframe-market/tests/errors.scenario.json +105 -0
- package/dist/content/examples/warframe-market/tests/fixtures.json +295 -0
- package/dist/content/examples/warframe-market/tests/load-logic.mjs +22 -0
- package/dist/content/examples/warframe-market/tests/logic.test.mjs +505 -0
- package/dist/content/examples/warframe-market/tests/no-clipboard.scenario.json +104 -0
- package/dist/content/examples/warframe-market/tests/passive.scenario.json +87 -0
- package/dist/content/examples/warframe-market/tests/preview.scenario.json +146 -0
- package/dist/content/examples/warframe-market/tests/refresh.scenario.json +56 -0
- package/dist/content/examples/warframe-market/tests/refused.scenario.json +74 -0
- package/dist/content/examples/warframe-market/tests/render.scenario.json +210 -0
- package/dist/content/examples/warframe-market/tests/search.scenario.json +189 -0
- package/dist/content/examples/warframe-market/tests/unavailable.scenario.json +54 -0
- package/dist/content/examples/warframe-market/tsconfig.json +16 -0
- package/dist/content/examples/warframe-market/view.ocml +116 -0
- package/dist/content/examples/weather/LICENSE +20 -0
- package/dist/content/examples/weather/listing.json +10 -0
- package/dist/content/examples/weather/locales/en.json +9 -0
- package/dist/content/examples/weather/locales/fr.json +9 -0
- package/dist/content/examples/weather/logic.ts +62 -0
- package/dist/content/examples/weather/manifest.json +51 -0
- package/dist/content/examples/weather/package.json +15 -0
- package/dist/content/examples/weather/style.ocss +29 -0
- package/dist/content/examples/weather/tsconfig.json +16 -0
- package/dist/content/examples/weather/view.ocml +12 -0
- package/dist/content/index.json +3601 -0
- package/dist/content/reference/errors.json +1712 -0
- package/dist/content/reference/limits.json +1154 -0
- package/dist/content/reference/manifest.md +223 -0
- package/dist/content/reference/permissions.json +413 -0
- package/dist/content/templates/blank/locales/en.json +3 -0
- package/dist/content/templates/blank/locales/fr.json +3 -0
- package/dist/content/templates/blank/logic.ts +7 -0
- package/dist/content/templates/blank/manifest.json +16 -0
- package/dist/content/templates/blank/style.ocss +10 -0
- package/dist/content/templates/blank/tests/example.scenario.json +10 -0
- package/dist/content/templates/blank/view.ocml +6 -0
- package/dist/content/templates/chart/locales/en.json +3 -0
- package/dist/content/templates/chart/locales/fr.json +3 -0
- package/dist/content/templates/chart/logic.ts +27 -0
- package/dist/content/templates/chart/manifest.json +16 -0
- package/dist/content/templates/chart/style.ocss +27 -0
- package/dist/content/templates/chart/tests/example.scenario.json +10 -0
- package/dist/content/templates/chart/view.ocml +10 -0
- package/dist/content/templates/counter/locales/en.json +4 -0
- package/dist/content/templates/counter/locales/fr.json +4 -0
- package/dist/content/templates/counter/logic.ts +20 -0
- package/dist/content/templates/counter/manifest.json +16 -0
- package/dist/content/templates/counter/style.ocss +26 -0
- package/dist/content/templates/counter/tests/example.scenario.json +11 -0
- package/dist/content/templates/counter/view.ocml +13 -0
- package/dist/content/templates/list/locales/en.json +8 -0
- package/dist/content/templates/list/locales/fr.json +8 -0
- package/dist/content/templates/list/logic.ts +35 -0
- package/dist/content/templates/list/manifest.json +16 -0
- package/dist/content/templates/list/style.ocss +42 -0
- package/dist/content/templates/list/tests/example.scenario.json +10 -0
- package/dist/content/templates/list/view.ocml +17 -0
- package/dist/content/templates/shared/LICENSE +20 -0
- package/dist/content/templates/shared/package.json +14 -0
- package/dist/content/templates/shared/tsconfig.json +16 -0
- package/dist/content.js +68 -0
- package/dist/env.js +156 -0
- package/dist/fingerprint.js +32 -0
- package/dist/ids.js +27 -0
- package/dist/index.js +82 -0
- package/dist/knowledge.js +222 -0
- package/dist/npm.js +149 -0
- package/dist/prompts.js +47 -0
- package/dist/resources.js +82 -0
- package/dist/run.js +120 -0
- package/dist/server.js +43 -0
- package/dist/session.js +205 -0
- package/dist/sources.js +218 -0
- package/dist/text.js +80 -0
- package/dist/texts.js +44 -0
- package/dist/tools/audit.js +105 -0
- package/dist/tools/build.js +453 -0
- package/dist/tools/common.js +122 -0
- package/dist/tools/docs.js +196 -0
- package/dist/tools/preview.js +87 -0
- package/dist/tools/project.js +178 -0
- package/dist/tools/setup.js +146 -0
- package/dist/tools/submission.js +369 -0
- package/dist/version.js +3 -0
- package/npm-shrinkwrap.json +402 -0
- package/package.json +52 -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).
|