@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,426 @@
|
|
|
1
|
+
import { CloudBoardConfig, isRemoteRuntime } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What a board's facade lets a member of the board do and see.
|
|
5
|
+
*
|
|
6
|
+
* A member is not handed the board. They are handed its facade, and the facade
|
|
7
|
+
* is therefore the whole of their reach: the services it asks to process are
|
|
8
|
+
* the ones a member may ask, and the services it reads from are the ones a
|
|
9
|
+
* member hears. Everything else on the board — its other services, their
|
|
10
|
+
* configuration, whatever credentials that configuration names — stays with
|
|
11
|
+
* the owner.
|
|
12
|
+
*
|
|
13
|
+
* Read here from the facade document itself rather than from a list a board
|
|
14
|
+
* author keeps beside it, so that what a member can do is exactly what the
|
|
15
|
+
* facade they are shown does.
|
|
16
|
+
*
|
|
17
|
+
* The vocabulary is the frontend's (`hkp-frontend/src/facade/types.ts`). Found
|
|
18
|
+
* by shape, the way `widgetServices.ts` finds references there, so a widget
|
|
19
|
+
* added later is covered without this being edited.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export type FacadeAccess = {
|
|
23
|
+
/**
|
|
24
|
+
* The facade as a member is shown it: the board's, without what it keeps for
|
|
25
|
+
* its owner. Everything below is read from this, so an item kept for the
|
|
26
|
+
* owner grants a member nothing, and is not sent to them either.
|
|
27
|
+
*/
|
|
28
|
+
facade: unknown;
|
|
29
|
+
/**
|
|
30
|
+
* Services a `process` action names. Naming one makes it callable by a
|
|
31
|
+
* member with *any* payload — the entry point is the capability, not what
|
|
32
|
+
* the widget would have sent — so whatever matters is checked behind it.
|
|
33
|
+
*/
|
|
34
|
+
processTargets: Set<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Services a widget or a notice reads, with the paths read from each. An
|
|
37
|
+
* empty string stands for a source with no path: the whole notification.
|
|
38
|
+
*/
|
|
39
|
+
sources: Map<string, Set<string>>;
|
|
40
|
+
/** Every service the facade names, for whatever reason. */
|
|
41
|
+
named: Set<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Source paths that name an object's machinery rather than its data
|
|
44
|
+
* (`isPlainPath`). They grant nothing; a board whose facade has one is not
|
|
45
|
+
* taken in the first place (`refusedFacadePaths`).
|
|
46
|
+
*/
|
|
47
|
+
refused: Set<string>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* What an action carries to its service. A uuid in there is a value being
|
|
52
|
+
* sent, not an address this facade dials.
|
|
53
|
+
*/
|
|
54
|
+
const PAYLOADS = new Set(["configure", "payload"]);
|
|
55
|
+
|
|
56
|
+
function isReference(name: string): boolean {
|
|
57
|
+
return name === "serviceUuid" || name.endsWith("ServiceUuid");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
61
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Segments that lead from a value into what every object inherits. A path
|
|
66
|
+
* through one reaches `Object.prototype`, so writing along it changes every
|
|
67
|
+
* object in the process, for every tenant.
|
|
68
|
+
*/
|
|
69
|
+
const MACHINERY = new Set(["__proto__", "constructor", "prototype"]);
|
|
70
|
+
|
|
71
|
+
/** Whether a dotted path names only data: no segment is `MACHINERY`. */
|
|
72
|
+
export function isPlainPath(path: string): boolean {
|
|
73
|
+
return path.split(".").every((key) => !MACHINERY.has(key));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** An address a template has yet to fill in names nothing a member may call. */
|
|
77
|
+
function isLiteral(address: string): boolean {
|
|
78
|
+
return !!address && !address.includes("{{");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Where a facade says what it reads: a widget's or a notice's source, and a
|
|
82
|
+
* fold's live count. */
|
|
83
|
+
const SOURCES = new Set(["source", "summary"]);
|
|
84
|
+
|
|
85
|
+
function walk(value: unknown, access: FacadeAccess, under = ""): void {
|
|
86
|
+
if (Array.isArray(value)) {
|
|
87
|
+
for (const entry of value) {
|
|
88
|
+
walk(entry, access, under);
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!isRecord(value)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const uuid = value.serviceUuid;
|
|
97
|
+
if (typeof uuid === "string" && isLiteral(uuid)) {
|
|
98
|
+
if (value.type === "process") {
|
|
99
|
+
access.processTargets.add(uuid);
|
|
100
|
+
} else if (SOURCES.has(under)) {
|
|
101
|
+
const path = typeof value.path === "string" ? value.path : "";
|
|
102
|
+
// Refused rather than kept: it would read nothing a member may see, and
|
|
103
|
+
// projecting it would write through to every object in the process.
|
|
104
|
+
if (isPlainPath(path)) {
|
|
105
|
+
const paths = access.sources.get(uuid) ?? new Set<string>();
|
|
106
|
+
paths.add(path);
|
|
107
|
+
access.sources.set(uuid, paths);
|
|
108
|
+
} else {
|
|
109
|
+
access.refused.add(path);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
115
|
+
if (PAYLOADS.has(name)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (typeof entry === "string") {
|
|
119
|
+
if (isReference(name) && isLiteral(entry)) {
|
|
120
|
+
access.named.add(entry);
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
walk(entry, access, name);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function emptyAccess(facade: unknown): FacadeAccess {
|
|
129
|
+
return {
|
|
130
|
+
facade,
|
|
131
|
+
processTargets: new Set(),
|
|
132
|
+
sources: new Map(),
|
|
133
|
+
named: new Set(),
|
|
134
|
+
refused: new Set(),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function readFacadeAccess(facade: unknown): FacadeAccess {
|
|
139
|
+
const shown = facadeForMembers(facade);
|
|
140
|
+
const access = emptyAccess(shown);
|
|
141
|
+
walk(shown, access);
|
|
142
|
+
return access;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The source paths a facade may not have, anywhere in it — kept for the owner
|
|
147
|
+
* or not, since what the owner keeps today a member may be shown tomorrow.
|
|
148
|
+
* Asked where a board is taken in, so that one carrying them is refused there
|
|
149
|
+
* rather than run with those sources silently reading nothing.
|
|
150
|
+
*/
|
|
151
|
+
export function refusedFacadePaths(facade: unknown): string[] {
|
|
152
|
+
const access = emptyAccess(facade);
|
|
153
|
+
walk(facade, access);
|
|
154
|
+
return [...access.refused];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Whether an entry is one a facade keeps for the board's owner. */
|
|
158
|
+
function isOwners(value: unknown): boolean {
|
|
159
|
+
return isRecord(value) && value.visibleTo === "owner";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** A value with every entry kept for the owner left out, at any depth. */
|
|
163
|
+
function withoutOwners(value: unknown): unknown {
|
|
164
|
+
if (Array.isArray(value)) {
|
|
165
|
+
return value.filter((entry) => !isOwners(entry)).map(withoutOwners);
|
|
166
|
+
}
|
|
167
|
+
if (!isRecord(value)) {
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
const out: Record<string, unknown> = {};
|
|
171
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
172
|
+
if (!isOwners(entry)) {
|
|
173
|
+
out[name] = withoutOwners(entry);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The facade without the panels only an owner's tab names. A panel no tab
|
|
181
|
+
* names is on screen whatever tab is chosen, so leaving out the tab alone
|
|
182
|
+
* would put its panels in front of a member rather than keep them from one.
|
|
183
|
+
*/
|
|
184
|
+
function withoutOwnersPanels(facade: unknown): unknown {
|
|
185
|
+
if (!isRecord(facade) || !Array.isArray(facade.tabs) || !Array.isArray(facade.panels)) {
|
|
186
|
+
return facade;
|
|
187
|
+
}
|
|
188
|
+
const named = (owners: boolean) =>
|
|
189
|
+
new Set(
|
|
190
|
+
(facade.tabs as unknown[])
|
|
191
|
+
.filter((tab) => isRecord(tab) && isOwners(tab) === owners)
|
|
192
|
+
.flatMap((tab) => (isRecord(tab) && Array.isArray(tab.panels) ? tab.panels : [])),
|
|
193
|
+
);
|
|
194
|
+
const everybodys = named(false);
|
|
195
|
+
const owners = named(true);
|
|
196
|
+
return {
|
|
197
|
+
...facade,
|
|
198
|
+
panels: facade.panels.filter(
|
|
199
|
+
(panel) =>
|
|
200
|
+
!isRecord(panel) || !owners.has(panel.id) || everybodys.has(panel.id),
|
|
201
|
+
),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The facade without what `visibleTo: "owner"` keeps for the board's owner —
|
|
207
|
+
* a widget, a container, a panel, a tab, a notice.
|
|
208
|
+
*
|
|
209
|
+
* Left out of what a member is sent rather than hidden by the page they are
|
|
210
|
+
* shown it on: a control a member cannot see but is sent still names its
|
|
211
|
+
* service and what it would send there, and a value only the owner reads
|
|
212
|
+
* would still be projected to them. A tab left with none of its panels goes
|
|
213
|
+
* with them, a panel only an owner's tab names goes with that tab, and so does
|
|
214
|
+
* a default naming a tab that went.
|
|
215
|
+
*/
|
|
216
|
+
export function facadeForMembers(facade: unknown): unknown {
|
|
217
|
+
const shown = withoutOwners(withoutOwnersPanels(facade));
|
|
218
|
+
if (!isRecord(shown) || !Array.isArray(shown.tabs)) {
|
|
219
|
+
return shown;
|
|
220
|
+
}
|
|
221
|
+
const panels = new Set(
|
|
222
|
+
(Array.isArray(shown.panels) ? shown.panels : [])
|
|
223
|
+
.map((panel) => (isRecord(panel) ? panel.id : undefined))
|
|
224
|
+
.filter((id): id is string => typeof id === "string"),
|
|
225
|
+
);
|
|
226
|
+
const tabs = shown.tabs.flatMap((tab) => {
|
|
227
|
+
if (!isRecord(tab) || !Array.isArray(tab.panels)) {
|
|
228
|
+
return [tab];
|
|
229
|
+
}
|
|
230
|
+
const kept = tab.panels.filter((id) => panels.has(id as string));
|
|
231
|
+
// A tab that never named a panel is the board's to have; one that lost
|
|
232
|
+
// all of them to the owner is the owner's.
|
|
233
|
+
return kept.length === 0 && tab.panels.length > 0 ? [] : [{ ...tab, panels: kept }];
|
|
234
|
+
});
|
|
235
|
+
const result: Record<string, unknown> = { ...shown, tabs };
|
|
236
|
+
if (!tabs.some((tab) => isRecord(tab) && tab.id === shown.defaultTab)) {
|
|
237
|
+
delete result.defaultTab;
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** The first segment of an address: the service a board lists. */
|
|
243
|
+
function rootOf(address: string): string {
|
|
244
|
+
const dot = address.indexOf(".");
|
|
245
|
+
return dot < 0 ? address : address.slice(0, dot);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The value at a dotted path, through own properties only: what a value
|
|
250
|
+
* inherits is not part of it, and is not a member's to be sent.
|
|
251
|
+
*/
|
|
252
|
+
function readPath(value: unknown, path: string): unknown {
|
|
253
|
+
let current = value;
|
|
254
|
+
for (const key of path.split(".")) {
|
|
255
|
+
if (!isRecord(current) && !Array.isArray(current)) {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
if (MACHINERY.has(key) || !Object.hasOwn(current, key)) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
current = (current as Record<string, unknown>)[key];
|
|
262
|
+
}
|
|
263
|
+
return current;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Sets a dotted path in an object `pick` built, creating what leads to it.
|
|
268
|
+
* Every object it creates has no prototype, and a path through `MACHINERY` is
|
|
269
|
+
* written nowhere — the checks here stand even where a path was let through
|
|
270
|
+
* on its way in.
|
|
271
|
+
*/
|
|
272
|
+
function writePath(
|
|
273
|
+
target: Record<string, unknown>,
|
|
274
|
+
path: string,
|
|
275
|
+
value: unknown,
|
|
276
|
+
): void {
|
|
277
|
+
if (!isPlainPath(path)) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const keys = path.split(".");
|
|
281
|
+
let current = target;
|
|
282
|
+
for (const key of keys.slice(0, -1)) {
|
|
283
|
+
const next = Object.hasOwn(current, key) ? current[key] : undefined;
|
|
284
|
+
if (!isRecord(next)) {
|
|
285
|
+
current[key] = Object.create(null);
|
|
286
|
+
}
|
|
287
|
+
current = current[key] as Record<string, unknown>;
|
|
288
|
+
}
|
|
289
|
+
current[keys[keys.length - 1]] = value;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Of a service's state, only what the facade's sources read from it.
|
|
294
|
+
*
|
|
295
|
+
* A source without a path reads whatever the service next says, which is a
|
|
296
|
+
* notification and not its state; nothing of the state is given for it. So a
|
|
297
|
+
* service the facade only acts on, or only listens to, has an empty state
|
|
298
|
+
* here — its statement, its address, its credentials' names are not a
|
|
299
|
+
* member's to see.
|
|
300
|
+
*/
|
|
301
|
+
export function projectState(
|
|
302
|
+
access: FacadeAccess,
|
|
303
|
+
serviceUuid: string,
|
|
304
|
+
state: unknown,
|
|
305
|
+
): Record<string, unknown> {
|
|
306
|
+
return pick(state, access.sources.get(serviceUuid) ?? []);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Of what a service said, only what the facade's sources read from it.
|
|
311
|
+
*
|
|
312
|
+
* A source without a path reads the notification whole, so the whole of it is
|
|
313
|
+
* given. Otherwise it is cut down to the paths read: each of them resolves in
|
|
314
|
+
* what is returned to exactly what it resolved to in what was said, and
|
|
315
|
+
* nothing beside them is there. A notification holding none of them is not a
|
|
316
|
+
* notification for this facade: forwarding an empty object would reveal that
|
|
317
|
+
* the service spoke but would not clear a widget, since none of its source
|
|
318
|
+
* paths changed. A service clears a value explicitly (`rows: []`, for example).
|
|
319
|
+
*/
|
|
320
|
+
export function projectNotification(
|
|
321
|
+
access: FacadeAccess,
|
|
322
|
+
serviceUuid: string,
|
|
323
|
+
payload: unknown,
|
|
324
|
+
): unknown | undefined {
|
|
325
|
+
const paths = access.sources.get(serviceUuid) ?? new Set<string>();
|
|
326
|
+
if (paths.has("")) {
|
|
327
|
+
return payload;
|
|
328
|
+
}
|
|
329
|
+
const projected = pick(payload, paths);
|
|
330
|
+
return Object.keys(projected).length > 0 ? projected : undefined;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** The values at `paths` in `value`, at the same paths in an object of their
|
|
334
|
+
* own. A pathless entry names no part of it and picks nothing.
|
|
335
|
+
*
|
|
336
|
+
* A path inside one that is picked whole adds nothing and is skipped: given
|
|
337
|
+
* `rows` and `rows.0.day`, the rows are already there, and writing the second
|
|
338
|
+
* would build `rows` again as an object holding `0` — a calendar reading the
|
|
339
|
+
* list would then be given none. */
|
|
340
|
+
function pick(value: unknown, paths: Iterable<string>): Record<string, unknown> {
|
|
341
|
+
const picked: Record<string, unknown> = Object.create(null);
|
|
342
|
+
const all = [...paths].filter(Boolean);
|
|
343
|
+
const covered = (path: string) =>
|
|
344
|
+
all.some((other) => other !== path && path.startsWith(`${other}.`));
|
|
345
|
+
for (const path of all) {
|
|
346
|
+
if (covered(path)) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const found = readPath(value, path);
|
|
350
|
+
if (found !== undefined) {
|
|
351
|
+
writePath(picked, path, found);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return picked;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* The runtime a facade's service is on: the first of the board's remote
|
|
359
|
+
* runtimes listing it, which is how a facade's bare uuid is resolved
|
|
360
|
+
* everywhere. A browser runtime's services are not a member's to reach — that
|
|
361
|
+
* runtime runs in its owner's browser.
|
|
362
|
+
*/
|
|
363
|
+
export function runtimeHolding(
|
|
364
|
+
config: CloudBoardConfig,
|
|
365
|
+
serviceUuid: string,
|
|
366
|
+
): string | undefined {
|
|
367
|
+
const root = rootOf(serviceUuid);
|
|
368
|
+
for (const runtime of config.runtimes) {
|
|
369
|
+
if (!isRemoteRuntime(runtime)) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if ((config.services[runtime.id] ?? []).some((svc) => svc.uuid === root)) {
|
|
373
|
+
return runtime.id;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* The board as a member is sent it: the facade, and of the board only the
|
|
381
|
+
* services the facade names — what each one is, never how it is configured.
|
|
382
|
+
*
|
|
383
|
+
* Shaped as a board, so a client renders the facade from it the way it would
|
|
384
|
+
* from the real one. There is no board underneath: the runtimes carry no
|
|
385
|
+
* address and no settings, and a service nobody named is not there at all.
|
|
386
|
+
*/
|
|
387
|
+
export function projectConfig(
|
|
388
|
+
config: CloudBoardConfig,
|
|
389
|
+
access: FacadeAccess,
|
|
390
|
+
stateOf: (runtimeId: string, serviceUuid: string) => unknown,
|
|
391
|
+
): CloudBoardConfig {
|
|
392
|
+
const services: CloudBoardConfig["services"] = {};
|
|
393
|
+
for (const address of access.named) {
|
|
394
|
+
const runtimeId = runtimeHolding(config, address);
|
|
395
|
+
if (!runtimeId) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
const uuid = rootOf(address);
|
|
399
|
+
const listed = services[runtimeId] ?? [];
|
|
400
|
+
if (listed.some((svc) => svc.uuid === uuid)) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const svc = (config.services[runtimeId] ?? []).find(
|
|
404
|
+
(entry) => entry.uuid === uuid,
|
|
405
|
+
);
|
|
406
|
+
if (!svc) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
listed.push({
|
|
410
|
+
uuid,
|
|
411
|
+
serviceId: svc.serviceId,
|
|
412
|
+
serviceName: svc.serviceName ?? svc.name ?? svc.serviceId,
|
|
413
|
+
state: projectState(access, uuid, stateOf(runtimeId, uuid)),
|
|
414
|
+
});
|
|
415
|
+
services[runtimeId] = listed;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
boardName: config.boardName,
|
|
420
|
+
runtimes: config.runtimes
|
|
421
|
+
.filter((runtime) => runtime.id in services)
|
|
422
|
+
.map(({ id, name, type }) => ({ id, name, type })),
|
|
423
|
+
services,
|
|
424
|
+
facade: access.facade,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { promises as fs } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
import { BoardStore, PersistedBoard } from "./boardStore";
|
|
7
|
+
import { CloudBoardConfig } from "./types";
|
|
8
|
+
import { readMembers } from "./members";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Boards kept as one JSON file each, under a directory this coordinator owns.
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* <root>/<sha256(userId)>/<sha256(boardName)>.json
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* The names in those paths are **derived, never used directly**. Both come from
|
|
18
|
+
* the wire: a board name is whatever the client sent, and an Auth0 `sub`
|
|
19
|
+
* contains characters (`|`) that have no business in a path. Hashing settles
|
|
20
|
+
* two problems at once — a board called `../../etc/passwd` cannot escape the
|
|
21
|
+
* root, and `Foo` and `foo`, which are two boards to the coordinator, cannot
|
|
22
|
+
* become one file on a case-insensitive filesystem. The real names are inside.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/** Bumped only when the shape on disk changes; an unknown one is left alone. */
|
|
26
|
+
const FORMAT_VERSION = 1;
|
|
27
|
+
|
|
28
|
+
type BoardFile = PersistedBoard & { version: number };
|
|
29
|
+
|
|
30
|
+
function fileNameFor(value: string): string {
|
|
31
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isBoardFile(value: unknown): value is BoardFile {
|
|
35
|
+
if (!value || typeof value !== "object") {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const board = value as Record<string, unknown>;
|
|
39
|
+
return (
|
|
40
|
+
typeof board.userId === "string" &&
|
|
41
|
+
typeof board.boardName === "string" &&
|
|
42
|
+
typeof board.createdAt === "string" &&
|
|
43
|
+
!!board.config &&
|
|
44
|
+
typeof board.config === "object"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createFileBoardStore(root: string): BoardStore {
|
|
49
|
+
const userDir = (userId: string) => path.join(root, fileNameFor(userId));
|
|
50
|
+
const boardPath = (userId: string, boardName: string) =>
|
|
51
|
+
path.join(userDir(userId), `${fileNameFor(boardName)}.json`);
|
|
52
|
+
|
|
53
|
+
async function readBoard(file: string): Promise<PersistedBoard | null> {
|
|
54
|
+
let parsed: unknown;
|
|
55
|
+
try {
|
|
56
|
+
parsed = JSON.parse(await fs.readFile(file, "utf8"));
|
|
57
|
+
} catch (err) {
|
|
58
|
+
// One unreadable board must not stop a coordinator from starting: the
|
|
59
|
+
// others are still good, and the operator can see which one is not.
|
|
60
|
+
console.error(
|
|
61
|
+
`[coordinator] Ignoring unreadable board file ${file}:`,
|
|
62
|
+
err instanceof Error ? err.message : err,
|
|
63
|
+
);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
if (!isBoardFile(parsed)) {
|
|
67
|
+
console.error(`[coordinator] Ignoring malformed board file ${file}`);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
if (parsed.version !== FORMAT_VERSION) {
|
|
71
|
+
// Written by a newer coordinator. Guessing at it could hand a board back
|
|
72
|
+
// in a shape it never had; leaving it be keeps it intact for that one.
|
|
73
|
+
console.error(
|
|
74
|
+
`[coordinator] Ignoring board file ${file}: format version ${parsed.version}`,
|
|
75
|
+
);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const { userId, boardName, createdAt, config, stopped, tickets, members } =
|
|
79
|
+
parsed;
|
|
80
|
+
return {
|
|
81
|
+
userId,
|
|
82
|
+
boardName,
|
|
83
|
+
createdAt,
|
|
84
|
+
config: config as CloudBoardConfig,
|
|
85
|
+
stopped: typeof stopped === "boolean" ? stopped : undefined,
|
|
86
|
+
tickets: Array.isArray(tickets)
|
|
87
|
+
? tickets.filter(
|
|
88
|
+
(ticket) =>
|
|
89
|
+
!!ticket &&
|
|
90
|
+
typeof ticket.runtimeId === "string" &&
|
|
91
|
+
typeof ticket.hash === "string" &&
|
|
92
|
+
typeof ticket.issuedAt === "string",
|
|
93
|
+
)
|
|
94
|
+
: undefined,
|
|
95
|
+
// Absent in a file written before boards could be shared.
|
|
96
|
+
members: Array.isArray(members) ? readMembers(members) : undefined,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
async load(): Promise<PersistedBoard[]> {
|
|
102
|
+
let userDirs: string[];
|
|
103
|
+
try {
|
|
104
|
+
userDirs = await fs.readdir(root);
|
|
105
|
+
} catch {
|
|
106
|
+
// Nothing has been deployed yet — the directory appears on first save.
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
const boards: PersistedBoard[] = [];
|
|
110
|
+
for (const dir of userDirs) {
|
|
111
|
+
let entries: string[];
|
|
112
|
+
try {
|
|
113
|
+
entries = await fs.readdir(path.join(root, dir));
|
|
114
|
+
} catch {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
for (const entry of entries) {
|
|
118
|
+
// Only finished files: a half-written one is still under its
|
|
119
|
+
// temporary name, which does not end in .json.
|
|
120
|
+
if (!entry.endsWith(".json")) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const board = await readBoard(path.join(root, dir, entry));
|
|
124
|
+
if (board) {
|
|
125
|
+
boards.push(board);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return boards;
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
async save(board: PersistedBoard): Promise<void> {
|
|
133
|
+
const dir = userDir(board.userId);
|
|
134
|
+
// A board config carries service state, which can carry credentials —
|
|
135
|
+
// so this is the owner's to read, and nobody else's.
|
|
136
|
+
await fs.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
137
|
+
const file = boardPath(board.userId, board.boardName);
|
|
138
|
+
const contents: BoardFile = { version: FORMAT_VERSION, ...board };
|
|
139
|
+
// Write beside the target, then rename: a rename within one directory is
|
|
140
|
+
// atomic, so a crash mid-write leaves the previous board intact rather
|
|
141
|
+
// than half of the new one.
|
|
142
|
+
const temporary = `${file}.${randomBytes(6).toString("hex")}.tmp`;
|
|
143
|
+
await fs.writeFile(temporary, JSON.stringify(contents, null, 2), {
|
|
144
|
+
mode: 0o600,
|
|
145
|
+
});
|
|
146
|
+
try {
|
|
147
|
+
await fs.rename(temporary, file);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
await fs.rm(temporary, { force: true });
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
async remove(userId: string, boardName: string): Promise<void> {
|
|
155
|
+
// Already gone is the outcome asked for.
|
|
156
|
+
await fs.rm(boardPath(userId, boardName), { force: true });
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How large one message between a coordinator and what is connected to it may
|
|
3
|
+
* be.
|
|
4
|
+
*
|
|
5
|
+
* Two limits, one derived from the other:
|
|
6
|
+
*
|
|
7
|
+
* - **The frame limit** is what a coordinator lets through: a value larger than
|
|
8
|
+
* it is dropped and logged as `frame-dropped`, and the connection stays — a
|
|
9
|
+
* board that lost a runtime over one large value would be wrong about what
|
|
10
|
+
* happened. `HKP_COORDINATOR_MAX_FRAME_BYTES` raises or lowers it; it is never
|
|
11
|
+
* off, because a socket that accepts anything buffers anything before a
|
|
12
|
+
* handler can look at it.
|
|
13
|
+
* - **The socket ceiling** is what the WebSocket library itself accepts, on
|
|
14
|
+
* every coordinator connection — a runtime server joining, a browser
|
|
15
|
+
* attaching, and this server's own link out to a coordinator. It sits above
|
|
16
|
+
* the frame limit by a margin, so the library only refuses what the frame
|
|
17
|
+
* limit would have dropped anyway, plus the room an introduction needs: a
|
|
18
|
+
* runtime server's hello carries its registry and is not held to the frame
|
|
19
|
+
* limit. Past the ceiling the library closes the connection, which is the
|
|
20
|
+
* one answer left for a message nobody should have sent.
|
|
21
|
+
*
|
|
22
|
+
* The same numbers are in hkp-python (`coordinator_links.py`) and hkp-rt
|
|
23
|
+
* (`link_socket.cpp`), which connect to a coordinator the way this server's
|
|
24
|
+
* links do.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** As large as an asset may be on hkp-rt: room for a sample or a recording. */
|
|
28
|
+
export const DEFAULT_MAX_FRAME_BYTES = 64 * 1024 * 1024;
|
|
29
|
+
|
|
30
|
+
/** What an introduction may need beyond a value. */
|
|
31
|
+
const SOCKET_HEADROOM_BYTES = 16 * 1024 * 1024;
|
|
32
|
+
|
|
33
|
+
/** The frame limit an operator's setting names; unset or 0 is the default. */
|
|
34
|
+
export function frameLimitFrom(value: number | undefined): number {
|
|
35
|
+
return value && value > 0 ? value : DEFAULT_MAX_FRAME_BYTES;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** What the WebSocket library accepts, for a frame limit. */
|
|
39
|
+
export function socketCeiling(frameLimit: number = DEFAULT_MAX_FRAME_BYTES): number {
|
|
40
|
+
return frameLimitFrom(frameLimit) + SOCKET_HEADROOM_BYTES;
|
|
41
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { createCoordinatorRouter } from "./router";
|
|
2
|
+
export { BoardCoordinator } from "./coordinator";
|
|
3
|
+
export { attachCoordinatorJoin } from "./join";
|
|
4
|
+
export { createBridgeHandler } from "./bridge";
|
|
5
|
+
export { SHARED_BOARDS_PATH } from "./router";
|
|
6
|
+
export type {
|
|
7
|
+
CloudBoardConfig,
|
|
8
|
+
CloudRuntimeDescriptor,
|
|
9
|
+
CloudServiceDescriptor,
|
|
10
|
+
BoardSessionInfo,
|
|
11
|
+
BoardSessionStatus,
|
|
12
|
+
} from "./types";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import { Duplex } from "node:stream";
|
|
3
|
+
|
|
4
|
+
import { WebSocketServer } from "ws";
|
|
5
|
+
|
|
6
|
+
import { BoardCoordinator } from "./coordinator";
|
|
7
|
+
import { JOIN_PATH } from "./participantProtocol";
|
|
8
|
+
import { socketCeiling } from "./frameLimits";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Where runtime servers connect in.
|
|
12
|
+
*
|
|
13
|
+
* The one endpoint of a coordinator that a user's token does not open: what
|
|
14
|
+
* connects here is a machine holding a ticket, possibly long after the person
|
|
15
|
+
* who deployed the board has gone. The ticket is presented as a bearer token on
|
|
16
|
+
* the upgrade and decides everything — which person, which board, which
|
|
17
|
+
* runtime — so the connection is told nothing and asks for nothing else.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
type UpgradeHost = {
|
|
21
|
+
addUpgradeRoute(
|
|
22
|
+
pathname: string,
|
|
23
|
+
handler: (
|
|
24
|
+
request: http.IncomingMessage,
|
|
25
|
+
socket: Duplex,
|
|
26
|
+
head: Buffer,
|
|
27
|
+
) => void,
|
|
28
|
+
): void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function attachCoordinatorJoin(
|
|
32
|
+
host: UpgradeHost,
|
|
33
|
+
coordinator: BoardCoordinator,
|
|
34
|
+
basePath = "/coordinator",
|
|
35
|
+
): void {
|
|
36
|
+
// What a coordinator's operator allows is decided per frame, and an
|
|
37
|
+
// oversized value is dropped without closing anything (ParticipantRegistry).
|
|
38
|
+
// The library's own ceiling sits above that, so it refuses only what the
|
|
39
|
+
// frame limit would have dropped anyway; see frameLimits.ts.
|
|
40
|
+
const wss = new WebSocketServer({
|
|
41
|
+
noServer: true,
|
|
42
|
+
maxPayload: socketCeiling(coordinator.maxFrameBytes),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
host.addUpgradeRoute(`${basePath}${JOIN_PATH}`, (request, socket, head) => {
|
|
46
|
+
const header = request.headers.authorization;
|
|
47
|
+
const ticket = header?.startsWith("Bearer ") ? header.slice(7) : undefined;
|
|
48
|
+
// Decided before the upgrade, so a ticket this coordinator does not hold is
|
|
49
|
+
// refused as an HTTP answer — which is what tells its holder to stop
|
|
50
|
+
// presenting it, rather than to try again.
|
|
51
|
+
if (!ticket || !coordinator.participants.resolve(ticket)) {
|
|
52
|
+
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
53
|
+
socket.destroy();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
57
|
+
if (!coordinator.participants.accept(ws, ticket)) {
|
|
58
|
+
ws.close();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|