@readymadeit/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/README.md +114 -2
- package/bundle/LICENSE +201 -0
- package/bundle/boards/aggregator-demo-board.json +54 -0
- package/bundle/boards/alpaca-board.json +316 -0
- package/bundle/boards/animate-board.json +159 -0
- package/bundle/boards/ascii-art-demo-board.json +33 -0
- package/bundle/boards/ascii-cam-board.json +184 -0
- package/bundle/boards/asset-demo-board.json +54 -0
- package/bundle/boards/audio-encode-demo-board.json +153 -0
- package/bundle/boards/audiolize-board.json +152 -0
- package/bundle/boards/batcher-demo-board.json +43 -0
- package/bundle/boards/buffer-demo-board.json +53 -0
- package/bundle/boards/cache-demo-board.json +59 -0
- package/bundle/boards/camera-demo-board.json +28 -0
- package/bundle/boards/canvas-demo-board.json +55 -0
- package/bundle/boards/changes-demo-board.json +60 -0
- package/bundle/boards/court-booking-browser-demo-board.json +221 -0
- package/bundle/boards/court-booking-demo-board.json +218 -0
- package/bundle/boards/current-time-board.json +32 -0
- package/bundle/boards/debounce-demo-board.json +43 -0
- package/bundle/boards/decrypt-demo-board.json +47 -0
- package/bundle/boards/delay-demo-board.json +28 -0
- package/bundle/boards/detect-demo-board.json +64 -0
- package/bundle/boards/document-extract-demo-board.json +55 -0
- package/bundle/boards/dropitapp-board.json +138 -0
- package/bundle/boards/encode-demo-board.json +39 -0
- package/bundle/boards/encrypt-board.json +185 -0
- package/bundle/boards/encrypt-demo-board.json +39 -0
- package/bundle/boards/face-alert-board.json +181 -0
- package/bundle/boards/fetcher-demo-board.json +40 -0
- package/bundle/boards/fft-demo-board.json +28 -0
- package/bundle/boards/filter-demo-board.json +55 -0
- package/bundle/boards/flat-map-demo-board.json +42 -0
- package/bundle/boards/frame-limit-test-board.json +130 -0
- package/bundle/boards/game-board.json +413 -0
- package/bundle/boards/game-of-life-board.json +139 -0
- package/bundle/boards/game-of-life-demo-board.json +34 -0
- package/bundle/boards/gather-demo-board.json +62 -0
- package/bundle/boards/group-by-demo-board.json +62 -0
- package/bundle/boards/hacker-demo-board.json +45 -0
- package/bundle/boards/hacker-news-board.json +741 -0
- package/bundle/boards/hash-demo-board.json +40 -0
- package/bundle/boards/health-log-browser-demo-board.json +537 -0
- package/bundle/boards/health-log-demo-board.json +498 -0
- package/bundle/boards/helloworld-board.json +57 -0
- package/bundle/boards/hold-demo-board.json +67 -0
- package/bundle/boards/hold-scopes-demo-board.json +141 -0
- package/bundle/boards/http-client-browser-demo-board.json +379 -0
- package/bundle/boards/http-client-demo-board.json +380 -0
- package/bundle/boards/image-picker-demo-board.json +22 -0
- package/bundle/boards/imap-email-demo-board.json +35 -0
- package/bundle/boards/injector-demo-board.json +55 -0
- package/bundle/boards/iterator-demo-board.json +55 -0
- package/bundle/boards/limit-demo-board.json +66 -0
- package/bundle/boards/link-debugger.json +32 -0
- package/bundle/boards/live-location-demo-board.json +93 -0
- package/bundle/boards/live-radio-cloud-demo-board.json +216 -0
- package/bundle/boards/live-radio-cloud-direct-demo-board.json +311 -0
- package/bundle/boards/live-radio-demo-board.json +211 -0
- package/bundle/boards/live-radio-members-demo-board.json +314 -0
- package/bundle/boards/local-storage-demo-board.json +30 -0
- package/bundle/boards/lz-compress-demo-board.json +52 -0
- package/bundle/boards/map-demo-board.json +46 -0
- package/bundle/boards/match-filter-demo-board.json +43 -0
- package/bundle/boards/meeting-poll-browser-demo-board.json +649 -0
- package/bundle/boards/meeting-poll-demo-board.json +650 -0
- package/bundle/boards/microphone-monitor-demo-board.json +28 -0
- package/bundle/boards/microphone-speaker-demo-board.json +86 -0
- package/bundle/boards/monitor-demo-board.json +52 -0
- package/bundle/boards/mounted-endpoint-demo-board-hkp-rt.json +84 -0
- package/bundle/boards/mounted-endpoint-demo-board.json +84 -0
- package/bundle/boards/nested-rhythm-demo-board.json +1160 -0
- package/bundle/boards/next-bus-board.json +52 -0
- package/bundle/boards/next-bus-switch-board.json +79 -0
- package/bundle/boards/night-groove-demo-board.json +742 -0
- package/bundle/boards/noise-alert-board.json +146 -0
- package/bundle/boards/offer-followup-demo-board.json +291 -0
- package/bundle/boards/offer-intake-demo-board.json +289 -0
- package/bundle/boards/offer-intake-hetzner-demo-board.json +286 -0
- package/bundle/boards/offer-intake-imap-demo-board.json +289 -0
- package/bundle/boards/offer-intake-imap-hetzner-demo-board.json +354 -0
- package/bundle/boards/p2p-receiver-demo-board.json +65 -0
- package/bundle/boards/p2p-sender-demo-board.json +94 -0
- package/bundle/boards/pad-groove-demo-board.json +644 -0
- package/bundle/boards/peer-chat-board.json +109 -0
- package/bundle/boards/peer-chat-node-board.json +97 -0
- package/bundle/boards/qr-code-demo-board.json +22 -0
- package/bundle/boards/queue-demo-board.json +239 -0
- package/bundle/boards/reduce-demo-board.json +54 -0
- package/bundle/boards/remote-named-demo-board-hkp-rt.json +61 -0
- package/bundle/boards/remote-named-demo-board.json +61 -0
- package/bundle/boards/rss-demo-board.json +530 -0
- package/bundle/boards/rss-radio-board.json +515 -0
- package/bundle/boards/rss-radio-brief-one-board.json +237 -0
- package/bundle/boards/rss-radio-editor-unit-board.json +555 -0
- package/bundle/boards/rss-radio-library-unit-board.json +293 -0
- package/bundle/boards/rss-radio-unit-board.json +809 -0
- package/bundle/boards/rss-radio-voice-unit-board.json +146 -0
- package/bundle/boards/runtime-configs/hold-example.json +41 -0
- package/bundle/boards/runtime-configs/injector-example.json +23 -0
- package/bundle/boards/runtime-configs/speech-to-text-example.json +35 -0
- package/bundle/boards/runtime-configs/text-generation-example.json +31 -0
- package/bundle/boards/runtime-configs/text-to-speech-example.json +28 -0
- package/bundle/boards/runtime-configs/text-to-speech-inflect-example.json +28 -0
- package/bundle/boards/runtime-configs/ws-audio-playback-example.json +23 -0
- package/bundle/boards/select-demo-board.json +32 -0
- package/bundle/boards/send-ntfy-board.json +52 -0
- package/bundle/boards/shared-costs-demo-board.json +361 -0
- package/bundle/boards/sign-demo-board.json +41 -0
- package/bundle/boards/skill-router-demo-board.json +210 -0
- package/bundle/boards/smooth-demo-board.json +91 -0
- package/bundle/boards/smtp-email-demo-board.json +34 -0
- package/bundle/boards/sort-demo-board.json +55 -0
- package/bundle/boards/sound-demo-board.json +65 -0
- package/bundle/boards/spectral-modifier-board.json +98 -0
- package/bundle/boards/speech-synth-demo-board.json +37 -0
- package/bundle/boards/speech-to-text-demo-board.json +146 -0
- package/bundle/boards/spotify-board.json +75 -0
- package/bundle/boards/spread-demo-board.json +35 -0
- package/bundle/boards/sql-demo-board.json +56 -0
- package/bundle/boards/sql-explorer-board.json +447 -0
- package/bundle/boards/sql-explorer-node-board.json +474 -0
- package/bundle/boards/sql-import-board.json +156 -0
- package/bundle/boards/state-demo-board.json +65 -0
- package/bundle/boards/stopper-demo-board.json +40 -0
- package/bundle/boards/storage-demo-board.json +193 -0
- package/bundle/boards/store-demo-board.json +63 -0
- package/bundle/boards/swimlanes-demo-board.json +197 -0
- package/bundle/boards/switch-demo-board.json +51 -0
- package/bundle/boards/syn-board.json +19 -0
- package/bundle/boards/syn-booking-unit-board.json +998 -0
- package/bundle/boards/syn-conversations-anthropic-demo-board.json +925 -0
- package/bundle/boards/syn-conversations-demo-board.json +925 -0
- package/bundle/boards/syn-hotels-unit-board.json +287 -0
- package/bundle/boards/syn-mail-desk-board.json +25 -0
- package/bundle/boards/syn-mail-desk-unit-board.json +254 -0
- package/bundle/boards/telegram-listener-demo-board.json +31 -0
- package/bundle/boards/text-generation-anthropic-demo-board.json +66 -0
- package/bundle/boards/text-generation-demo-board.json +51 -0
- package/bundle/boards/text-generation-local-demo-board.json +80 -0
- package/bundle/boards/text-to-speech-demo-board.json +58 -0
- package/bundle/boards/timeline-demo-board.json +477 -0
- package/bundle/boards/timer-demo-board.json +35 -0
- package/bundle/boards/tracks-demo-board.json +95 -0
- package/bundle/boards/trigger-pad-demo-board.json +47 -0
- package/bundle/boards/triggerpad-board.json +31 -0
- package/bundle/boards/triggerpad-recorder-board.json +56 -0
- package/bundle/boards/uuid-generator-demo-board.json +166 -0
- package/bundle/boards/voice-assistant-demo-board.json +230 -0
- package/bundle/boards/voice-assistant-hkp-rt-demo-board.json +239 -0
- package/bundle/boards/voice-assistant-local-demo-board.json +232 -0
- package/bundle/boards/voice-assistant-skills-demo-board.json +316 -0
- package/bundle/boards/voice-assistant-skills-local-demo-board.json +316 -0
- package/bundle/boards/xy-pad-demo-board.json +36 -0
- package/bundle/docs/content/board-json.md +277 -0
- package/bundle/docs/content/boards/alpaca-board.md +56 -0
- package/bundle/docs/content/boards/animate-board.md +40 -0
- package/bundle/docs/content/boards/ascii-cam-board.md +37 -0
- package/bundle/docs/content/boards/audiolize-board.md +47 -0
- package/bundle/docs/content/boards/court-booking-browser-demo-board.md +43 -0
- package/bundle/docs/content/boards/court-booking-demo-board.md +120 -0
- package/bundle/docs/content/boards/current-time-board.md +32 -0
- package/bundle/docs/content/boards/dropitapp-board.md +57 -0
- package/bundle/docs/content/boards/encrypt-board.md +36 -0
- package/bundle/docs/content/boards/face-alert-board.md +50 -0
- package/bundle/docs/content/boards/game-board.md +69 -0
- package/bundle/docs/content/boards/game-of-life-board.md +47 -0
- package/bundle/docs/content/boards/hacker-news-board.md +76 -0
- package/bundle/docs/content/boards/health-log-browser-demo-board.md +56 -0
- package/bundle/docs/content/boards/health-log-demo-board.md +138 -0
- package/bundle/docs/content/boards/helloworld-board.md +40 -0
- package/bundle/docs/content/boards/link-debugger.md +31 -0
- package/bundle/docs/content/boards/live-radio-cloud-demo-board.md +70 -0
- package/bundle/docs/content/boards/live-radio-cloud-direct-demo-board.md +89 -0
- package/bundle/docs/content/boards/live-radio-demo-board.md +102 -0
- package/bundle/docs/content/boards/live-radio-members-demo-board.md +91 -0
- package/bundle/docs/content/boards/meeting-poll-browser-demo-board.md +45 -0
- package/bundle/docs/content/boards/meeting-poll-demo-board.md +121 -0
- package/bundle/docs/content/boards/mounted-endpoint-demo-board-hkp-rt.md +50 -0
- package/bundle/docs/content/boards/nested-rhythm-demo-board.md +165 -0
- package/bundle/docs/content/boards/next-bus-board.md +38 -0
- package/bundle/docs/content/boards/next-bus-switch-board.md +44 -0
- package/bundle/docs/content/boards/night-groove-demo-board.md +110 -0
- package/bundle/docs/content/boards/noise-alert-board.md +44 -0
- package/bundle/docs/content/boards/pad-groove-demo-board.md +93 -0
- package/bundle/docs/content/boards/peer-chat-board.md +49 -0
- package/bundle/docs/content/boards/peer-chat-node-board.md +47 -0
- package/bundle/docs/content/boards/rss-radio-board.md +221 -0
- package/bundle/docs/content/boards/send-ntfy-board.md +33 -0
- package/bundle/docs/content/boards/shared-costs-demo-board.md +65 -0
- package/bundle/docs/content/boards/spectral-modifier-board.md +55 -0
- package/bundle/docs/content/boards/spotify-board.md +46 -0
- package/bundle/docs/content/boards/sql-explorer-board.md +70 -0
- package/bundle/docs/content/boards/sql-explorer-node-board.md +76 -0
- package/bundle/docs/content/boards/sql-import-board.md +37 -0
- package/bundle/docs/content/boards/swimlanes-demo-board.md +148 -0
- package/bundle/docs/content/boards/syn-mail-desk-board.md +52 -0
- package/bundle/docs/content/boards/timeline-demo-board.md +115 -0
- package/bundle/docs/content/boards/triggerpad-board.md +32 -0
- package/bundle/docs/content/boards/triggerpad-recorder-board.md +52 -0
- package/bundle/docs/content/boards/voice-assistant-demo-board.md +51 -0
- package/bundle/docs/content/concepts/assets.md +245 -0
- package/bundle/docs/content/concepts/blocks.md +300 -0
- package/bundle/docs/content/concepts/board-assistant.md +307 -0
- package/bundle/docs/content/concepts/board.md +265 -0
- package/bundle/docs/content/concepts/cloud-boards.md +803 -0
- package/bundle/docs/content/concepts/coordinator.md +297 -0
- package/bundle/docs/content/concepts/logging.md +293 -0
- package/bundle/docs/content/concepts/mounts.md +314 -0
- package/bundle/docs/content/concepts/presets.md +360 -0
- package/bundle/docs/content/concepts/remotes.md +423 -0
- package/bundle/docs/content/concepts/runtime.md +664 -0
- package/bundle/docs/content/concepts/scopes.md +256 -0
- package/bundle/docs/content/concepts/service.md +227 -0
- package/bundle/docs/content/concepts/units.md +321 -0
- package/bundle/docs/content/introduction.md +163 -0
- package/bundle/docs/content/llm/circle-text-board.json +55 -0
- package/bundle/docs/content/llm/howto-workflow.md +369 -0
- package/bundle/docs/content/repository.md +161 -0
- package/bundle/docs/content/services/aggregator.md +76 -0
- package/bundle/docs/content/services/analyzer.md +44 -0
- package/bundle/docs/content/services/ascii-art.md +58 -0
- package/bundle/docs/content/services/asset.md +88 -0
- package/bundle/docs/content/services/audio-editor.md +57 -0
- package/bundle/docs/content/services/audio-encode.md +115 -0
- package/bundle/docs/content/services/audio-io.md +173 -0
- package/bundle/docs/content/services/batcher.md +49 -0
- package/bundle/docs/content/services/board-service.md +48 -0
- package/bundle/docs/content/services/browser-sub-service.md +75 -0
- package/bundle/docs/content/services/buffer.md +70 -0
- package/bundle/docs/content/services/cache.md +92 -0
- package/bundle/docs/content/services/camera.md +85 -0
- package/bundle/docs/content/services/canvas.md +196 -0
- package/bundle/docs/content/services/changes.md +87 -0
- package/bundle/docs/content/services/chunked-file-provider.md +63 -0
- package/bundle/docs/content/services/communication-dispatcher.md +190 -0
- package/bundle/docs/content/services/configurator.md +66 -0
- package/bundle/docs/content/services/conversations.md +244 -0
- package/bundle/docs/content/services/debounce.md +45 -0
- package/bundle/docs/content/services/decrypt.md +53 -0
- package/bundle/docs/content/services/delay.md +55 -0
- package/bundle/docs/content/services/detect.md +101 -0
- package/bundle/docs/content/services/document-extract.md +174 -0
- package/bundle/docs/content/services/download.md +67 -0
- package/bundle/docs/content/services/encode.md +63 -0
- package/bundle/docs/content/services/encrypt.md +53 -0
- package/bundle/docs/content/services/fetcher.md +122 -0
- package/bundle/docs/content/services/fft.md +96 -0
- package/bundle/docs/content/services/file-source.md +67 -0
- package/bundle/docs/content/services/filesystem.md +157 -0
- package/bundle/docs/content/services/filter.md +133 -0
- package/bundle/docs/content/services/flat-map.md +62 -0
- package/bundle/docs/content/services/game-of-life.md +93 -0
- package/bundle/docs/content/services/gather.md +135 -0
- package/bundle/docs/content/services/gif-encoder.md +56 -0
- package/bundle/docs/content/services/github.md +85 -0
- package/bundle/docs/content/services/group-by.md +54 -0
- package/bundle/docs/content/services/hacker.md +79 -0
- package/bundle/docs/content/services/hash.md +59 -0
- package/bundle/docs/content/services/hold.md +182 -0
- package/bundle/docs/content/services/http-relay-client.md +48 -0
- package/bundle/docs/content/services/http-uploader.md +62 -0
- package/bundle/docs/content/services/http.md +424 -0
- package/bundle/docs/content/services/if.md +79 -0
- package/bundle/docs/content/services/ifft.md +46 -0
- package/bundle/docs/content/services/image-picker.md +50 -0
- package/bundle/docs/content/services/imap-email.md +104 -0
- package/bundle/docs/content/services/injector.md +129 -0
- package/bundle/docs/content/services/input.md +90 -0
- package/bundle/docs/content/services/iterator.md +186 -0
- package/bundle/docs/content/services/join.md +153 -0
- package/bundle/docs/content/services/limit.md +47 -0
- package/bundle/docs/content/services/local-storage.md +47 -0
- package/bundle/docs/content/services/looper.md +62 -0
- package/bundle/docs/content/services/lz-compress.md +52 -0
- package/bundle/docs/content/services/map.md +257 -0
- package/bundle/docs/content/services/match-filter.md +38 -0
- package/bundle/docs/content/services/microphone-monitor.md +66 -0
- package/bundle/docs/content/services/monitor.md +67 -0
- package/bundle/docs/content/services/ollama.md +116 -0
- package/bundle/docs/content/services/openai-prompt.md +74 -0
- package/bundle/docs/content/services/output.md +107 -0
- package/bundle/docs/content/services/peer-socket.md +61 -0
- package/bundle/docs/content/services/qr-code.md +48 -0
- package/bundle/docs/content/services/queue.md +201 -0
- package/bundle/docs/content/services/reduce.md +51 -0
- package/bundle/docs/content/services/rss.md +232 -0
- package/bundle/docs/content/services/select.md +47 -0
- package/bundle/docs/content/services/sign.md +53 -0
- package/bundle/docs/content/services/skill-router.md +154 -0
- package/bundle/docs/content/services/smooth.md +59 -0
- package/bundle/docs/content/services/smtp-email.md +129 -0
- package/bundle/docs/content/services/sort.md +48 -0
- package/bundle/docs/content/services/sound.md +87 -0
- package/bundle/docs/content/services/speech-synth.md +46 -0
- package/bundle/docs/content/services/speech-to-text.md +172 -0
- package/bundle/docs/content/services/spotify.md +77 -0
- package/bundle/docs/content/services/spread.md +111 -0
- package/bundle/docs/content/services/sql.md +491 -0
- package/bundle/docs/content/services/state.md +57 -0
- package/bundle/docs/content/services/static.md +47 -0
- package/bundle/docs/content/services/stopper.md +55 -0
- package/bundle/docs/content/services/storage.md +155 -0
- package/bundle/docs/content/services/store.md +255 -0
- package/bundle/docs/content/services/sub-service.md +152 -0
- package/bundle/docs/content/services/switch.md +67 -0
- package/bundle/docs/content/services/telegram-listener.md +76 -0
- package/bundle/docs/content/services/text-generation.md +390 -0
- package/bundle/docs/content/services/text-to-speech.md +130 -0
- package/bundle/docs/content/services/timeline.md +333 -0
- package/bundle/docs/content/services/timer.md +113 -0
- package/bundle/docs/content/services/tracks.md +207 -0
- package/bundle/docs/content/services/trigger-pad.md +68 -0
- package/bundle/docs/content/services/uuid-generator.md +48 -0
- package/bundle/docs/content/services/wav-reader.md +66 -0
- package/bundle/docs/content/services/websocket.md +189 -0
- package/bundle/docs/content/services/workflow-board-builder.md +65 -0
- package/bundle/docs/content/services/xy-pad.md +60 -0
- package/bundle/docs/content/targets.md +434 -0
- package/bundle/docs/content/testing.md +263 -0
- package/bundle/docs/content/vocabulary.md +171 -0
- package/bundle/hkp-frontend/src/runtime/browser/BrowserRegistry.tsx +141 -0
- package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntime.tsx +202 -0
- package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeApi.ts +306 -0
- package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeApp.ts +310 -0
- package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeScope.ts +500 -0
- package/bundle/hkp-frontend/src/runtime/browser/UIRegistry.ts +150 -0
- package/bundle/hkp-frontend/src/runtime/browser/assetResolver.ts +123 -0
- package/bundle/hkp-frontend/src/runtime/browser/pipelineNames.ts +65 -0
- package/bundle/hkp-frontend/src/runtime/browser/registry/Default.ts +237 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Aggregator.ts +127 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AggregatorUI.tsx +83 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Analyzer.tsx +43 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/Bars.tsx +33 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/HorizontalSpectrogram.tsx +53 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/VerticalSpectogram.tsx +56 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/Waveform.tsx +109 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/index.tsx +99 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AsciiArt.ts +119 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AsciiArtUI.tsx +131 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Asset.ts +125 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AssetUI.tsx +37 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AudioDeviceSettings.tsx +56 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AudioEditor.ts +129 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AudioEditorUI.tsx +549 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AudioInput.ts +298 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AudioInputUI.tsx +257 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AudioOutput.ts +189 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/AudioOutputUI.tsx +63 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Batcher.ts +11 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/BoardService.tsx +86 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/BoardServiceUI.tsx +410 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/BrowserGather.ts +311 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/BrowserIterator.ts +167 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/BrowserSubService.tsx +583 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/BrowserSubServiceUI.tsx +187 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/BrowserTracks.tsx +477 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Buffer.ts +11 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Cache.ts +134 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CacheUI.tsx +125 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Camera.ts +90 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CameraUI.tsx +321 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Canvas.ts +139 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/canvasDraw.ts +543 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/canvasUtils.ts +39 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/index.tsx +287 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/canvasDraw.test.ts +355 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/canvasUtils.test.ts +89 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/fullscreen.test.tsx +26 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Changes.ts +201 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/ChangesUI.tsx +85 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/ChunkedFileProvider.tsx +183 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Configurator.ts +258 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/ConfiguratorUI.tsx +83 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/ConsideredHacker.tsx +28 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Debounce.ts +75 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/DebounceUI.tsx +70 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Decrypt.ts +127 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/DecryptUI.tsx +39 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Delay.tsx +110 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Detect.ts +214 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/DetectUI.tsx +86 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Download.ts +120 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/DownloadUI.tsx +61 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Encode.ts +138 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/EncodeUI.tsx +52 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Encrypt.ts +125 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/EncryptUI.tsx +39 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FFT.tsx +238 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FFTUI.tsx +112 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FeedbackService.ts +247 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FeedbackServiceUI.tsx +35 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Fetcher.tsx +232 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FetcherUI.tsx +154 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FileSource.tsx +171 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Filter.tsx +18 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FilterUI.tsx +89 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FlatMap.ts +68 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/FlatMapUI.tsx +38 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLife.ts +210 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeRenderer.ts +182 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeRendererUI.tsx +48 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeUI.tsx +58 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GatherUI.tsx +84 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GifEncoder.tsx +651 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GithubAPI.ts +294 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GithubComponents.tsx +389 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GithubSink.tsx +109 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GithubSinkUI.tsx +143 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GithubSource.tsx +86 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GithubSourceUI.tsx +162 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/GroupBy.ts +11 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/HTTPUploader.ts +102 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Hacker.ts +73 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/HackerUI.tsx +134 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Hash.ts +134 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/HashUI.tsx +45 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Hold.ts +288 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/HoldUI.tsx +43 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/HttpClient.ts +558 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/HttpClientUI.tsx +212 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/HttpUploaderTokenInjector.ts +149 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/IfService.ts +231 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/IfServiceUI.tsx +50 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/ImagePicker.tsx +118 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Injector.ts +61 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/InjectorUI.tsx +389 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Input.ts +214 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/InputUI.tsx +71 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/IteratorUI.tsx +59 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/LZCompress.ts +63 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Limit.ts +39 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/LimitUI.tsx +41 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/LocalStorage.ts +65 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/LocalStorageUI.tsx +72 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Map.ts +14 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/MapUI.tsx +334 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/MapUIModeAssist.tsx +61 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/MatchFilter.ts +11 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/MicrophoneMonitor.ts +190 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/MicrophoneMonitorUI.tsx +94 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Monitor.tsx +15 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/MonitorUI.tsx +281 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPrompt.ts +237 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/BusyIndicator.tsx +18 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/PromptInput.tsx +71 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/StreamingPreview.tsx +24 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/index.tsx +156 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OpenAIPrompt.ts +254 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OpenAIPromptUI.tsx +189 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Output.tsx +145 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/OutputUI.tsx +118 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/PeerChatTemplate.json +43 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/PeerConnection.ts +260 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocket.tsx +268 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocketReceiverTemplate.json +29 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocketUI.tsx +341 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/PlaceholderUI.tsx +72 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/QrCode.ts +63 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/QrCodeUI.tsx +197 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Select.ts +40 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SelectUI.tsx +41 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/ServiceBase.ts +50 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SetRuntimeVariable.ts +65 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SetRuntimeVariableUI.tsx +50 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Sign.ts +182 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SignUI.tsx +55 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Smooth.ts +101 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SmoothUI.tsx +50 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Sort.ts +59 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SortUI.tsx +61 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Sound.ts +541 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SoundUI.tsx +183 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SpeechSynth.ts +56 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SpeechSynthUI.tsx +108 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Spotify.tsx +111 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyAPI.ts +113 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyComponents.tsx +104 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyUI.tsx +186 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Spread.ts +117 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SpreadUI.tsx +38 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Sql.ts +448 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SqlInspector.tsx +332 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SqlUI.tsx +226 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/State.ts +149 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Stopper.ts +29 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Switch.tsx +419 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/SwitchUI.tsx +171 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TickRuleDelta.ts +101 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TickRuleDeltaUI.tsx +56 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Timeline.ts +709 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/TimelinePanel.tsx +79 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/TimelineRows.tsx +574 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/Transport.tsx +141 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/index.tsx +119 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/model.ts +425 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/parts.tsx +708 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/Timer.ts +15 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TimerUI.tsx +213 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TracksUI.tsx +81 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TriggerPad.ts +108 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/TriggerPadUI.tsx +160 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/UuidGenerator.ts +74 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/UuidGeneratorUI.tsx +59 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/WaveformDisplay.tsx +104 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/WebsocketClient.ts +114 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/WebsocketClientUI.tsx +42 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/WorkflowBoardBuilder.ts +499 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/WorkflowBoardBuilderUI.tsx +521 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/XYPad.ts +68 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/XYPadUI.tsx +274 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/audio/audioHelper.ts +36 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/Batcher.ts +76 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/Buffer.ts +142 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/Filter.ts +125 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/GroupBy.ts +101 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/Map.ts +543 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/MatchFilter.ts +49 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/Monitor.ts +75 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/Reduce.ts +74 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/Timer.ts +342 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/bundle.js +7375 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/eval.ts +208 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/expressionEval.ts +223 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/helpers.ts +10 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/base/index.ts +37 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/camera/videoCapture.ts +78 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/changes-modes.ts +9 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/colorpalette.ts +26 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/detect/DetectionPreview.tsx +76 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/detect/mediapipe.ts +34 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/detect/models/README.md +14 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/detect/models/blaze_face_short_range.tflite +0 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/detect-modes.ts +7 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/encode-modes.ts +10 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/helpers.ts +300 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/http-client-methods.ts +10 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/sql-database.ts +594 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/sql-dump.ts +192 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/sql-inspect.ts +130 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/sql-inspector.css +155 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/sql-modes.ts +27 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/TESTING_APPROACH.md +169 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/__snapshots__/service-ui.future-enhancements.test.tsx.snap +5 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/audio-input-permissions.test.ts +42 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/audiolizeLanes.test.ts +70 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/browser-scopes.test.ts +305 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/cache-service.test.ts +53 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/camera-video-capture.test.ts +24 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/changes-service.test.ts +133 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/crypto-secrets.test.ts +196 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/detect-service.test.ts +119 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/download.test.ts +100 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/expressionEval.test.ts +117 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/fetcher-panel.test.tsx +35 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/fetcher-service.test.ts +80 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/filter-service.test.ts +37 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/github-secrets.test.ts +108 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/group-by-board.test.ts +42 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/hold-service.test.ts +199 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/http-client-service.test.ts +474 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/http-uploader-token-injector.test.ts +152 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/iterator-gather-service.test.ts +277 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/map-service.test.ts +1047 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/map-ui.test.tsx +70 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/nested-rhythm-board.test.ts +311 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/night-groove-board.test.ts +290 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/pad-groove-board.test.ts +230 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/peer-host-discovery.test.ts +77 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/peer-socket-discovery.test.ts +69 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/pipeline-names.test.ts +63 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/secret-canary.test.ts +121 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-modules.contract.test.ts +229 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.advanced.test.tsx +670 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.future-enhancements.test.tsx +219 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.integration.test.tsx +432 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.smoke.test.tsx +140 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/sound-service.test.ts +293 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/spread-service.test.ts +137 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-dump.test.ts +172 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-inspect.test.ts +163 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-inspector.test.tsx +121 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql.test.ts +702 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/sub-service-in-block.test.tsx +84 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/switch-service.test.ts +254 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-board.test.ts +218 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-service.test.ts +1002 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-ui-model.test.ts +230 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-ui.test.tsx +371 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/timer-service.test.ts +902 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/tracks-service.test.ts +275 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/tracks-ui.test.tsx +126 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/triggerpad-recorder-board.test.ts +100 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/tests/uuid-generator-service.test.ts +214 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/timeline-core.ts +410 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/DefaultWorkflowBoard.ts +90 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/RefinementSession.ts +121 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/SystemPromptCatalog.ts +245 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/catalog/browser-service-specs.json +110 -0
- package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/catalog/runtime-capabilities.json +37 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/asset-service.test.ts +73 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/board-persistence.integration.test.tsx +391 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/browser-runtime.identity-binding.test.tsx +81 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/demo-boards.regression.test.tsx +386 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/failed-call-lifecycle.test.ts +56 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/http-client.integration.test.ts +146 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/nested-run.integration.test.ts +415 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/replay-next.test.ts +391 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/rerun.test.ts +71 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/run-no-input.test.ts +72 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-add.integration.test.tsx +256 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-operations.integration.test.tsx +310 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-processing.integration.test.ts +311 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-removal.integration.test.tsx +454 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-update.identity.integration.test.tsx +145 -0
- package/bundle/hkp-frontend/src/runtime/browser/tests/service-operations.integration.test.tsx +511 -0
- package/bundle/hkp-node/src/address.ts +72 -0
- package/bundle/hkp-node/src/assets.ts +582 -0
- package/bundle/hkp-node/src/auth.ts +369 -0
- package/bundle/hkp-node/src/callReport.ts +281 -0
- package/bundle/hkp-node/src/coordinator/auth.ts +85 -0
- package/bundle/hkp-node/src/coordinator/binaryFrame.ts +189 -0
- package/bundle/hkp-node/src/coordinator/boardStore.ts +0 -0
- package/bundle/hkp-node/src/coordinator/bridge.ts +242 -0
- package/bundle/hkp-node/src/coordinator/bridgeProtocol.ts +200 -0
- package/bundle/hkp-node/src/coordinator/coordinator.ts +594 -0
- package/bundle/hkp-node/src/coordinator/facadeAccess.ts +426 -0
- package/bundle/hkp-node/src/coordinator/fileBoardStore.ts +159 -0
- package/bundle/hkp-node/src/coordinator/frameLimits.ts +41 -0
- package/bundle/hkp-node/src/coordinator/index.ts +12 -0
- package/bundle/hkp-node/src/coordinator/join.ts +62 -0
- package/bundle/hkp-node/src/coordinator/logStore.ts +335 -0
- package/bundle/hkp-node/src/coordinator/members.ts +133 -0
- package/bundle/hkp-node/src/coordinator/mount.ts +124 -0
- package/bundle/hkp-node/src/coordinator/participantProtocol.ts +169 -0
- package/bundle/hkp-node/src/coordinator/participants.ts +666 -0
- package/bundle/hkp-node/src/coordinator/router.ts +416 -0
- package/bundle/hkp-node/src/coordinator/session.ts +1610 -0
- package/bundle/hkp-node/src/coordinator/types.ts +95 -0
- package/bundle/hkp-node/src/coordinatorLinks.ts +712 -0
- package/bundle/hkp-node/src/credentialedFetch.ts +122 -0
- package/bundle/hkp-node/src/egress.ts +344 -0
- package/bundle/hkp-node/src/expressionEval.ts +223 -0
- package/bundle/hkp-node/src/index.ts +470 -0
- package/bundle/hkp-node/src/instance.ts +172 -0
- package/bundle/hkp-node/src/mounts.ts +296 -0
- package/bundle/hkp-node/src/origins.ts +201 -0
- package/bundle/hkp-node/src/reset.ts +187 -0
- package/bundle/hkp-node/src/runtime.ts +1345 -0
- package/bundle/hkp-node/src/secrets.ts +292 -0
- package/bundle/hkp-node/src/server.ts +2120 -0
- package/bundle/hkp-node/src/services/asset.ts +150 -0
- package/bundle/hkp-node/src/services/claudeModels.ts +370 -0
- package/bundle/hkp-node/src/services/communication-dispatcher.ts +735 -0
- package/bundle/hkp-node/src/services/conversations.ts +914 -0
- package/bundle/hkp-node/src/services/database.ts +386 -0
- package/bundle/hkp-node/src/services/document-extract.ts +575 -0
- package/bundle/hkp-node/src/services/expression.ts +417 -0
- package/bundle/hkp-node/src/services/fileStore.ts +369 -0
- package/bundle/hkp-node/src/services/filesystem.ts +280 -0
- package/bundle/hkp-node/src/services/gather.ts +335 -0
- package/bundle/hkp-node/src/services/hold.ts +275 -0
- package/bundle/hkp-node/src/services/http-client.ts +525 -0
- package/bundle/hkp-node/src/services/http-server.ts +1222 -0
- package/bundle/hkp-node/src/services/imap-email.ts +627 -0
- package/bundle/hkp-node/src/services/injector.ts +135 -0
- package/bundle/hkp-node/src/services/iterator.ts +203 -0
- package/bundle/hkp-node/src/services/join.ts +226 -0
- package/bundle/hkp-node/src/services/map.ts +632 -0
- package/bundle/hkp-node/src/services/monitor.ts +128 -0
- package/bundle/hkp-node/src/services/nested-pipeline.ts +405 -0
- package/bundle/hkp-node/src/services/peer-server.ts +268 -0
- package/bundle/hkp-node/src/services/queue-store.ts +301 -0
- package/bundle/hkp-node/src/services/queue.ts +316 -0
- package/bundle/hkp-node/src/services/recordStore.ts +341 -0
- package/bundle/hkp-node/src/services/rss-parse.ts +281 -0
- package/bundle/hkp-node/src/services/rss.ts +392 -0
- package/bundle/hkp-node/src/services/smtp-email.ts +398 -0
- package/bundle/hkp-node/src/services/spread.ts +153 -0
- package/bundle/hkp-node/src/services/sql-dump.ts +192 -0
- package/bundle/hkp-node/src/services/sql.ts +429 -0
- package/bundle/hkp-node/src/services/stopper.ts +69 -0
- package/bundle/hkp-node/src/services/storage.ts +332 -0
- package/bundle/hkp-node/src/services/store.ts +609 -0
- package/bundle/hkp-node/src/services/stream.ts +367 -0
- package/bundle/hkp-node/src/services/sub-service.ts +600 -0
- package/bundle/hkp-node/src/services/telegram-listener.ts +263 -0
- package/bundle/hkp-node/src/services/telegram-sender.ts +136 -0
- package/bundle/hkp-node/src/services/text-generation.ts +1249 -0
- package/bundle/hkp-node/src/services/timer.ts +273 -0
- package/bundle/hkp-node/src/services/tracks.ts +381 -0
- package/bundle/hkp-node/src/services/websocket-reader.ts +364 -0
- package/bundle/hkp-node/src/types.ts +465 -0
- package/bundle/hkp-node/src/wsTickets.ts +77 -0
- package/bundle/hkp-node/src/yas.ts +95 -0
- package/bundle/hkp-python/src/hkp/__init__.py +1 -0
- package/bundle/hkp-python/src/hkp/__main__.py +241 -0
- package/bundle/hkp-python/src/hkp/address.py +56 -0
- package/bundle/hkp-python/src/hkp/assets.py +439 -0
- package/bundle/hkp-python/src/hkp/auth.py +252 -0
- package/bundle/hkp-python/src/hkp/binary_frame.py +100 -0
- package/bundle/hkp-python/src/hkp/call_report.py +201 -0
- package/bundle/hkp-python/src/hkp/coordinator_links.py +667 -0
- package/bundle/hkp-python/src/hkp/data.py +118 -0
- package/bundle/hkp-python/src/hkp/egress.py +310 -0
- package/bundle/hkp-python/src/hkp/mount.py +46 -0
- package/bundle/hkp-python/src/hkp/mounts.py +288 -0
- package/bundle/hkp-python/src/hkp/origins.py +169 -0
- package/bundle/hkp-python/src/hkp/runtime.py +1131 -0
- package/bundle/hkp-python/src/hkp/secrets.py +261 -0
- package/bundle/hkp-python/src/hkp/server.py +1714 -0
- package/bundle/hkp-python/src/hkp/services/__init__.py +0 -0
- package/bundle/hkp-python/src/hkp/services/asset.py +123 -0
- package/bundle/hkp-python/src/hkp/services/audio_encode.py +190 -0
- package/bundle/hkp-python/src/hkp/services/expression.py +942 -0
- package/bundle/hkp-python/src/hkp/services/gather.py +266 -0
- package/bundle/hkp-python/src/hkp/services/hold.py +246 -0
- package/bundle/hkp-python/src/hkp/services/http_client.py +444 -0
- package/bundle/hkp-python/src/hkp/services/http_server.py +790 -0
- package/bundle/hkp-python/src/hkp/services/iterator.py +141 -0
- package/bundle/hkp-python/src/hkp/services/join.py +173 -0
- package/bundle/hkp-python/src/hkp/services/map_service.py +452 -0
- package/bundle/hkp-python/src/hkp/services/monitor.py +99 -0
- package/bundle/hkp-python/src/hkp/services/nested_pipeline.py +278 -0
- package/bundle/hkp-python/src/hkp/services/skill_router.py +388 -0
- package/bundle/hkp-python/src/hkp/services/speech_to_text.py +186 -0
- package/bundle/hkp-python/src/hkp/services/spread.py +114 -0
- package/bundle/hkp-python/src/hkp/services/stopper.py +59 -0
- package/bundle/hkp-python/src/hkp/services/sub_service.py +417 -0
- package/bundle/hkp-python/src/hkp/services/text_generation.py +498 -0
- package/bundle/hkp-python/src/hkp/services/text_to_speech.py +237 -0
- package/bundle/hkp-python/src/hkp/services/timer.py +267 -0
- package/bundle/hkp-python/src/hkp/services/tracks.py +251 -0
- package/bundle/hkp-python/src/hkp/types.py +412 -0
- package/bundle/hkp-python/src/hkp/ws_tickets.py +54 -0
- package/bundle/hkp-python/src/hkp/yas.py +192 -0
- package/bundle/hkp-rt/lib/CMakeLists.txt +193 -0
- package/bundle/hkp-rt/lib/hkp-bundles/CMakeLists.txt +55 -0
- package/bundle/hkp-rt/lib/hkp-bundles/plugin_register.cpp +14 -0
- package/bundle/hkp-rt/lib/include/app.h +201 -0
- package/bundle/hkp-rt/lib/include/assets.h +239 -0
- package/bundle/hkp-rt/lib/include/auth.h +167 -0
- package/bundle/hkp-rt/lib/include/call_report.h +197 -0
- package/bundle/hkp-rt/lib/include/coordinator_links.h +127 -0
- package/bundle/hkp-rt/lib/include/discovery_hooks.h +29 -0
- package/bundle/hkp-rt/lib/include/egress.h +379 -0
- package/bundle/hkp-rt/lib/include/files.h +275 -0
- package/bundle/hkp-rt/lib/include/log_entry.h +131 -0
- package/bundle/hkp-rt/lib/include/mounts.h +139 -0
- package/bundle/hkp-rt/lib/include/origins.h +363 -0
- package/bundle/hkp-rt/lib/include/registry.h +119 -0
- package/bundle/hkp-rt/lib/include/secrets.h +414 -0
- package/bundle/hkp-rt/lib/include/server.h +122 -0
- package/bundle/hkp-rt/lib/include/service.h +190 -0
- package/bundle/hkp-rt/lib/include/slot_store.h +41 -0
- package/bundle/hkp-rt/lib/include/standalone_config.h +253 -0
- package/bundle/hkp-rt/lib/include/types/audio.h +3 -0
- package/bundle/hkp-rt/lib/include/types/data.h +152 -0
- package/bundle/hkp-rt/lib/include/types/message.h +56 -0
- package/bundle/hkp-rt/lib/include/types/models.h +154 -0
- package/bundle/hkp-rt/lib/include/types/owns_me.h +19 -0
- package/bundle/hkp-rt/lib/include/types/ringbuffer.h +86 -0
- package/bundle/hkp-rt/lib/include/types/types.h +33 -0
- package/bundle/hkp-rt/lib/include/types/validation.h +205 -0
- package/bundle/hkp-rt/lib/src/address.h +88 -0
- package/bundle/hkp-rt/lib/src/app.cpp +591 -0
- package/bundle/hkp-rt/lib/src/assets.cpp +686 -0
- package/bundle/hkp-rt/lib/src/binary_frame.h +154 -0
- package/bundle/hkp-rt/lib/src/common/expression.h +1481 -0
- package/bundle/hkp-rt/lib/src/common/inja.h +36 -0
- package/bundle/hkp-rt/lib/src/common/link_socket.cpp +437 -0
- package/bundle/hkp-rt/lib/src/common/link_socket.h +97 -0
- package/bundle/hkp-rt/lib/src/common/realtime_wakeup.h +120 -0
- package/bundle/hkp-rt/lib/src/common/stream_broadcast.h +250 -0
- package/bundle/hkp-rt/lib/src/common/string_util.h +31 -0
- package/bundle/hkp-rt/lib/src/common/websocket_client_session.cpp +217 -0
- package/bundle/hkp-rt/lib/src/common/websocket_client_session.h +37 -0
- package/bundle/hkp-rt/lib/src/common/websocket_config.h +119 -0
- package/bundle/hkp-rt/lib/src/common/websocket_protocol.h +32 -0
- package/bundle/hkp-rt/lib/src/common/websocket_server.cpp +82 -0
- package/bundle/hkp-rt/lib/src/common/websocket_server.h +57 -0
- package/bundle/hkp-rt/lib/src/common/websocket_server_listener.cpp +115 -0
- package/bundle/hkp-rt/lib/src/common/websocket_server_listener.h +35 -0
- package/bundle/hkp-rt/lib/src/common/websocket_server_session.cpp +172 -0
- package/bundle/hkp-rt/lib/src/common/websocket_server_session.h +53 -0
- package/bundle/hkp-rt/lib/src/common.h +13 -0
- package/bundle/hkp-rt/lib/src/coordinator_links.cpp +1142 -0
- package/bundle/hkp-rt/lib/src/discovery/discovery.cpp +707 -0
- package/bundle/hkp-rt/lib/src/discovery/discovery.h +89 -0
- package/bundle/hkp-rt/lib/src/http/auth.cpp +569 -0
- package/bundle/hkp-rt/lib/src/http/front_door.cpp +518 -0
- package/bundle/hkp-rt/lib/src/http/front_door.h +131 -0
- package/bundle/hkp-rt/lib/src/http/server.cpp +1539 -0
- package/bundle/hkp-rt/lib/src/http/ws_tickets.h +125 -0
- package/bundle/hkp-rt/lib/src/mount.h +63 -0
- package/bundle/hkp-rt/lib/src/process_context.h +335 -0
- package/bundle/hkp-rt/lib/src/process_depth.h +20 -0
- package/bundle/hkp-rt/lib/src/registry.cpp +233 -0
- package/bundle/hkp-rt/lib/src/runtime.cpp +986 -0
- package/bundle/hkp-rt/lib/src/runtime.h +225 -0
- package/bundle/hkp-rt/lib/src/runtime_host.h +180 -0
- package/bundle/hkp-rt/lib/src/service.cpp +315 -0
- package/bundle/hkp-rt/lib/src/services/asset.h +185 -0
- package/bundle/hkp-rt/lib/src/services/audio_encode.cpp +372 -0
- package/bundle/hkp-rt/lib/src/services/audio_encode.h +97 -0
- package/bundle/hkp-rt/lib/src/services/cache.h +362 -0
- package/bundle/hkp-rt/lib/src/services/cache_subservices.h +463 -0
- package/bundle/hkp-rt/lib/src/services/core_audio.cpp +384 -0
- package/bundle/hkp-rt/lib/src/services/core_audio.h +22 -0
- package/bundle/hkp-rt/lib/src/services/core_input.h +337 -0
- package/bundle/hkp-rt/lib/src/services/core_output.h +370 -0
- package/bundle/hkp-rt/lib/src/services/ffmpeg/detail.cpp +749 -0
- package/bundle/hkp-rt/lib/src/services/ffmpeg/detail.h +29 -0
- package/bundle/hkp-rt/lib/src/services/ffmpeg/ffmpeg.cpp +193 -0
- package/bundle/hkp-rt/lib/src/services/ffmpeg/ffmpeg.h +40 -0
- package/bundle/hkp-rt/lib/src/services/ffmpeg/types.h +120 -0
- package/bundle/hkp-rt/lib/src/services/fft_service.h +190 -0
- package/bundle/hkp-rt/lib/src/services/filesystem.h +309 -0
- package/bundle/hkp-rt/lib/src/services/filter.h +208 -0
- package/bundle/hkp-rt/lib/src/services/gather.h +272 -0
- package/bundle/hkp-rt/lib/src/services/hold.h +304 -0
- package/bundle/hkp-rt/lib/src/services/http_client.cpp +347 -0
- package/bundle/hkp-rt/lib/src/services/http_client.h +67 -0
- package/bundle/hkp-rt/lib/src/services/http_client_impl.h +45 -0
- package/bundle/hkp-rt/lib/src/services/http_client_template_examples.md +202 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_listener.cpp +130 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_listener.h +33 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_server.cpp +351 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_server.h +79 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_server_impl.cpp +230 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_server_impl.h +64 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_server_subservices.cpp +950 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_server_subservices.h +253 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_session.cpp +495 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_session.h +169 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_stream_listener.cpp +270 -0
- package/bundle/hkp-rt/lib/src/services/http_server/http_stream_listener.h +104 -0
- package/bundle/hkp-rt/lib/src/services/http_server/request_decode.h +164 -0
- package/bundle/hkp-rt/lib/src/services/if_service.h +210 -0
- package/bundle/hkp-rt/lib/src/services/ifft_service.h +198 -0
- package/bundle/hkp-rt/lib/src/services/injector.h +162 -0
- package/bundle/hkp-rt/lib/src/services/iterator.h +201 -0
- package/bundle/hkp-rt/lib/src/services/map.h +641 -0
- package/bundle/hkp-rt/lib/src/services/monitor.h +161 -0
- package/bundle/hkp-rt/lib/src/services/mp3_frames.h +119 -0
- package/bundle/hkp-rt/lib/src/services/mp4_to_wav.cpp +281 -0
- package/bundle/hkp-rt/lib/src/services/mp4_to_wav.h +263 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_registry.cpp +88 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_registry.h +43 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_server.h +163 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_listener.cpp +133 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_listener.h +46 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_session.cpp +165 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_session.h +44 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_ws_session.cpp +184 -0
- package/bundle/hkp-rt/lib/src/services/peer_server/peer_ws_session.h +55 -0
- package/bundle/hkp-rt/lib/src/services/receiver_session.h +172 -0
- package/bundle/hkp-rt/lib/src/services/root_certificates.h +3959 -0
- package/bundle/hkp-rt/lib/src/services/sha256_openssl.h +49 -0
- package/bundle/hkp-rt/lib/src/services/speech_http.h +306 -0
- package/bundle/hkp-rt/lib/src/services/speech_to_text.cpp +595 -0
- package/bundle/hkp-rt/lib/src/services/speech_to_text.h +69 -0
- package/bundle/hkp-rt/lib/src/services/static.cpp +45 -0
- package/bundle/hkp-rt/lib/src/services/static.h +41 -0
- package/bundle/hkp-rt/lib/src/services/stopper.h +72 -0
- package/bundle/hkp-rt/lib/src/services/sub_service.h +286 -0
- package/bundle/hkp-rt/lib/src/services/text_generation.cpp +1132 -0
- package/bundle/hkp-rt/lib/src/services/text_generation.h +71 -0
- package/bundle/hkp-rt/lib/src/services/text_to_speech.cpp +853 -0
- package/bundle/hkp-rt/lib/src/services/text_to_speech.h +97 -0
- package/bundle/hkp-rt/lib/src/services/timer.h +300 -0
- package/bundle/hkp-rt/lib/src/services/tracks.h +397 -0
- package/bundle/hkp-rt/lib/src/services/tts_inflect.cpp +149 -0
- package/bundle/hkp-rt/lib/src/services/tts_inflect.h +82 -0
- package/bundle/hkp-rt/lib/src/services/wav_reader.h +213 -0
- package/bundle/hkp-rt/lib/src/services/websocket_client_service.h +182 -0
- package/bundle/hkp-rt/lib/src/services/websocket_reader.h +148 -0
- package/bundle/hkp-rt/lib/src/services/websocket_server_service.h +196 -0
- package/bundle/hkp-rt/lib/src/services/websocket_writer.cpp +641 -0
- package/bundle/hkp-rt/lib/src/services/websocket_writer.h +117 -0
- package/bundle/hkp-rt/lib/src/sub_runtime.cpp +234 -0
- package/bundle/hkp-rt/lib/src/sub_runtime.h +160 -0
- package/bundle/hkp-rt/lib/src/types/data.cpp +237 -0
- package/bundle/hkp-rt/lib/src/types/message.cpp +148 -0
- package/bundle/hkp-rt/lib/src/types/models.cpp +83 -0
- package/bundle/hkp-rt/lib/src/types/ringbuffer.cpp +336 -0
- package/bundle/hkp-rt/lib/src/uuid.h +12 -0
- package/bundle/readymade-mcp-commits.json +5 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +79 -0
- package/dist/git.d.ts +8 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +53 -0
- package/dist/http.d.ts +17 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +130 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/repository.d.ts +49 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +452 -0
- package/dist/schemas.d.ts +156 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +43 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +83 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/validation.d.ts +9 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +101 -0
- package/package.json +52 -4
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a syndication feed, without a dependency to do it.
|
|
3
|
+
*
|
|
4
|
+
* RSS 2.0, RSS 1.0 (RDF) and Atom are three documents that say the same few
|
|
5
|
+
* things under different names, and this narrows them to one shape: an item has
|
|
6
|
+
* a title, somewhere to read it, when it was published, and a line about what
|
|
7
|
+
* it is. Everything else a feed carries is dropped here rather than downstream,
|
|
8
|
+
* because a board that merges several feeds can only sort and show fields all
|
|
9
|
+
* of them have.
|
|
10
|
+
*
|
|
11
|
+
* It is a scanner over the markup rather than a general XML parser. That is the
|
|
12
|
+
* honest description of what it can do: it finds the element boundaries these
|
|
13
|
+
* three formats use, unwraps CDATA, and decodes the entities that appear in
|
|
14
|
+
* feed text. A document that would need a real parser to read — arbitrary
|
|
15
|
+
* namespaces, nested elements of the same name — is out of its range, and the
|
|
16
|
+
* answer for one is a proper parser, not more regular expressions.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** One article, in the vocabulary every feed format can be reduced to. */
|
|
20
|
+
export type FeedItem = {
|
|
21
|
+
/** The feed's own identity for the item — guid, id, or the link. */
|
|
22
|
+
id: string;
|
|
23
|
+
title: string;
|
|
24
|
+
/** Where to read it. Empty when the feed offered no readable address. */
|
|
25
|
+
link: string;
|
|
26
|
+
author: string;
|
|
27
|
+
/** A line about the item, with its markup stripped. */
|
|
28
|
+
summary: string;
|
|
29
|
+
/** When it was published, ISO 8601, or "" when the feed did not say. */
|
|
30
|
+
published: string;
|
|
31
|
+
/**
|
|
32
|
+
* The same instant as `YYYY-MM-DD HH:mm`, in UTC.
|
|
33
|
+
*
|
|
34
|
+
* A merged list shows a date on every row, so deriving one is work every
|
|
35
|
+
* consumer would otherwise repeat — and a board has no date formatter to
|
|
36
|
+
* repeat it with. UTC rather than a local zone because the formatting happens
|
|
37
|
+
* wherever the runtime is, which is not where the reader is.
|
|
38
|
+
*/
|
|
39
|
+
publishedLabel: string;
|
|
40
|
+
/**
|
|
41
|
+
* The same instant in epoch milliseconds, which is what sorting uses.
|
|
42
|
+
* An item with no date sorts as 0 — last — rather than as now, so a feed
|
|
43
|
+
* that omits dates cannot crowd out the ones that keep them.
|
|
44
|
+
*/
|
|
45
|
+
publishedMs: number;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type ParsedFeed = {
|
|
49
|
+
/** What the feed calls itself, for a board that did not name it. */
|
|
50
|
+
title: string;
|
|
51
|
+
items: FeedItem[];
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `<item>` in RSS and RDF, `<entry>` in Atom.
|
|
56
|
+
*
|
|
57
|
+
* The opening tag is captured alongside the body because RDF puts the item's
|
|
58
|
+
* address in an attribute of it (`rdf:about`) rather than in an element.
|
|
59
|
+
*/
|
|
60
|
+
const ITEM_BLOCK = /<(item|entry)((?:\s[^>]*)?)>([\s\S]*?)<\/\1\s*>/gi;
|
|
61
|
+
|
|
62
|
+
const COMMENT = /<!--[\s\S]*?-->/g;
|
|
63
|
+
|
|
64
|
+
const CDATA = /^\s*<!\[CDATA\[([\s\S]*?)\]\]>\s*$/;
|
|
65
|
+
|
|
66
|
+
const NAMED_ENTITIES: Record<string, string> = {
|
|
67
|
+
amp: "&",
|
|
68
|
+
lt: "<",
|
|
69
|
+
gt: ">",
|
|
70
|
+
quot: '"',
|
|
71
|
+
apos: "'",
|
|
72
|
+
nbsp: " ",
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/** One pass of entity decoding — the unit the two callers compose. */
|
|
76
|
+
function decodeOnce(value: string): string {
|
|
77
|
+
return value.replace(
|
|
78
|
+
/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g,
|
|
79
|
+
(match, body: string): string => {
|
|
80
|
+
if (body.startsWith("#x") || body.startsWith("#X")) {
|
|
81
|
+
const code = Number.parseInt(body.slice(2), 16);
|
|
82
|
+
return Number.isFinite(code) ? String.fromCodePoint(code) : match;
|
|
83
|
+
}
|
|
84
|
+
if (body.startsWith("#")) {
|
|
85
|
+
const code = Number.parseInt(body.slice(1), 10);
|
|
86
|
+
return Number.isFinite(code) ? String.fromCodePoint(code) : match;
|
|
87
|
+
}
|
|
88
|
+
const named = NAMED_ENTITIES[body.toLowerCase()];
|
|
89
|
+
return named ?? match;
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Decodes the entities feed text actually contains.
|
|
96
|
+
*
|
|
97
|
+
* Feeds are written by publishing systems escaping HTML into XML, so the same
|
|
98
|
+
* title arrives as `&amp;` from one and `&` from another. Decoding runs
|
|
99
|
+
* twice for that reason — a second pass turns what the first pass revealed as
|
|
100
|
+
* `&` into `&` — and no further, since a third would start rewriting text
|
|
101
|
+
* that legitimately contains an ampersand followed by a word.
|
|
102
|
+
*/
|
|
103
|
+
function decodeEntities(text: string): string {
|
|
104
|
+
return decodeOnce(decodeOnce(text));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Unwraps CDATA, decodes entities, and collapses the whitespace markup left. */
|
|
108
|
+
function text(raw: string | undefined): string {
|
|
109
|
+
if (!raw) {
|
|
110
|
+
return "";
|
|
111
|
+
}
|
|
112
|
+
const cdata = raw.match(CDATA);
|
|
113
|
+
return decodeEntities(cdata ? cdata[1] : raw)
|
|
114
|
+
.replace(/\s+/g, " ")
|
|
115
|
+
.trim();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The same, for a value that arrived as HTML — a description, a summary.
|
|
120
|
+
*
|
|
121
|
+
* The markup may be escaped (`<p>`) or it may be markup (inside CDATA),
|
|
122
|
+
* and a feed reader sees both. So the passes go decode, strip, decode: the
|
|
123
|
+
* first reveals escaped tags as tags, the strip removes them whichever way they
|
|
124
|
+
* arrived, and the second decodes the entities the text itself contains. Doing
|
|
125
|
+
* it in the other order leaves a feed's `<span>` sitting in the summary as
|
|
126
|
+
* visible markup.
|
|
127
|
+
*/
|
|
128
|
+
function plainText(raw: string | undefined): string {
|
|
129
|
+
if (!raw) {
|
|
130
|
+
return "";
|
|
131
|
+
}
|
|
132
|
+
const cdata = raw.match(CDATA);
|
|
133
|
+
const body = decodeOnce(cdata ? cdata[1] : raw);
|
|
134
|
+
return decodeOnce(
|
|
135
|
+
body
|
|
136
|
+
.replace(COMMENT, "")
|
|
137
|
+
.replace(/<(script|style)\b[\s\S]*?<\/\1\s*>/gi, "")
|
|
138
|
+
.replace(/<[^>]*>/g, " "),
|
|
139
|
+
)
|
|
140
|
+
.replace(/\s+/g, " ")
|
|
141
|
+
.trim();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The content of the first of `names` that appears, with any namespace prefix
|
|
146
|
+
* ignored — `dc:date` answers to "date" because what distinguishes the formats
|
|
147
|
+
* is the prefix, and the prefix is exactly what does not matter here.
|
|
148
|
+
*/
|
|
149
|
+
function firstTag(block: string, names: string[]): string | undefined {
|
|
150
|
+
for (const name of names) {
|
|
151
|
+
const pattern = new RegExp(
|
|
152
|
+
`<(?:[A-Za-z0-9_.-]+:)?${name}(?:\\s[^>]*)?>([\\s\\S]*?)</(?:[A-Za-z0-9_.-]+:)?${name}\\s*>`,
|
|
153
|
+
"i",
|
|
154
|
+
);
|
|
155
|
+
const match = block.match(pattern);
|
|
156
|
+
if (match) {
|
|
157
|
+
return match[1];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const ATTRIBUTE = (name: string) =>
|
|
164
|
+
new RegExp(`\\b${name}\\s*=\\s*("([^"]*)"|'([^']*)')`, "i");
|
|
165
|
+
|
|
166
|
+
function attribute(tag: string, name: string): string | undefined {
|
|
167
|
+
const match = tag.match(ATTRIBUTE(name));
|
|
168
|
+
if (!match) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
return match[2] ?? match[3];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Where to read the item.
|
|
176
|
+
*
|
|
177
|
+
* RSS puts the address in the element's text; Atom puts it in the `href` of a
|
|
178
|
+
* `<link>` and may offer several. Of those, `alternate` is the human-readable
|
|
179
|
+
* one, which is the only kind worth handing a reader — `self` points back at
|
|
180
|
+
* the feed and `enclosure` at a media file.
|
|
181
|
+
*/
|
|
182
|
+
function itemLink(block: string, openTag: string): string {
|
|
183
|
+
const inline = firstTag(block, ["link"]);
|
|
184
|
+
if (inline && !/^\s*<|^\s*$/.test(inline)) {
|
|
185
|
+
return text(inline);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const links = block.match(/<(?:[A-Za-z0-9_.-]+:)?link\b[^>]*\/?>/gi) ?? [];
|
|
189
|
+
const usable = links.filter((tag) => {
|
|
190
|
+
const rel = (attribute(tag, "rel") ?? "alternate").toLowerCase();
|
|
191
|
+
return rel === "alternate";
|
|
192
|
+
});
|
|
193
|
+
const chosen = usable[0] ?? links[0];
|
|
194
|
+
const href = chosen ? attribute(chosen, "href") : undefined;
|
|
195
|
+
if (href) {
|
|
196
|
+
return decodeEntities(href).trim();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// RDF names the item by its address, on the item's own tag, which is the
|
|
200
|
+
// only place some 1.0 feeds put it at all.
|
|
201
|
+
const about = attribute(openTag, "about");
|
|
202
|
+
return about ? decodeEntities(about).trim() : "";
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* When the item was published.
|
|
207
|
+
*
|
|
208
|
+
* The publication date is preferred over the update date wherever a feed
|
|
209
|
+
* carries both: a list sorted by "last touched" reorders itself when a
|
|
210
|
+
* publisher fixes a typo in something from last week, which is not what a
|
|
211
|
+
* reader looking for what is new is asking to see.
|
|
212
|
+
*/
|
|
213
|
+
function itemDate(block: string): {
|
|
214
|
+
published: string;
|
|
215
|
+
publishedMs: number;
|
|
216
|
+
publishedLabel: string;
|
|
217
|
+
} {
|
|
218
|
+
const raw = text(
|
|
219
|
+
firstTag(block, ["pubDate", "published", "date", "issued", "updated"]),
|
|
220
|
+
);
|
|
221
|
+
const parsed = raw ? Date.parse(raw) : Number.NaN;
|
|
222
|
+
if (!Number.isFinite(parsed)) {
|
|
223
|
+
return { published: "", publishedMs: 0, publishedLabel: "" };
|
|
224
|
+
}
|
|
225
|
+
const iso = new Date(parsed).toISOString();
|
|
226
|
+
return {
|
|
227
|
+
published: iso,
|
|
228
|
+
publishedMs: parsed,
|
|
229
|
+
publishedLabel: `${iso.slice(0, 10)} ${iso.slice(11, 16)}`,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function itemAuthor(block: string): string {
|
|
234
|
+
// Atom wraps the author in a <name>; RSS puts an address in <author> and a
|
|
235
|
+
// display name in <dc:creator>.
|
|
236
|
+
const author = firstTag(block, ["author"]);
|
|
237
|
+
if (author && /<(?:[A-Za-z0-9_.-]+:)?name[\s>]/i.test(author)) {
|
|
238
|
+
return text(firstTag(author, ["name"]));
|
|
239
|
+
}
|
|
240
|
+
return text(author ?? firstTag(block, ["creator"]));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Reads a feed document into items.
|
|
245
|
+
*
|
|
246
|
+
* Nothing is rejected for being the wrong format: a document with no items
|
|
247
|
+
* parses to none, which is what a board shows as a feed that said nothing
|
|
248
|
+
* rather than as an error it cannot act on.
|
|
249
|
+
*/
|
|
250
|
+
export function parseFeed(xml: string): ParsedFeed {
|
|
251
|
+
const document = xml.replace(COMMENT, "");
|
|
252
|
+
|
|
253
|
+
const blocks: { open: string; body: string }[] = [];
|
|
254
|
+
for (const match of document.matchAll(ITEM_BLOCK)) {
|
|
255
|
+
blocks.push({ open: match[2], body: match[3] });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// The feed's own title is the first one outside any item, so the items are
|
|
259
|
+
// taken out of the way before looking for it.
|
|
260
|
+
const channel = document.replace(ITEM_BLOCK, "");
|
|
261
|
+
const title = text(firstTag(channel, ["title"]));
|
|
262
|
+
|
|
263
|
+
const items = blocks.map(({ open, body: block }): FeedItem => {
|
|
264
|
+
const link = itemLink(block, open);
|
|
265
|
+
const { published, publishedMs, publishedLabel } = itemDate(block);
|
|
266
|
+
return {
|
|
267
|
+
id: text(firstTag(block, ["guid", "id"])) || link,
|
|
268
|
+
title: text(firstTag(block, ["title"])) || "(untitled)",
|
|
269
|
+
link,
|
|
270
|
+
author: itemAuthor(block),
|
|
271
|
+
summary: plainText(
|
|
272
|
+
firstTag(block, ["description", "summary", "content", "encoded"]),
|
|
273
|
+
),
|
|
274
|
+
published,
|
|
275
|
+
publishedMs,
|
|
276
|
+
publishedLabel,
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
return { title, items };
|
|
281
|
+
}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Documentation
|
|
3
|
+
* Service ID: rss
|
|
4
|
+
* Service Name: RSS
|
|
5
|
+
* Runtime: hkp-node
|
|
6
|
+
* Modes: none
|
|
7
|
+
* Key Config: feeds, limit, timeoutMs, summaryChars, __hkpMount (a feed named
|
|
8
|
+
* by reference); addFeed/removeFeed/refresh as commands
|
|
9
|
+
* IO: in=any (ignored, a trigger) -> out=null immediately; the merged article
|
|
10
|
+
* list is pushed through the rest of the pipeline when the feeds answer
|
|
11
|
+
* Arrays: emits an array of articles
|
|
12
|
+
* Binary: not applicable
|
|
13
|
+
*
|
|
14
|
+
* Several feeds read as one list.
|
|
15
|
+
*
|
|
16
|
+
* A reader's unit is not the feed, it is the article: the question being asked
|
|
17
|
+
* is "what is new", and the answer spans every feed subscribed to. So this
|
|
18
|
+
* service fetches them together, reduces the three syndication formats to one
|
|
19
|
+
* article shape (`rss-parse`), merges the results and sorts them newest first.
|
|
20
|
+
* A board wanting one feed asks for one feed; nothing about the contract
|
|
21
|
+
* changes.
|
|
22
|
+
*
|
|
23
|
+
* It lives on hkp-node rather than the browser because a feed is served by
|
|
24
|
+
* whoever publishes it, and almost none of them send the CORS header a browser
|
|
25
|
+
* would need. Reading feeds is therefore something a board can only do from a
|
|
26
|
+
* runtime that is not a browser — not a preference.
|
|
27
|
+
*
|
|
28
|
+
* The feeds are **fetched concurrently and failures are kept apart**. One feed
|
|
29
|
+
* that is down, slow or no longer a feed produces an entry in `errors` and the
|
|
30
|
+
* others still arrive: a reader missing one source is still a reader, while one
|
|
31
|
+
* that shows nothing because a single site is having a bad morning is not.
|
|
32
|
+
*/
|
|
33
|
+
import {
|
|
34
|
+
HostedService,
|
|
35
|
+
JsonRecord,
|
|
36
|
+
ProcessContext,
|
|
37
|
+
RuntimeHost,
|
|
38
|
+
RuntimeNotification,
|
|
39
|
+
ServiceConfiguration,
|
|
40
|
+
ServiceRegistryEntry,
|
|
41
|
+
} from "../types";
|
|
42
|
+
import { FeedItem, parseFeed } from "./rss-parse";
|
|
43
|
+
import { MOUNT_FIELD, parseMountRef } from "../coordinator/mount";
|
|
44
|
+
import { failureReason } from "../egress";
|
|
45
|
+
|
|
46
|
+
export const rssDescriptor: ServiceRegistryEntry = {
|
|
47
|
+
serviceId: "rss",
|
|
48
|
+
serviceName: "RSS",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** A feed as a board subscribes to it: where it is, and what to call it. */
|
|
52
|
+
type Feed = {
|
|
53
|
+
url: string;
|
|
54
|
+
/** What the list shows as the source. Empty until the feed says its own. */
|
|
55
|
+
name: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** An article, as it travels: a feed item that remembers where it came from. */
|
|
59
|
+
export type Article = FeedItem & {
|
|
60
|
+
feed: string;
|
|
61
|
+
feedUrl: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const DEFAULT_LIMIT = 60;
|
|
65
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
66
|
+
const DEFAULT_SUMMARY_CHARS = 240;
|
|
67
|
+
|
|
68
|
+
/** A feed entry as it may be written: a bare URL, or a URL with a name. */
|
|
69
|
+
function readFeed(value: unknown): Feed | null {
|
|
70
|
+
if (typeof value === "string") {
|
|
71
|
+
return value.trim() ? { url: value.trim(), name: "" } : null;
|
|
72
|
+
}
|
|
73
|
+
if (value && typeof value === "object") {
|
|
74
|
+
const record = value as JsonRecord;
|
|
75
|
+
const url = typeof record.url === "string" ? record.url.trim() : "";
|
|
76
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
77
|
+
return url ? { url, name } : null;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function readFeedList(value: unknown): Feed[] | null {
|
|
83
|
+
if (!Array.isArray(value)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const feeds: Feed[] = [];
|
|
87
|
+
for (const entry of value) {
|
|
88
|
+
const feed = readFeed(entry);
|
|
89
|
+
// A feed already subscribed to is not added twice: the list is what a
|
|
90
|
+
// person reads, and the same source listed twice doubles every article.
|
|
91
|
+
if (feed && !feeds.some((existing) => existing.url === feed.url)) {
|
|
92
|
+
feeds.push(feed);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return feeds;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** The host, as the name to show for a feed that did not offer one. */
|
|
99
|
+
function hostOf(url: string): string {
|
|
100
|
+
try {
|
|
101
|
+
return new URL(url).hostname.replace(/^www\./, "");
|
|
102
|
+
} catch {
|
|
103
|
+
return url;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export class RssService implements HostedService {
|
|
108
|
+
readonly serviceId = rssDescriptor.serviceId;
|
|
109
|
+
readonly serviceName = rssDescriptor.serviceName;
|
|
110
|
+
readonly uuid: string;
|
|
111
|
+
|
|
112
|
+
private host: RuntimeHost | null = null;
|
|
113
|
+
private feeds: Feed[] = [];
|
|
114
|
+
private limit = DEFAULT_LIMIT;
|
|
115
|
+
private timeoutMs = DEFAULT_TIMEOUT_MS;
|
|
116
|
+
private summaryChars = DEFAULT_SUMMARY_CHARS;
|
|
117
|
+
private fetching = false;
|
|
118
|
+
/** The latest round begun; an earlier one finishing later is dropped. */
|
|
119
|
+
private round = 0;
|
|
120
|
+
/**
|
|
121
|
+
* The address a feed named by reference resolves to.
|
|
122
|
+
*
|
|
123
|
+
* A feed on this board rather than out on the web — one unit publishing what
|
|
124
|
+
* another reads — has no address until the board loads, so it is named the
|
|
125
|
+
* way every other endpoint is and resolved by the coordinator. One address,
|
|
126
|
+
* so one feed of a list may be a reference; the rest are URLs, which is what
|
|
127
|
+
* they are anyway.
|
|
128
|
+
*/
|
|
129
|
+
private mount = "";
|
|
130
|
+
|
|
131
|
+
constructor(config: ServiceConfiguration) {
|
|
132
|
+
this.uuid = config.uuid;
|
|
133
|
+
if (config.state) {
|
|
134
|
+
this.configure(config.state);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
setHost(host: RuntimeHost): void {
|
|
139
|
+
this.host = host;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The address a feed's url stands for: itself when it is a URL, the resolved
|
|
144
|
+
* mount when it is a reference, and nothing while a reference is unresolved.
|
|
145
|
+
*/
|
|
146
|
+
private addressOf(url: string): string | null {
|
|
147
|
+
if (!parseMountRef(url)) {
|
|
148
|
+
return url;
|
|
149
|
+
}
|
|
150
|
+
return this.mount && !parseMountRef(this.mount) ? this.mount : null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* What the service is configured as — and not what it last read.
|
|
155
|
+
*
|
|
156
|
+
* This is the state a board is saved with, so the articles stay out of it:
|
|
157
|
+
* they are a fetch's result rather than a setting, they are large, and they
|
|
158
|
+
* are stale the moment they are written. The list reaches a panel or a facade
|
|
159
|
+
* as a notification, and a board that has just loaded gets one as soon as
|
|
160
|
+
* something triggers it.
|
|
161
|
+
*/
|
|
162
|
+
getState(): JsonRecord {
|
|
163
|
+
return {
|
|
164
|
+
feeds: this.feeds.map((feed) => ({ ...feed })),
|
|
165
|
+
limit: this.limit,
|
|
166
|
+
timeoutMs: this.timeoutMs,
|
|
167
|
+
summaryChars: this.summaryChars,
|
|
168
|
+
fetching: this.fetching,
|
|
169
|
+
[MOUNT_FIELD]: this.mount,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
configure(config: JsonRecord): JsonRecord {
|
|
174
|
+
const feeds = readFeedList(config.feeds);
|
|
175
|
+
if (feeds) {
|
|
176
|
+
this.feeds = feeds;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Adding and removing are commands rather than settings: a facade has a
|
|
180
|
+
// field and a button, not an editor for the whole list, and rewriting
|
|
181
|
+
// `feeds` from a text input would mean the widget had to know the list it
|
|
182
|
+
// was changing.
|
|
183
|
+
const added = readFeed(config.addFeed);
|
|
184
|
+
if (added && !this.feeds.some((feed) => feed.url === added.url)) {
|
|
185
|
+
this.feeds = [...this.feeds, added];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const removed = readFeed(config.removeFeed);
|
|
189
|
+
if (removed) {
|
|
190
|
+
this.feeds = this.feeds.filter((feed) => feed.url !== removed.url);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// The list is announced whenever it changes, not only returned to whoever
|
|
194
|
+
// changed it: a panel and a facade both render it, and only one of them
|
|
195
|
+
// made the call.
|
|
196
|
+
if (feeds || added || removed) {
|
|
197
|
+
this._notify({ feeds: this.feeds.map((feed) => ({ ...feed })) });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (typeof config.limit === "number" && config.limit > 0) {
|
|
201
|
+
this.limit = Math.floor(config.limit);
|
|
202
|
+
}
|
|
203
|
+
if (typeof config.timeoutMs === "number" && config.timeoutMs > 0) {
|
|
204
|
+
this.timeoutMs = config.timeoutMs;
|
|
205
|
+
}
|
|
206
|
+
if (typeof config.summaryChars === "number" && config.summaryChars >= 0) {
|
|
207
|
+
this.summaryChars = Math.floor(config.summaryChars);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Fetching now is a command here as well as the service's process(),
|
|
211
|
+
// because a panel is the one caller that cannot use process(): a service on
|
|
212
|
+
// a remote runtime has no local instance for its UI to call, so configure
|
|
213
|
+
// is the only verb that reaches it. Same work either way — Injector's
|
|
214
|
+
// `inject` is the same arrangement for the same reason.
|
|
215
|
+
if (typeof config[MOUNT_FIELD] === "string") {
|
|
216
|
+
this.mount = config[MOUNT_FIELD] as string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (config.refresh) {
|
|
220
|
+
this.start((payload) => this._notify(payload as JsonRecord));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return this.getState();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Starts the round of fetches and stops the synchronous push.
|
|
228
|
+
*
|
|
229
|
+
* Like every service whose answer is a response, the articles do not exist
|
|
230
|
+
* when this returns — the rest of the pipeline is called with them once the
|
|
231
|
+
* feeds have answered.
|
|
232
|
+
*/
|
|
233
|
+
process(
|
|
234
|
+
_input: unknown,
|
|
235
|
+
notify: (payload: unknown, instanceId?: string) => void,
|
|
236
|
+
): unknown {
|
|
237
|
+
this.start(notify);
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
destroy(): void {
|
|
242
|
+
this.host = null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ── Private ───────────────────────────────────────────────────────────────
|
|
246
|
+
|
|
247
|
+
private _notify(payload: JsonRecord, instanceId: string = this.uuid): void {
|
|
248
|
+
this.host?.notify(payload, instanceId);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Begins a round, or says why there is nothing to fetch. */
|
|
252
|
+
private start(notify: (payload: unknown, instanceId?: string) => void): void {
|
|
253
|
+
if (this.feeds.length === 0) {
|
|
254
|
+
notify({ fetching: false, error: "No feeds configured" });
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
void this.refresh(notify, this.host?.currentContext() ?? undefined);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private async refresh(
|
|
261
|
+
notify: (payload: unknown, instanceId?: string) => void,
|
|
262
|
+
context?: ProcessContext,
|
|
263
|
+
): Promise<void> {
|
|
264
|
+
const feeds = this.feeds;
|
|
265
|
+
const round = ++this.round;
|
|
266
|
+
this.fetching = true;
|
|
267
|
+
notify({ fetching: true, error: "", sources: feeds.length });
|
|
268
|
+
|
|
269
|
+
const results = await Promise.all(
|
|
270
|
+
feeds.map((feed) => this.readFeed(feed)),
|
|
271
|
+
);
|
|
272
|
+
// A newer round began while this one waited — after a feed was added or
|
|
273
|
+
// removed, say — and its list is the one that holds. Reporting this one
|
|
274
|
+
// last would bring a removed feed's articles back.
|
|
275
|
+
if (round !== this.round) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const articles: Article[] = [];
|
|
280
|
+
const errors: { url: string; error: string }[] = [];
|
|
281
|
+
for (const result of results) {
|
|
282
|
+
if (result.error) {
|
|
283
|
+
errors.push({ url: result.feed.url, error: result.error });
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
articles.push(...result.articles);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Newest first, across every feed — which is the whole point of reading
|
|
290
|
+
// them together rather than one after another.
|
|
291
|
+
articles.sort((a, b) => b.publishedMs - a.publishedMs);
|
|
292
|
+
const items = articles.slice(0, this.limit);
|
|
293
|
+
|
|
294
|
+
this.fetching = false;
|
|
295
|
+
notify({
|
|
296
|
+
fetching: false,
|
|
297
|
+
fetchedAt: new Date().toISOString(),
|
|
298
|
+
sources: feeds.length,
|
|
299
|
+
count: items.length,
|
|
300
|
+
// Said on every round, so a panel showing a failure shows this round's
|
|
301
|
+
// and not one still standing from an earlier one.
|
|
302
|
+
error: errors.length ? `${errors.length} of ${feeds.length} failed` : "",
|
|
303
|
+
errors,
|
|
304
|
+
items,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
await this.push(items, notify, context);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private async readFeed(
|
|
311
|
+
feed: Feed,
|
|
312
|
+
): Promise<{ feed: Feed; articles: Article[]; error?: string }> {
|
|
313
|
+
const address = this.addressOf(feed.url);
|
|
314
|
+
if (!address) {
|
|
315
|
+
// A reference nobody has published yet: the unit that serves this feed is
|
|
316
|
+
// still coming up. Not an error to act on, and not a URL to dial — the
|
|
317
|
+
// next round tries again, by which time the coordinator has usually
|
|
318
|
+
// handed the address over.
|
|
319
|
+
return { feed, articles: [], error: `Waiting for ${feed.url}` };
|
|
320
|
+
}
|
|
321
|
+
const controller = new AbortController();
|
|
322
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
323
|
+
try {
|
|
324
|
+
const response = await fetch(address, {
|
|
325
|
+
headers: {
|
|
326
|
+
accept:
|
|
327
|
+
"application/rss+xml, application/atom+xml, application/xml, text/xml;q=0.9, */*;q=0.8",
|
|
328
|
+
// Some publishers answer a request without one with a redirect to a
|
|
329
|
+
// consent page, which is not a feed.
|
|
330
|
+
"user-agent": "Readymade/1.0 (+https://readymadeit.com)",
|
|
331
|
+
},
|
|
332
|
+
signal: controller.signal,
|
|
333
|
+
});
|
|
334
|
+
if (!response.ok) {
|
|
335
|
+
return {
|
|
336
|
+
feed,
|
|
337
|
+
articles: [],
|
|
338
|
+
error: `HTTP ${response.status}`,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
const parsed = parseFeed(await response.text());
|
|
342
|
+
const name = feed.name || parsed.title || hostOf(feed.url);
|
|
343
|
+
return {
|
|
344
|
+
feed,
|
|
345
|
+
articles: parsed.items.map((item) => ({
|
|
346
|
+
...item,
|
|
347
|
+
summary: this.summaryChars
|
|
348
|
+
? item.summary.slice(0, this.summaryChars)
|
|
349
|
+
: "",
|
|
350
|
+
feed: name,
|
|
351
|
+
feedUrl: feed.url,
|
|
352
|
+
})),
|
|
353
|
+
};
|
|
354
|
+
} catch (err) {
|
|
355
|
+
const message = failureReason(err);
|
|
356
|
+
return {
|
|
357
|
+
feed,
|
|
358
|
+
articles: [],
|
|
359
|
+
// An abort is this service's own timeout, and says so — "This operation
|
|
360
|
+
// was aborted" tells a reader nothing about which feed was slow.
|
|
361
|
+
error: controller.signal.aborted
|
|
362
|
+
? `Timed out after ${this.timeoutMs}ms`
|
|
363
|
+
: message,
|
|
364
|
+
};
|
|
365
|
+
} finally {
|
|
366
|
+
clearTimeout(timer);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
private async push(
|
|
371
|
+
items: Article[],
|
|
372
|
+
notify: (payload: unknown, instanceId?: string) => void,
|
|
373
|
+
context?: ProcessContext,
|
|
374
|
+
): Promise<void> {
|
|
375
|
+
if (!this.host) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const output = await this.host.processFrom(
|
|
379
|
+
this.uuid,
|
|
380
|
+
items,
|
|
381
|
+
// No-op: the runtime already fans these out to its notification
|
|
382
|
+
// targets. Re-notifying through `notify` would deliver every one twice.
|
|
383
|
+
(_n: RuntimeNotification) => {},
|
|
384
|
+
context,
|
|
385
|
+
);
|
|
386
|
+
// A downstream service returning null means stop — honour it rather than
|
|
387
|
+
// driving the next runtime with a dead result.
|
|
388
|
+
if (output !== null && output !== undefined) {
|
|
389
|
+
this.host.emitResult(output);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|