@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.
- package/LICENSE +21 -0
- package/README.md +91 -1
- 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 +50 -4
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# Formulaires et intents d’écriture
|
|
2
|
+
|
|
3
|
+
Un widget PlayerVox OverCrow reçoit ses entrées par des contrôles
|
|
4
|
+
qu’OverCrow dessine et édite lui-même : boutons, bascules, cases à cocher,
|
|
5
|
+
curseurs, listes déroulantes, champs de texte. La logique en est informée
|
|
6
|
+
par des événements. Un `form` regroupe des contrôles et les valide ensemble.
|
|
7
|
+
Un formulaire lié à un **intent d’écriture** est le moyen, pour un widget,
|
|
8
|
+
de laisser l’utilisateur écrire dans ses notes, publier sa note d’un jeu sur
|
|
9
|
+
PlayerVox ou envoyer un message de chat, sans que le texte passe jamais par
|
|
10
|
+
le code du widget.
|
|
11
|
+
|
|
12
|
+
Les widgets ne reçoivent d’entrées qu’en mode interactif d’OverCrow. En mode
|
|
13
|
+
passif, un clic traverse le widget jusqu’au jeu : masquez ou désactivez ce
|
|
14
|
+
qui est inutilisable, comme le font les widgets intégrés avec `host.mode`.
|
|
15
|
+
|
|
16
|
+
## Contrôles
|
|
17
|
+
|
|
18
|
+
| Élément | Valeur | Événements |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| `button` | aucune | `activate` |
|
|
21
|
+
| `toggle`, `checkbox` | `checked` | `change` |
|
|
22
|
+
| `slider` | `value`, entre `min` et `max` | `input` pendant le glissement, `change` au relâchement |
|
|
23
|
+
| `select` avec des enfants `option` | `value` de l’option choisie | `change` |
|
|
24
|
+
| `field` | une ligne de texte | `input` à chaque modification, `change` sur Entrée ou quand le focus quitte le champ, `submit` sur Entrée |
|
|
25
|
+
| `textarea` | plusieurs lignes de texte | `input`, `change`, `submit` sur Ctrl+Entrée |
|
|
26
|
+
|
|
27
|
+
Chacun prend un `label`, son nom accessible, et `disabled`. Leurs attributs
|
|
28
|
+
sont décrits dans [Éléments et attributs](elements.md).
|
|
29
|
+
|
|
30
|
+
<!-- source: docs/content/examples/countdown/view.ocml -->
|
|
31
|
+
```xml
|
|
32
|
+
<select class="duration" value={minutesValue(state.minutes)} label={t("duration")} disabled={state.running} on:change={setMinutes}>
|
|
33
|
+
<for each={state.durations} as="minutes" key={minutes}>
|
|
34
|
+
<option value={minutesValue(minutes)}>{t("minutes", { count: minutes })}</option>
|
|
35
|
+
</for>
|
|
36
|
+
</select>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
<!-- source: docs/content/examples/countdown/logic.ts -->
|
|
40
|
+
```ts
|
|
41
|
+
export function setMinutes(event: { value: unknown }): void {
|
|
42
|
+
const minutes = Number(event.value);
|
|
43
|
+
if (state.durations.includes(minutes)) {
|
|
44
|
+
state.minutes = minutes;
|
|
45
|
+
state.remainingMs = total(minutes);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
La vue lie le contrôle à l’état (`value={…}`, `checked={…}`), et le
|
|
51
|
+
gestionnaire y réécrit la nouvelle valeur. Le détail de `input` et de
|
|
52
|
+
`change` est `{ value }` : un booléen pour une bascule ou une case à cocher,
|
|
53
|
+
un nombre pour un curseur, du texte pour les autres.
|
|
54
|
+
|
|
55
|
+
<!-- source: docs/content/examples/countdown/view.ocml -->
|
|
56
|
+
```xml
|
|
57
|
+
<toggle class="repeat" label={t("repeat")} tooltip={t("repeat")} checked={state.repeat} on:change={setRepeat}/>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Champs de texte
|
|
61
|
+
|
|
62
|
+
OverCrow édite lui-même le texte d’un `field` ou d’un `textarea` : le point
|
|
63
|
+
d’insertion, la sélection, le copier-coller et les méthodes de saisie des
|
|
64
|
+
langues qui composent leurs caractères. La logique reçoit une copie du texte
|
|
65
|
+
dans chaque événement `input`.
|
|
66
|
+
|
|
67
|
+
<!-- source: widgets/warframe-market/view.ocml -->
|
|
68
|
+
```xml
|
|
69
|
+
<field class="query" label={t("search-field")} value={state.query} placeholder={t("placeholder")} max-length="256" on:input={search}/>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
<!-- source: widgets/warframe-market/logic.ts -->
|
|
73
|
+
```ts
|
|
74
|
+
export function search(detail: { value: unknown }): void {
|
|
75
|
+
state.query = typeof detail.value === "string" ? detail.value : "";
|
|
76
|
+
state.results = searchItems(items, lowered, state.query);
|
|
77
|
+
state.detail = null;
|
|
78
|
+
state.loadingOrders = false;
|
|
79
|
+
state.refreshing = false;
|
|
80
|
+
state.copy = null;
|
|
81
|
+
if (state.error === "orders_unavailable") {
|
|
82
|
+
state.error = null;
|
|
83
|
+
}
|
|
84
|
+
selection += 1;
|
|
85
|
+
stopRefresh();
|
|
86
|
+
saveQuery();
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Lier `value` remplace le contenu du champ : liez-le à l’état qu’écrit votre
|
|
91
|
+
gestionnaire `input`, comme ci-dessus, ou omettez-le et contentez-vous
|
|
92
|
+
d’écouter. `max-length` limite le texte en octets, et `placeholder` affiche
|
|
93
|
+
une indication tant que le champ est vide.
|
|
94
|
+
|
|
95
|
+
Un champ envoie aussi `keydown` quand vous le demandez, avec la touche et
|
|
96
|
+
ses modificateurs, pour des raccourcis comme Échap pour annuler. Les touches
|
|
97
|
+
qu’OverCrow se réserve (Tab pour déplacer le focus, ses propres raccourcis,
|
|
98
|
+
une composition en cours) ne sont pas transmises.
|
|
99
|
+
|
|
100
|
+
### Le focus à l’ouverture d’un éditeur
|
|
101
|
+
|
|
102
|
+
La logique ne peut pas déplacer le focus clavier. Un `field` ou un
|
|
103
|
+
`textarea` qui porte `autofocus` le prend de lui-même quand il apparaît
|
|
104
|
+
pendant que la logique traite une action de l’utilisateur : un clic sur un
|
|
105
|
+
bouton Modifier qui ouvre un éditeur place le point d’insertion dans le
|
|
106
|
+
champ, après son texte, comme le ferait un clic dans ce champ.
|
|
107
|
+
|
|
108
|
+
<!-- source: widgets/notes/view.ocml -->
|
|
109
|
+
```xml
|
|
110
|
+
<field class="title-field" name="title" autofocus placeholder={t("title-hint")} label={t("title-hint")} on:input={titleInput(editor.key, event.value)} on:keydown={keyed(editor.key, event.key, event.ctrl)}/>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
OverCrow ne donne ce focus que si l’élément apparaît pendant une
|
|
114
|
+
[action de l’utilisateur](services.md#les-appels-qui-demandent-une-action-de-lutilisateur),
|
|
115
|
+
en mode interactif, dans le widget sur lequel l’utilisateur a agi ; quand
|
|
116
|
+
plusieurs de ces éléments apparaissent ensemble, le premier de la vue le
|
|
117
|
+
prend. Un élément qui apparaît au démarrage du widget, depuis un minuteur
|
|
118
|
+
ou depuis la réponse d’un service (y compris après un `await` dans le
|
|
119
|
+
gestionnaire du clic) ne prend pas le focus, pas plus qu’un élément déjà
|
|
120
|
+
affiché : `autofocus` est lu quand l’élément apparaît. Donnez-le à un seul
|
|
121
|
+
champ d’un éditeur, et pas à un champ qui apparaît pendant que
|
|
122
|
+
l’utilisateur saisit, comme une nouvelle ligne d’une liste.
|
|
123
|
+
|
|
124
|
+
## Formulaires
|
|
125
|
+
|
|
126
|
+
Un `form` regroupe des contrôles et leur donne un seul événement `submit`.
|
|
127
|
+
On le valide par Entrée dans un `field`, par Ctrl+Entrée dans un `field` ou
|
|
128
|
+
un `textarea`, ou en activant un bouton doté de l’attribut `submit`.
|
|
129
|
+
|
|
130
|
+
<!-- source: widgets/twitch-chat/view.ocml -->
|
|
131
|
+
```xml
|
|
132
|
+
<form class="selector" on:submit={join}>
|
|
133
|
+
<field class="input channel" max-length="26" autofocus placeholder={t("channel-name")} label={t("channel-name")} on:input={channelTyped(event.value)}/>
|
|
134
|
+
<button class="action" submit disabled={!canJoin(state)}>
|
|
135
|
+
<text class="action-label">{t("join")}</text>
|
|
136
|
+
</button>
|
|
137
|
+
</form>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
<!-- source: widgets/twitch-chat/logic.ts -->
|
|
141
|
+
```ts
|
|
142
|
+
export function join(): void {
|
|
143
|
+
const channel = normalizeChannel(state.channelDraft);
|
|
144
|
+
if (channel !== null) {
|
|
145
|
+
joinChannel(channel);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Ce formulaire n’a pas d’intent : son gestionnaire `submit` lit ce que le
|
|
151
|
+
gestionnaire `input` a gardé dans l’état, puis appelle un service. `submit`
|
|
152
|
+
est une action de l’utilisateur : le gestionnaire peut donc appeler un
|
|
153
|
+
service qui en demande une (`twitch.chat.join` ici).
|
|
154
|
+
|
|
155
|
+
Un formulaire garde ce que l’utilisateur a saisi tant qu’il reste dans la
|
|
156
|
+
vue. Masquez-le avec `display: none` pour garder un brouillon ; retirez-le
|
|
157
|
+
de la vue pour l’abandonner. Pour repartir de champs vides, donnez au
|
|
158
|
+
formulaire une nouvelle clé dans un `for` : une nouvelle clé, c’est un
|
|
159
|
+
nouveau formulaire.
|
|
160
|
+
|
|
161
|
+
## Les formulaires qui écrivent des données de l’utilisateur
|
|
162
|
+
|
|
163
|
+
Trois opérations d’un widget écrivent, dans les données de l’utilisateur, un
|
|
164
|
+
texte que celui-ci a saisi : enregistrer une note, publier la note d’un jeu
|
|
165
|
+
sur PlayerVox avec son avis, et envoyer un message dans un chat Twitch. Ce ne
|
|
166
|
+
sont pas des appels de service. C’est un formulaire doté d’un attribut
|
|
167
|
+
`intent` qui les envoie :
|
|
168
|
+
|
|
169
|
+
<!-- source: widgets/twitch-chat/view.ocml -->
|
|
170
|
+
```xml
|
|
171
|
+
<form class={composerClass(state)} intent="twitch.chat.send" target={replyTarget(state)} on:submit={submitted(event.outcome, event.error)}>
|
|
172
|
+
<if test={state.reply}>
|
|
173
|
+
<box class="replying">
|
|
174
|
+
<text class="replying-label">{replyingTo(state)}</text>
|
|
175
|
+
<button class="icon-button small" label={t("cancel-reply")} tooltip={t("cancel-reply")} on:activate={cancelReply}>
|
|
176
|
+
<icon name="x"/>
|
|
177
|
+
</button>
|
|
178
|
+
</box>
|
|
179
|
+
</if>
|
|
180
|
+
<if test={state.sendError != ""}>
|
|
181
|
+
<text class="error">{t(state.sendError)}</text>
|
|
182
|
+
</if>
|
|
183
|
+
<box class="compose">
|
|
184
|
+
<field class="input message-field" name="message" max-length="500" placeholder={t(composerHint(state))} label={t("message-label")} disabled={!state.canSend} on:input={drafted(event.value)} on:keydown={keyed(event.key)}/>
|
|
185
|
+
<if test={sendMark(state) != ""}>
|
|
186
|
+
<text class={sendMarkClass(state)}>{t(sendMark(state))}</text>
|
|
187
|
+
</if>
|
|
188
|
+
<button class="action" submit disabled={!canSubmit(state)} on:activate={sendPressed}>
|
|
189
|
+
<text class="action-label">{t("send")}</text>
|
|
190
|
+
</button>
|
|
191
|
+
</box>
|
|
192
|
+
</form>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Quand l’utilisateur valide un tel formulaire, **OverCrow lit les valeurs des
|
|
196
|
+
contrôles de ce formulaire et les envoie lui-même**. La logique du widget ne
|
|
197
|
+
fournit jamais le texte : un widget ne peut donc ni écrire ce que
|
|
198
|
+
l’utilisateur n’a pas saisi, ni valider sans lui. Le formulaire ne part que
|
|
199
|
+
sur une action de l’utilisateur, en mode interactif, avec la capability
|
|
200
|
+
accordée.
|
|
201
|
+
|
|
202
|
+
Ce que cela change pour la vue et la logique :
|
|
203
|
+
|
|
204
|
+
- **Les contrôles appartiennent à OverCrow.** Les contrôles `field`,
|
|
205
|
+
`textarea` et `slider` du formulaire ne prennent pas de `value` :
|
|
206
|
+
`overcrow-widget check` le refuse (`view.bound_value`), et OverCrow arrête
|
|
207
|
+
un widget qui en définit un à l’exécution. Leur attribut `name` indique à
|
|
208
|
+
quel champ de l’intent chacun correspond.
|
|
209
|
+
- **OverCrow les remplit** là où l’intent le prévoit : le titre, le corps et
|
|
210
|
+
la liste de tâches de la note, la note publiée par l’utilisateur. Un
|
|
211
|
+
remplissage envoie l’événement `input` du contrôle avec la valeur, pour
|
|
212
|
+
que la logique sache ce qui est affiché ; cet événement n’est pas une
|
|
213
|
+
action de l’utilisateur.
|
|
214
|
+
- **La logique suit par les événements `input`**, pour afficher un compteur
|
|
215
|
+
ou activer le bouton, et peut désactiver les contrôles.
|
|
216
|
+
- **L’issue arrive dans l’événement `submit` du formulaire** :
|
|
217
|
+
`event.outcome` vaut `accepted`, `rejected` (avec le
|
|
218
|
+
[code d’erreur](services.md#erreurs) dans `event.error`) ou `cancelled`.
|
|
219
|
+
Un formulaire sans intent donne `submitted`.
|
|
220
|
+
|
|
221
|
+
<!-- source: widgets/playervox-rating/view.ocml -->
|
|
222
|
+
```xml
|
|
223
|
+
<slider class="criterion-slider" name="gameplay" min="0" max="100" step="1" label={t("gameplay")} disabled={!editable(state)} on:input={scored("gameplay", event.value)}/>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
<!-- source: widgets/playervox-rating/logic.ts -->
|
|
227
|
+
```ts
|
|
228
|
+
export function scored(key: CriterionKey, value: number): void {
|
|
229
|
+
state[key] = value;
|
|
230
|
+
edited();
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
<!-- source: widgets/playervox-rating/logic.ts -->
|
|
235
|
+
```ts
|
|
236
|
+
export function submitted(outcome: string, error: ServiceErrorPayload | undefined): void {
|
|
237
|
+
state.pending = Math.max(0, state.pending - 1);
|
|
238
|
+
if (state.pending === 0) {
|
|
239
|
+
answer?.cancel();
|
|
240
|
+
answer = null;
|
|
241
|
+
}
|
|
242
|
+
if (outcome === "accepted") {
|
|
243
|
+
// The subscription sends the stored rating; nothing is read again.
|
|
244
|
+
state.saved = true;
|
|
245
|
+
state.error = "";
|
|
246
|
+
} else if (outcome !== "cancelled") {
|
|
247
|
+
state.error = errorKey(error?.code ?? null);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Une écriture ne change pas d’elle-même ce que dit un abonnement : après une
|
|
253
|
+
note PlayerVox acceptée, `playervox.rating.subscribe` livre la note
|
|
254
|
+
enregistrée, et c’est elle que le widget affiche.
|
|
255
|
+
|
|
256
|
+
### Les intents
|
|
257
|
+
|
|
258
|
+
<!-- generated:write-intents -->
|
|
259
|
+
### `notes.save`
|
|
260
|
+
|
|
261
|
+
Capability `notes.write` ; attribut `target` obligatoire (l’ID de la note ; l’hôte remplit les contrôles liés à partir de cette note). Entrée dans un `field` du formulaire fait passer le focus à son `field` ou `textarea` suivant et ne valide pas ; Ctrl+Entrée et un bouton `submit` valident.
|
|
262
|
+
|
|
263
|
+
| Champ | Type | Obligatoire | Signification |
|
|
264
|
+
| --- | --- | --- | --- |
|
|
265
|
+
| `title` | texte ≤ 96 octets | oui | `field` ; enregistré sans espaces en début ni en fin, et non vide. |
|
|
266
|
+
| `body` | texte ≤ 8 Kio | non | `textarea` ; enregistré tel qu’il est écrit. |
|
|
267
|
+
| `item` | liste de `NoteItem` ≤ 64 | non | Un `field` par ligne de la liste de tâches, dans l’ordre, chacun ≤ 256 octets. L’hôte retient avec quelle entrée il a rempli chaque champ : une ligne garde l’ID et la coche de cette entrée quelles que soient les lignes que le widget retire ou déplace, et un champ apparu depuis est une nouvelle entrée, non cochée. Les lignes sont enregistrées sans espaces en début ni en fin ; une ligne vide est abandonnée. Une note enregistrée telle qu’elle est déjà stockée est acceptée sans écriture. |
|
|
268
|
+
|
|
269
|
+
### `playervox.rating.publish`
|
|
270
|
+
|
|
271
|
+
Capability `playervox.rating.write` ; attribut `target` refusé.
|
|
272
|
+
|
|
273
|
+
| Champ | Type | Obligatoire | Signification |
|
|
274
|
+
| --- | --- | --- | --- |
|
|
275
|
+
| `gameplay` | entier de 0 à 100 | oui | `slider` ; rempli à partir de la note de l’utilisateur, 50 avant la première. |
|
|
276
|
+
| `art` | entier de 0 à 100 | oui | `slider` ; rempli comme `gameplay`. |
|
|
277
|
+
| `tech` | entier de 0 à 100 | oui | `slider` ; rempli comme `gameplay`. |
|
|
278
|
+
| `review` | texte ≤ 2000 caractères | non | `textarea` ; rempli à partir de l’avis publié. Un avis inchangé n’est pas renvoyé ; un avis vidé est retiré. |
|
|
279
|
+
|
|
280
|
+
### `twitch.chat.send`
|
|
281
|
+
|
|
282
|
+
Capability `twitch.chat.compose` ; attribut `target` facultatif (l’ID du message auquel on répond).
|
|
283
|
+
|
|
284
|
+
| Champ | Type | Obligatoire | Signification |
|
|
285
|
+
| --- | --- | --- | --- |
|
|
286
|
+
| `message` | texte ≤ 500 caractères | oui | `field` ; l’hôte le vide après un envoi réussi. |
|
|
287
|
+
<!-- /generated:write-intents -->
|
|
288
|
+
|
|
289
|
+
`target` est l’attribut du formulaire qui désigne l’objet écrit :
|
|
290
|
+
l’identifiant de la note pour `notes.save`, l’identifiant du message auquel
|
|
291
|
+
on répond pour `twitch.chat.send`.
|
|
292
|
+
|
|
293
|
+
### Plusieurs lignes d’un même champ
|
|
294
|
+
|
|
295
|
+
L’intent `notes.save` prend un champ `item` par ligne de la liste de tâches.
|
|
296
|
+
La logique décide des lignes du formulaire, avec un `for` ; OverCrow remplit
|
|
297
|
+
le champ de chaque ligne à partir de la note enregistrée et retient quelle
|
|
298
|
+
entrée de la liste de tâches il y a placée. Une ligne que la logique retire
|
|
299
|
+
ou déplace garde son entrée, et une ligne ajoutée depuis est une nouvelle
|
|
300
|
+
entrée.
|
|
301
|
+
|
|
302
|
+
<!-- source: widgets/notes/view.ocml -->
|
|
303
|
+
```xml
|
|
304
|
+
<for each={editor.rows} as="row" key={row.key}>
|
|
305
|
+
<box class="row">
|
|
306
|
+
<if test={rowStored(state, editor, row)}>
|
|
307
|
+
<checkbox class="row-check" checked={rowChecked(state, editor, row)} label={rowLabel(row)} on:change={check(editor.note, row.id, event.value)}/>
|
|
308
|
+
</if>
|
|
309
|
+
<else>
|
|
310
|
+
<icon class="row-new" name="circle"/>
|
|
311
|
+
</else>
|
|
312
|
+
<field class="row-field" name="item" placeholder={rowHint(editor, row)} label={t("item-hint")} on:input={rowInput(editor.key, row.key, event.value)} on:keydown={keyed(editor.key, event.key, event.ctrl)}/>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Dans ce formulaire, Entrée passe au champ suivant au lieu de valider ;
|
|
316
|
+
Ctrl+Entrée ou le bouton `submit` enregistre.
|
|
317
|
+
|
|
318
|
+
## Confirmations
|
|
319
|
+
|
|
320
|
+
Deux services suppriment des données de l’utilisateur : `notes.delete` et
|
|
321
|
+
`journal.delete`. Ce sont des appels ordinaires qui demandent une action de
|
|
322
|
+
l’utilisateur. OverCrow demande ensuite à l’utilisateur de confirmer, dans
|
|
323
|
+
une boîte de dialogue qu’il dessine lui-même, hors du widget. L’appel
|
|
324
|
+
aboutit quand l’utilisateur confirme et échoue avec `cancelled` quand il
|
|
325
|
+
refuse. Ne dessinez pas votre propre « Êtes-vous sûr ? » : seule la
|
|
326
|
+
confirmation d’OverCrow compte.
|
|
327
|
+
|
|
328
|
+
## Points à vérifier pour un formulaire
|
|
329
|
+
|
|
330
|
+
- Chaque contrôle a un `label`.
|
|
331
|
+
- Les boutons qui ne peuvent pas agir sont `disabled`, et rien de ce qui
|
|
332
|
+
demande une entrée ne s’affiche en mode passif.
|
|
333
|
+
- Le gestionnaire `submit` traite un refus : `not_connected` quand le compte
|
|
334
|
+
est déconnecté, `busy` quand l’utilisateur envoie trop vite,
|
|
335
|
+
`unavailable`.
|
|
336
|
+
- Un formulaire lié à un intent n’a pas de `value` sur ses champs de texte
|
|
337
|
+
ni sur ses curseurs, et chaque contrôle nommé est un champ de l’intent.
|
|
338
|
+
- Testez-le avec un scénario : les étapes `text` saisissent du texte dans le
|
|
339
|
+
champ qui a le focus, les étapes `key` appuient sur Entrée, et
|
|
340
|
+
`expect.intents` vérifie exactement ce qu’OverCrow a envoyé. Voir
|
|
341
|
+
[Tester un widget](testing.md#steps).
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Guide du créateur
|
|
2
|
+
|
|
3
|
+
Ce guide mène un widget PlayerVox OverCrow d’un dossier vide à une
|
|
4
|
+
soumission : créer un projet, modifier sa vue, son style et sa logique, le
|
|
5
|
+
lancer dans OverCrow, le tester, l’empaqueter et le soumettre. Chaque étape
|
|
6
|
+
renvoie à la page qui la traite en détail.
|
|
7
|
+
|
|
8
|
+
Pour travailler plutôt avec un assistant IA, ajoutez-lui le serveur MCP
|
|
9
|
+
d’OverCrow : voir [MCP](mcp.md).
|
|
10
|
+
|
|
11
|
+
## 1. Installer les outils
|
|
12
|
+
|
|
13
|
+
- **`overcrow-widget`**, la CLI des widgets, un seul binaire pour Linux et
|
|
14
|
+
Windows. Voir [installer la CLI](cli.md#installation).
|
|
15
|
+
- **Node.js 22 ou plus récent** et npm, pour que `check` vérifie les types
|
|
16
|
+
de votre logique avec le TypeScript du projet et le SDK de npm. Sans lui, la CLI vérifie et
|
|
17
|
+
empaquette quand même, mais signale que les types n’ont pas été vérifiés.
|
|
18
|
+
- **OverCrow**, pour lancer le widget pendant que vous l’écrivez.
|
|
19
|
+
|
|
20
|
+
`overcrow-widget doctor` indique ce que votre installation a et ce qui lui
|
|
21
|
+
manque.
|
|
22
|
+
|
|
23
|
+
## 2. Créer un projet
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
overcrow-widget init my-counter --template counter
|
|
27
|
+
cd my-counter
|
|
28
|
+
npm install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`npm install` installe TypeScript et `@overcrow/sdk` 1.0.0, nommés dans le
|
|
32
|
+
`package.json` du projet.
|
|
33
|
+
|
|
34
|
+
Les templates sont `blank`, `counter`, `list` et `chart`. L’ID vaut par
|
|
35
|
+
défaut `com.example.<dir>` : passez `--id` avec un nom DNS inversé que vous
|
|
36
|
+
contrôlez (`com.playervox.*` est réservé).
|
|
37
|
+
[Fichiers d’un projet](cli.md#fichiers-dun-projet) liste chaque fichier et
|
|
38
|
+
indique lesquels sont empaquetés ;
|
|
39
|
+
[les types du SDK](cli.md#les-types-du-sdk) explique comment ajouter le SDK
|
|
40
|
+
à un autre projet.
|
|
41
|
+
|
|
42
|
+
## 3. La vue
|
|
43
|
+
|
|
44
|
+
`view.ocml` est du balisage : des éléments, des attributs, des expressions
|
|
45
|
+
`{…}` liées à l’état, et des gestionnaires `on:<event>` qui appellent des
|
|
46
|
+
fonctions exportées par la logique.
|
|
47
|
+
|
|
48
|
+
<!-- source: templates/counter/view.ocml -->
|
|
49
|
+
```xml
|
|
50
|
+
<box class="counter">
|
|
51
|
+
<text class="value">{state.count}</text>
|
|
52
|
+
<box class="actions">
|
|
53
|
+
<button class="step" label={t("decrement")} on:activate={decrement}>
|
|
54
|
+
<icon name="minus"/>
|
|
55
|
+
</button>
|
|
56
|
+
<button class="step" label={t("increment")} on:activate={increment}>
|
|
57
|
+
<icon name="plus"/>
|
|
58
|
+
</button>
|
|
59
|
+
</box>
|
|
60
|
+
</box>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
La vue offre aussi `if`, `for` avec une clé obligatoire, et des composants
|
|
64
|
+
locaux : voir [la vue](view.md). Chaque élément et chaque attribut figure
|
|
65
|
+
dans [éléments et attributs](elements.md).
|
|
66
|
+
|
|
67
|
+
## 4. Le style
|
|
68
|
+
|
|
69
|
+
`style.ocss` est un sous-ensemble borné de CSS : sélecteurs de classe,
|
|
70
|
+
d’élément, de descendant et d’enfant, états `:hover`, `:active`, `:focus`,
|
|
71
|
+
`:disabled` et `:checked`, mise en page flex et grid, et les tokens du thème
|
|
72
|
+
en `var(--…)`, qui suivent le thème clair ou sombre de l’utilisateur.
|
|
73
|
+
|
|
74
|
+
<!-- source: templates/counter/style.ocss -->
|
|
75
|
+
```css
|
|
76
|
+
.step {
|
|
77
|
+
width: var(--icon-button-size);
|
|
78
|
+
height: var(--icon-button-size);
|
|
79
|
+
border-radius: var(--radius-md);
|
|
80
|
+
background: var(--color-surface-raised);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
<!-- source: templates/counter/style.ocss -->
|
|
85
|
+
```css
|
|
86
|
+
.step:hover {
|
|
87
|
+
background: var(--color-surface-hover);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Il n’y a ni `@media`, ni `@import`, ni `url()`, ni `calc()` : une
|
|
92
|
+
propriété ou un sélecteur inconnu est une erreur, il n’est pas ignoré en
|
|
93
|
+
silence. Voir [le style](style.md) et
|
|
94
|
+
[propriétés de style et tokens](style-properties.md).
|
|
95
|
+
|
|
96
|
+
## 5. La logique
|
|
97
|
+
|
|
98
|
+
`logic.ts` possède l’état. Déclarez son type une fois, modifiez-le dans vos
|
|
99
|
+
gestionnaires, et la vue suit : après chaque tour, la VM évalue de nouveau
|
|
100
|
+
la vue et n’envoie que ce qui a changé.
|
|
101
|
+
|
|
102
|
+
<!-- source: templates/counter/logic.ts -->
|
|
103
|
+
```ts
|
|
104
|
+
import { initState } from "@overcrow/sdk";
|
|
105
|
+
|
|
106
|
+
declare module "@overcrow/sdk" {
|
|
107
|
+
interface WidgetState {
|
|
108
|
+
count: number;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
<!-- source: templates/counter/logic.ts -->
|
|
114
|
+
```ts
|
|
115
|
+
export function increment(): void {
|
|
116
|
+
state.count += 1;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
La logique tourne dans une VM enfermée dans un sandbox, pas dans un
|
|
121
|
+
navigateur : il n’y a ni DOM, ni `fetch`, ni `setTimeout`, ni `console`, ni
|
|
122
|
+
`Intl`. Le SDK fournit les minuteurs, les services, des fonctions de
|
|
123
|
+
formatage des heures et des nombres au format régional de l’utilisateur, les
|
|
124
|
+
messages et le dessin. Voir [la logique](logic.md) et la
|
|
125
|
+
[référence du SDK](sdk.md).
|
|
126
|
+
|
|
127
|
+
## 6. Les messages
|
|
128
|
+
|
|
129
|
+
`t("key")`, dans la vue ou la logique, lit `locales/en.json` ou
|
|
130
|
+
`locales/fr.json` selon la langue de l’utilisateur et remplit les paramètres
|
|
131
|
+
`{name}`.
|
|
132
|
+
|
|
133
|
+
<!-- source: templates/counter/locales/en.json -->
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"decrement": "Decrease",
|
|
137
|
+
"increment": "Increase"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Fournissez les deux fichiers ou aucun, avec les mêmes clés. Voir
|
|
142
|
+
[messages](logic.md#messages).
|
|
143
|
+
|
|
144
|
+
## 7. Vérifier
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
overcrow-widget check
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`check` exécute les mêmes validateurs qu’OverCrow : manifeste, vue, style,
|
|
151
|
+
messages, une analyse de la logique selon ce que la VM exécute, le
|
|
152
|
+
TypeScript du projet, et un paquet construit en mémoire puis relu. Chaque
|
|
153
|
+
problème a un code stable, une position et une ligne d’aide ; voir les
|
|
154
|
+
[diagnostics](cli.md#diagnostics).
|
|
155
|
+
|
|
156
|
+
## 8. Le lancer dans OverCrow
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
overcrow-widget dev
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`dev` envoie le widget à l’overlay OverCrow qui tourne sur votre machine et
|
|
163
|
+
le recharge à chaque enregistrement. OverCrow ne le propose que s’il a été
|
|
164
|
+
lancé avec les installations de développement autorisées
|
|
165
|
+
(`OVERCROW_WIDGET_DEVELOPMENT=1` ; `overcrow-widget doctor` affiche les
|
|
166
|
+
commandes). Le widget porte la mention
|
|
167
|
+
**Unverified · development package** ; ses permissions déclarées sont
|
|
168
|
+
accordées pour la session seulement, et rien n’est conservé. Les
|
|
169
|
+
`log.info(…)` de votre logique s’affichent dans le terminal. Voir
|
|
170
|
+
[le canal de développement](dev-channel.md).
|
|
171
|
+
|
|
172
|
+
## 9. Le tester
|
|
173
|
+
|
|
174
|
+
Deux sortes de tests, décrites dans [tester un widget](testing.md) :
|
|
175
|
+
|
|
176
|
+
- des tests unitaires de la logique avec `@overcrow/sdk/testing`, qui
|
|
177
|
+
exécute votre module avec un temps virtuel et des services simulés ;
|
|
178
|
+
- des scénarios joués par `overcrow-widget test` dans le runtime headless
|
|
179
|
+
d’OverCrow : la vraie VM et le vrai rendu, des services qui répondent avec
|
|
180
|
+
des fixtures (des données simulées), et des images comparées à des images
|
|
181
|
+
de référence.
|
|
182
|
+
|
|
183
|
+
<!-- source: templates/counter/tests/example.scenario.json -->
|
|
184
|
+
```json
|
|
185
|
+
"host": { "mode": "interactive" },
|
|
186
|
+
"steps": [
|
|
187
|
+
{ "expect": { "state": "running", "text": ["0"], "image": "initial" } },
|
|
188
|
+
{ "pointer": { "click": { "label": "Increase" } } },
|
|
189
|
+
{ "expect": { "text": ["1"], "noText": ["0"], "image": "increased", "fault": "none" } }
|
|
190
|
+
]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
overcrow-widget test
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## 10. Demander ce dont vous avez besoin
|
|
198
|
+
|
|
199
|
+
Un widget n’obtient rien par défaut. Pour appeler une API, conserver des
|
|
200
|
+
données ou lire des informations de jeu, déclarez-le dans `manifest.json` ;
|
|
201
|
+
l’utilisateur donne son accord dans le Centre de contrôle avant que le
|
|
202
|
+
widget n’y ait accès. Une règle
|
|
203
|
+
réseau nomme une origine HTTPS, une méthode et un chemin complet, avec des
|
|
204
|
+
paramètres typés :
|
|
205
|
+
|
|
206
|
+
<!-- source: docs/content/examples/weather/manifest.json -->
|
|
207
|
+
```json
|
|
208
|
+
"permissions": {
|
|
209
|
+
"network": [
|
|
210
|
+
{
|
|
211
|
+
"origin": "https://api.example.com",
|
|
212
|
+
"method": "GET",
|
|
213
|
+
"path": "/v1/forecast/{city}",
|
|
214
|
+
"pathParams": { "city": { "type": "slug", "maxLength": 32 } },
|
|
215
|
+
"queryParams": {
|
|
216
|
+
"units": { "type": "enum", "values": ["metric", "imperial"], "required": true }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
"storage": true
|
|
221
|
+
},
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
<!-- source: docs/content/examples/weather/logic.ts -->
|
|
225
|
+
```ts
|
|
226
|
+
const url = `https://api.example.com/v1/forecast/${state.city}?units=${state.units}`;
|
|
227
|
+
const { status, body } = await http.fetch(url, { as: "json" });
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Les données du jeu et du système viennent d’abonnements (`fps.subscribe`,
|
|
231
|
+
`media.subscribe`…), qui mettent votre état à jour jusqu’à ce que vous les
|
|
232
|
+
annuliez. [Services et permissions](services.md) explique ce que chaque
|
|
233
|
+
permission autorise, et [sécurité](security.md) ce qu’un widget ne peut
|
|
234
|
+
jamais faire. L’exemple complet se trouve dans
|
|
235
|
+
[`docs/content/examples/weather`](../examples/weather/).
|
|
236
|
+
|
|
237
|
+
## 11. Empaqueter
|
|
238
|
+
|
|
239
|
+
```sh
|
|
240
|
+
overcrow-widget package
|
|
241
|
+
overcrow-widget inspect dist/com.example.my-counter-0.1.0.ocpkg
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`package` écrit un `.ocpkg` déterministe dans `dist/` : les mêmes sources
|
|
245
|
+
et la même version de la CLI donnent les mêmes octets sur tous les systèmes.
|
|
246
|
+
`inspect` montre ce qu’un paquet contient et demande, comme le voit un
|
|
247
|
+
relecteur. Un paquet installé localement reste non vérifié ; les
|
|
248
|
+
utilisateurs obtiennent les widgets par le catalogue signé. Voir
|
|
249
|
+
[le paquet](package.md).
|
|
250
|
+
|
|
251
|
+
## 12. Soumettre
|
|
252
|
+
|
|
253
|
+
Ajoutez un `listing.json` avec le texte de la marketplace, lancez vous-même
|
|
254
|
+
l’admission, puis ouvrez une pull request qui ajoute votre widget sous
|
|
255
|
+
`widgets/<dir>/`, sur la branche `candidate` du
|
|
256
|
+
[dépôt public](https://github.com/Valhallab/playervox-overcrow-releases) :
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
overcrow-widget admit
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
`admit` exécute exactement les contrôles de la CI de la marketplace. La
|
|
263
|
+
suite, de la revue au catalogue signé, est décrite dans
|
|
264
|
+
[publication et revue](publishing.md).
|