@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.
Files changed (916) hide show
  1. package/README.md +114 -2
  2. package/bundle/LICENSE +201 -0
  3. package/bundle/boards/aggregator-demo-board.json +54 -0
  4. package/bundle/boards/alpaca-board.json +316 -0
  5. package/bundle/boards/animate-board.json +159 -0
  6. package/bundle/boards/ascii-art-demo-board.json +33 -0
  7. package/bundle/boards/ascii-cam-board.json +184 -0
  8. package/bundle/boards/asset-demo-board.json +54 -0
  9. package/bundle/boards/audio-encode-demo-board.json +153 -0
  10. package/bundle/boards/audiolize-board.json +152 -0
  11. package/bundle/boards/batcher-demo-board.json +43 -0
  12. package/bundle/boards/buffer-demo-board.json +53 -0
  13. package/bundle/boards/cache-demo-board.json +59 -0
  14. package/bundle/boards/camera-demo-board.json +28 -0
  15. package/bundle/boards/canvas-demo-board.json +55 -0
  16. package/bundle/boards/changes-demo-board.json +60 -0
  17. package/bundle/boards/court-booking-browser-demo-board.json +221 -0
  18. package/bundle/boards/court-booking-demo-board.json +218 -0
  19. package/bundle/boards/current-time-board.json +32 -0
  20. package/bundle/boards/debounce-demo-board.json +43 -0
  21. package/bundle/boards/decrypt-demo-board.json +47 -0
  22. package/bundle/boards/delay-demo-board.json +28 -0
  23. package/bundle/boards/detect-demo-board.json +64 -0
  24. package/bundle/boards/document-extract-demo-board.json +55 -0
  25. package/bundle/boards/dropitapp-board.json +138 -0
  26. package/bundle/boards/encode-demo-board.json +39 -0
  27. package/bundle/boards/encrypt-board.json +185 -0
  28. package/bundle/boards/encrypt-demo-board.json +39 -0
  29. package/bundle/boards/face-alert-board.json +181 -0
  30. package/bundle/boards/fetcher-demo-board.json +40 -0
  31. package/bundle/boards/fft-demo-board.json +28 -0
  32. package/bundle/boards/filter-demo-board.json +55 -0
  33. package/bundle/boards/flat-map-demo-board.json +42 -0
  34. package/bundle/boards/frame-limit-test-board.json +130 -0
  35. package/bundle/boards/game-board.json +413 -0
  36. package/bundle/boards/game-of-life-board.json +139 -0
  37. package/bundle/boards/game-of-life-demo-board.json +34 -0
  38. package/bundle/boards/gather-demo-board.json +62 -0
  39. package/bundle/boards/group-by-demo-board.json +62 -0
  40. package/bundle/boards/hacker-demo-board.json +45 -0
  41. package/bundle/boards/hacker-news-board.json +741 -0
  42. package/bundle/boards/hash-demo-board.json +40 -0
  43. package/bundle/boards/health-log-browser-demo-board.json +537 -0
  44. package/bundle/boards/health-log-demo-board.json +498 -0
  45. package/bundle/boards/helloworld-board.json +57 -0
  46. package/bundle/boards/hold-demo-board.json +67 -0
  47. package/bundle/boards/hold-scopes-demo-board.json +141 -0
  48. package/bundle/boards/http-client-browser-demo-board.json +379 -0
  49. package/bundle/boards/http-client-demo-board.json +380 -0
  50. package/bundle/boards/image-picker-demo-board.json +22 -0
  51. package/bundle/boards/imap-email-demo-board.json +35 -0
  52. package/bundle/boards/injector-demo-board.json +55 -0
  53. package/bundle/boards/iterator-demo-board.json +55 -0
  54. package/bundle/boards/limit-demo-board.json +66 -0
  55. package/bundle/boards/link-debugger.json +32 -0
  56. package/bundle/boards/live-location-demo-board.json +93 -0
  57. package/bundle/boards/live-radio-cloud-demo-board.json +216 -0
  58. package/bundle/boards/live-radio-cloud-direct-demo-board.json +311 -0
  59. package/bundle/boards/live-radio-demo-board.json +211 -0
  60. package/bundle/boards/live-radio-members-demo-board.json +314 -0
  61. package/bundle/boards/local-storage-demo-board.json +30 -0
  62. package/bundle/boards/lz-compress-demo-board.json +52 -0
  63. package/bundle/boards/map-demo-board.json +46 -0
  64. package/bundle/boards/match-filter-demo-board.json +43 -0
  65. package/bundle/boards/meeting-poll-browser-demo-board.json +649 -0
  66. package/bundle/boards/meeting-poll-demo-board.json +650 -0
  67. package/bundle/boards/microphone-monitor-demo-board.json +28 -0
  68. package/bundle/boards/microphone-speaker-demo-board.json +86 -0
  69. package/bundle/boards/monitor-demo-board.json +52 -0
  70. package/bundle/boards/mounted-endpoint-demo-board-hkp-rt.json +84 -0
  71. package/bundle/boards/mounted-endpoint-demo-board.json +84 -0
  72. package/bundle/boards/nested-rhythm-demo-board.json +1160 -0
  73. package/bundle/boards/next-bus-board.json +52 -0
  74. package/bundle/boards/next-bus-switch-board.json +79 -0
  75. package/bundle/boards/night-groove-demo-board.json +742 -0
  76. package/bundle/boards/noise-alert-board.json +146 -0
  77. package/bundle/boards/offer-followup-demo-board.json +291 -0
  78. package/bundle/boards/offer-intake-demo-board.json +289 -0
  79. package/bundle/boards/offer-intake-hetzner-demo-board.json +286 -0
  80. package/bundle/boards/offer-intake-imap-demo-board.json +289 -0
  81. package/bundle/boards/offer-intake-imap-hetzner-demo-board.json +354 -0
  82. package/bundle/boards/p2p-receiver-demo-board.json +65 -0
  83. package/bundle/boards/p2p-sender-demo-board.json +94 -0
  84. package/bundle/boards/pad-groove-demo-board.json +644 -0
  85. package/bundle/boards/peer-chat-board.json +109 -0
  86. package/bundle/boards/peer-chat-node-board.json +97 -0
  87. package/bundle/boards/qr-code-demo-board.json +22 -0
  88. package/bundle/boards/queue-demo-board.json +239 -0
  89. package/bundle/boards/reduce-demo-board.json +54 -0
  90. package/bundle/boards/remote-named-demo-board-hkp-rt.json +61 -0
  91. package/bundle/boards/remote-named-demo-board.json +61 -0
  92. package/bundle/boards/rss-demo-board.json +530 -0
  93. package/bundle/boards/rss-radio-board.json +515 -0
  94. package/bundle/boards/rss-radio-brief-one-board.json +237 -0
  95. package/bundle/boards/rss-radio-editor-unit-board.json +555 -0
  96. package/bundle/boards/rss-radio-library-unit-board.json +293 -0
  97. package/bundle/boards/rss-radio-unit-board.json +809 -0
  98. package/bundle/boards/rss-radio-voice-unit-board.json +146 -0
  99. package/bundle/boards/runtime-configs/hold-example.json +41 -0
  100. package/bundle/boards/runtime-configs/injector-example.json +23 -0
  101. package/bundle/boards/runtime-configs/speech-to-text-example.json +35 -0
  102. package/bundle/boards/runtime-configs/text-generation-example.json +31 -0
  103. package/bundle/boards/runtime-configs/text-to-speech-example.json +28 -0
  104. package/bundle/boards/runtime-configs/text-to-speech-inflect-example.json +28 -0
  105. package/bundle/boards/runtime-configs/ws-audio-playback-example.json +23 -0
  106. package/bundle/boards/select-demo-board.json +32 -0
  107. package/bundle/boards/send-ntfy-board.json +52 -0
  108. package/bundle/boards/shared-costs-demo-board.json +361 -0
  109. package/bundle/boards/sign-demo-board.json +41 -0
  110. package/bundle/boards/skill-router-demo-board.json +210 -0
  111. package/bundle/boards/smooth-demo-board.json +91 -0
  112. package/bundle/boards/smtp-email-demo-board.json +34 -0
  113. package/bundle/boards/sort-demo-board.json +55 -0
  114. package/bundle/boards/sound-demo-board.json +65 -0
  115. package/bundle/boards/spectral-modifier-board.json +98 -0
  116. package/bundle/boards/speech-synth-demo-board.json +37 -0
  117. package/bundle/boards/speech-to-text-demo-board.json +146 -0
  118. package/bundle/boards/spotify-board.json +75 -0
  119. package/bundle/boards/spread-demo-board.json +35 -0
  120. package/bundle/boards/sql-demo-board.json +56 -0
  121. package/bundle/boards/sql-explorer-board.json +447 -0
  122. package/bundle/boards/sql-explorer-node-board.json +474 -0
  123. package/bundle/boards/sql-import-board.json +156 -0
  124. package/bundle/boards/state-demo-board.json +65 -0
  125. package/bundle/boards/stopper-demo-board.json +40 -0
  126. package/bundle/boards/storage-demo-board.json +193 -0
  127. package/bundle/boards/store-demo-board.json +63 -0
  128. package/bundle/boards/swimlanes-demo-board.json +197 -0
  129. package/bundle/boards/switch-demo-board.json +51 -0
  130. package/bundle/boards/syn-board.json +19 -0
  131. package/bundle/boards/syn-booking-unit-board.json +998 -0
  132. package/bundle/boards/syn-conversations-anthropic-demo-board.json +925 -0
  133. package/bundle/boards/syn-conversations-demo-board.json +925 -0
  134. package/bundle/boards/syn-hotels-unit-board.json +287 -0
  135. package/bundle/boards/syn-mail-desk-board.json +25 -0
  136. package/bundle/boards/syn-mail-desk-unit-board.json +254 -0
  137. package/bundle/boards/telegram-listener-demo-board.json +31 -0
  138. package/bundle/boards/text-generation-anthropic-demo-board.json +66 -0
  139. package/bundle/boards/text-generation-demo-board.json +51 -0
  140. package/bundle/boards/text-generation-local-demo-board.json +80 -0
  141. package/bundle/boards/text-to-speech-demo-board.json +58 -0
  142. package/bundle/boards/timeline-demo-board.json +477 -0
  143. package/bundle/boards/timer-demo-board.json +35 -0
  144. package/bundle/boards/tracks-demo-board.json +95 -0
  145. package/bundle/boards/trigger-pad-demo-board.json +47 -0
  146. package/bundle/boards/triggerpad-board.json +31 -0
  147. package/bundle/boards/triggerpad-recorder-board.json +56 -0
  148. package/bundle/boards/uuid-generator-demo-board.json +166 -0
  149. package/bundle/boards/voice-assistant-demo-board.json +230 -0
  150. package/bundle/boards/voice-assistant-hkp-rt-demo-board.json +239 -0
  151. package/bundle/boards/voice-assistant-local-demo-board.json +232 -0
  152. package/bundle/boards/voice-assistant-skills-demo-board.json +316 -0
  153. package/bundle/boards/voice-assistant-skills-local-demo-board.json +316 -0
  154. package/bundle/boards/xy-pad-demo-board.json +36 -0
  155. package/bundle/docs/content/board-json.md +277 -0
  156. package/bundle/docs/content/boards/alpaca-board.md +56 -0
  157. package/bundle/docs/content/boards/animate-board.md +40 -0
  158. package/bundle/docs/content/boards/ascii-cam-board.md +37 -0
  159. package/bundle/docs/content/boards/audiolize-board.md +47 -0
  160. package/bundle/docs/content/boards/court-booking-browser-demo-board.md +43 -0
  161. package/bundle/docs/content/boards/court-booking-demo-board.md +120 -0
  162. package/bundle/docs/content/boards/current-time-board.md +32 -0
  163. package/bundle/docs/content/boards/dropitapp-board.md +57 -0
  164. package/bundle/docs/content/boards/encrypt-board.md +36 -0
  165. package/bundle/docs/content/boards/face-alert-board.md +50 -0
  166. package/bundle/docs/content/boards/game-board.md +69 -0
  167. package/bundle/docs/content/boards/game-of-life-board.md +47 -0
  168. package/bundle/docs/content/boards/hacker-news-board.md +76 -0
  169. package/bundle/docs/content/boards/health-log-browser-demo-board.md +56 -0
  170. package/bundle/docs/content/boards/health-log-demo-board.md +138 -0
  171. package/bundle/docs/content/boards/helloworld-board.md +40 -0
  172. package/bundle/docs/content/boards/link-debugger.md +31 -0
  173. package/bundle/docs/content/boards/live-radio-cloud-demo-board.md +70 -0
  174. package/bundle/docs/content/boards/live-radio-cloud-direct-demo-board.md +89 -0
  175. package/bundle/docs/content/boards/live-radio-demo-board.md +102 -0
  176. package/bundle/docs/content/boards/live-radio-members-demo-board.md +91 -0
  177. package/bundle/docs/content/boards/meeting-poll-browser-demo-board.md +45 -0
  178. package/bundle/docs/content/boards/meeting-poll-demo-board.md +121 -0
  179. package/bundle/docs/content/boards/mounted-endpoint-demo-board-hkp-rt.md +50 -0
  180. package/bundle/docs/content/boards/nested-rhythm-demo-board.md +165 -0
  181. package/bundle/docs/content/boards/next-bus-board.md +38 -0
  182. package/bundle/docs/content/boards/next-bus-switch-board.md +44 -0
  183. package/bundle/docs/content/boards/night-groove-demo-board.md +110 -0
  184. package/bundle/docs/content/boards/noise-alert-board.md +44 -0
  185. package/bundle/docs/content/boards/pad-groove-demo-board.md +93 -0
  186. package/bundle/docs/content/boards/peer-chat-board.md +49 -0
  187. package/bundle/docs/content/boards/peer-chat-node-board.md +47 -0
  188. package/bundle/docs/content/boards/rss-radio-board.md +221 -0
  189. package/bundle/docs/content/boards/send-ntfy-board.md +33 -0
  190. package/bundle/docs/content/boards/shared-costs-demo-board.md +65 -0
  191. package/bundle/docs/content/boards/spectral-modifier-board.md +55 -0
  192. package/bundle/docs/content/boards/spotify-board.md +46 -0
  193. package/bundle/docs/content/boards/sql-explorer-board.md +70 -0
  194. package/bundle/docs/content/boards/sql-explorer-node-board.md +76 -0
  195. package/bundle/docs/content/boards/sql-import-board.md +37 -0
  196. package/bundle/docs/content/boards/swimlanes-demo-board.md +148 -0
  197. package/bundle/docs/content/boards/syn-mail-desk-board.md +52 -0
  198. package/bundle/docs/content/boards/timeline-demo-board.md +115 -0
  199. package/bundle/docs/content/boards/triggerpad-board.md +32 -0
  200. package/bundle/docs/content/boards/triggerpad-recorder-board.md +52 -0
  201. package/bundle/docs/content/boards/voice-assistant-demo-board.md +51 -0
  202. package/bundle/docs/content/concepts/assets.md +245 -0
  203. package/bundle/docs/content/concepts/blocks.md +300 -0
  204. package/bundle/docs/content/concepts/board-assistant.md +307 -0
  205. package/bundle/docs/content/concepts/board.md +265 -0
  206. package/bundle/docs/content/concepts/cloud-boards.md +803 -0
  207. package/bundle/docs/content/concepts/coordinator.md +297 -0
  208. package/bundle/docs/content/concepts/logging.md +293 -0
  209. package/bundle/docs/content/concepts/mounts.md +314 -0
  210. package/bundle/docs/content/concepts/presets.md +360 -0
  211. package/bundle/docs/content/concepts/remotes.md +423 -0
  212. package/bundle/docs/content/concepts/runtime.md +664 -0
  213. package/bundle/docs/content/concepts/scopes.md +256 -0
  214. package/bundle/docs/content/concepts/service.md +227 -0
  215. package/bundle/docs/content/concepts/units.md +321 -0
  216. package/bundle/docs/content/introduction.md +163 -0
  217. package/bundle/docs/content/llm/circle-text-board.json +55 -0
  218. package/bundle/docs/content/llm/howto-workflow.md +369 -0
  219. package/bundle/docs/content/repository.md +161 -0
  220. package/bundle/docs/content/services/aggregator.md +76 -0
  221. package/bundle/docs/content/services/analyzer.md +44 -0
  222. package/bundle/docs/content/services/ascii-art.md +58 -0
  223. package/bundle/docs/content/services/asset.md +88 -0
  224. package/bundle/docs/content/services/audio-editor.md +57 -0
  225. package/bundle/docs/content/services/audio-encode.md +115 -0
  226. package/bundle/docs/content/services/audio-io.md +173 -0
  227. package/bundle/docs/content/services/batcher.md +49 -0
  228. package/bundle/docs/content/services/board-service.md +48 -0
  229. package/bundle/docs/content/services/browser-sub-service.md +75 -0
  230. package/bundle/docs/content/services/buffer.md +70 -0
  231. package/bundle/docs/content/services/cache.md +92 -0
  232. package/bundle/docs/content/services/camera.md +85 -0
  233. package/bundle/docs/content/services/canvas.md +196 -0
  234. package/bundle/docs/content/services/changes.md +87 -0
  235. package/bundle/docs/content/services/chunked-file-provider.md +63 -0
  236. package/bundle/docs/content/services/communication-dispatcher.md +190 -0
  237. package/bundle/docs/content/services/configurator.md +66 -0
  238. package/bundle/docs/content/services/conversations.md +244 -0
  239. package/bundle/docs/content/services/debounce.md +45 -0
  240. package/bundle/docs/content/services/decrypt.md +53 -0
  241. package/bundle/docs/content/services/delay.md +55 -0
  242. package/bundle/docs/content/services/detect.md +101 -0
  243. package/bundle/docs/content/services/document-extract.md +174 -0
  244. package/bundle/docs/content/services/download.md +67 -0
  245. package/bundle/docs/content/services/encode.md +63 -0
  246. package/bundle/docs/content/services/encrypt.md +53 -0
  247. package/bundle/docs/content/services/fetcher.md +122 -0
  248. package/bundle/docs/content/services/fft.md +96 -0
  249. package/bundle/docs/content/services/file-source.md +67 -0
  250. package/bundle/docs/content/services/filesystem.md +157 -0
  251. package/bundle/docs/content/services/filter.md +133 -0
  252. package/bundle/docs/content/services/flat-map.md +62 -0
  253. package/bundle/docs/content/services/game-of-life.md +93 -0
  254. package/bundle/docs/content/services/gather.md +135 -0
  255. package/bundle/docs/content/services/gif-encoder.md +56 -0
  256. package/bundle/docs/content/services/github.md +85 -0
  257. package/bundle/docs/content/services/group-by.md +54 -0
  258. package/bundle/docs/content/services/hacker.md +79 -0
  259. package/bundle/docs/content/services/hash.md +59 -0
  260. package/bundle/docs/content/services/hold.md +182 -0
  261. package/bundle/docs/content/services/http-relay-client.md +48 -0
  262. package/bundle/docs/content/services/http-uploader.md +62 -0
  263. package/bundle/docs/content/services/http.md +424 -0
  264. package/bundle/docs/content/services/if.md +79 -0
  265. package/bundle/docs/content/services/ifft.md +46 -0
  266. package/bundle/docs/content/services/image-picker.md +50 -0
  267. package/bundle/docs/content/services/imap-email.md +104 -0
  268. package/bundle/docs/content/services/injector.md +129 -0
  269. package/bundle/docs/content/services/input.md +90 -0
  270. package/bundle/docs/content/services/iterator.md +186 -0
  271. package/bundle/docs/content/services/join.md +153 -0
  272. package/bundle/docs/content/services/limit.md +47 -0
  273. package/bundle/docs/content/services/local-storage.md +47 -0
  274. package/bundle/docs/content/services/looper.md +62 -0
  275. package/bundle/docs/content/services/lz-compress.md +52 -0
  276. package/bundle/docs/content/services/map.md +257 -0
  277. package/bundle/docs/content/services/match-filter.md +38 -0
  278. package/bundle/docs/content/services/microphone-monitor.md +66 -0
  279. package/bundle/docs/content/services/monitor.md +67 -0
  280. package/bundle/docs/content/services/ollama.md +116 -0
  281. package/bundle/docs/content/services/openai-prompt.md +74 -0
  282. package/bundle/docs/content/services/output.md +107 -0
  283. package/bundle/docs/content/services/peer-socket.md +61 -0
  284. package/bundle/docs/content/services/qr-code.md +48 -0
  285. package/bundle/docs/content/services/queue.md +201 -0
  286. package/bundle/docs/content/services/reduce.md +51 -0
  287. package/bundle/docs/content/services/rss.md +232 -0
  288. package/bundle/docs/content/services/select.md +47 -0
  289. package/bundle/docs/content/services/sign.md +53 -0
  290. package/bundle/docs/content/services/skill-router.md +154 -0
  291. package/bundle/docs/content/services/smooth.md +59 -0
  292. package/bundle/docs/content/services/smtp-email.md +129 -0
  293. package/bundle/docs/content/services/sort.md +48 -0
  294. package/bundle/docs/content/services/sound.md +87 -0
  295. package/bundle/docs/content/services/speech-synth.md +46 -0
  296. package/bundle/docs/content/services/speech-to-text.md +172 -0
  297. package/bundle/docs/content/services/spotify.md +77 -0
  298. package/bundle/docs/content/services/spread.md +111 -0
  299. package/bundle/docs/content/services/sql.md +491 -0
  300. package/bundle/docs/content/services/state.md +57 -0
  301. package/bundle/docs/content/services/static.md +47 -0
  302. package/bundle/docs/content/services/stopper.md +55 -0
  303. package/bundle/docs/content/services/storage.md +155 -0
  304. package/bundle/docs/content/services/store.md +255 -0
  305. package/bundle/docs/content/services/sub-service.md +152 -0
  306. package/bundle/docs/content/services/switch.md +67 -0
  307. package/bundle/docs/content/services/telegram-listener.md +76 -0
  308. package/bundle/docs/content/services/text-generation.md +390 -0
  309. package/bundle/docs/content/services/text-to-speech.md +130 -0
  310. package/bundle/docs/content/services/timeline.md +333 -0
  311. package/bundle/docs/content/services/timer.md +113 -0
  312. package/bundle/docs/content/services/tracks.md +207 -0
  313. package/bundle/docs/content/services/trigger-pad.md +68 -0
  314. package/bundle/docs/content/services/uuid-generator.md +48 -0
  315. package/bundle/docs/content/services/wav-reader.md +66 -0
  316. package/bundle/docs/content/services/websocket.md +189 -0
  317. package/bundle/docs/content/services/workflow-board-builder.md +65 -0
  318. package/bundle/docs/content/services/xy-pad.md +60 -0
  319. package/bundle/docs/content/targets.md +434 -0
  320. package/bundle/docs/content/testing.md +263 -0
  321. package/bundle/docs/content/vocabulary.md +171 -0
  322. package/bundle/hkp-frontend/src/runtime/browser/BrowserRegistry.tsx +141 -0
  323. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntime.tsx +202 -0
  324. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeApi.ts +306 -0
  325. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeApp.ts +310 -0
  326. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeScope.ts +500 -0
  327. package/bundle/hkp-frontend/src/runtime/browser/UIRegistry.ts +150 -0
  328. package/bundle/hkp-frontend/src/runtime/browser/assetResolver.ts +123 -0
  329. package/bundle/hkp-frontend/src/runtime/browser/pipelineNames.ts +65 -0
  330. package/bundle/hkp-frontend/src/runtime/browser/registry/Default.ts +237 -0
  331. package/bundle/hkp-frontend/src/runtime/browser/services/Aggregator.ts +127 -0
  332. package/bundle/hkp-frontend/src/runtime/browser/services/AggregatorUI.tsx +83 -0
  333. package/bundle/hkp-frontend/src/runtime/browser/services/Analyzer.tsx +43 -0
  334. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/Bars.tsx +33 -0
  335. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/HorizontalSpectrogram.tsx +53 -0
  336. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/VerticalSpectogram.tsx +56 -0
  337. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/Waveform.tsx +109 -0
  338. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/index.tsx +99 -0
  339. package/bundle/hkp-frontend/src/runtime/browser/services/AsciiArt.ts +119 -0
  340. package/bundle/hkp-frontend/src/runtime/browser/services/AsciiArtUI.tsx +131 -0
  341. package/bundle/hkp-frontend/src/runtime/browser/services/Asset.ts +125 -0
  342. package/bundle/hkp-frontend/src/runtime/browser/services/AssetUI.tsx +37 -0
  343. package/bundle/hkp-frontend/src/runtime/browser/services/AudioDeviceSettings.tsx +56 -0
  344. package/bundle/hkp-frontend/src/runtime/browser/services/AudioEditor.ts +129 -0
  345. package/bundle/hkp-frontend/src/runtime/browser/services/AudioEditorUI.tsx +549 -0
  346. package/bundle/hkp-frontend/src/runtime/browser/services/AudioInput.ts +298 -0
  347. package/bundle/hkp-frontend/src/runtime/browser/services/AudioInputUI.tsx +257 -0
  348. package/bundle/hkp-frontend/src/runtime/browser/services/AudioOutput.ts +189 -0
  349. package/bundle/hkp-frontend/src/runtime/browser/services/AudioOutputUI.tsx +63 -0
  350. package/bundle/hkp-frontend/src/runtime/browser/services/Batcher.ts +11 -0
  351. package/bundle/hkp-frontend/src/runtime/browser/services/BoardService.tsx +86 -0
  352. package/bundle/hkp-frontend/src/runtime/browser/services/BoardServiceUI.tsx +410 -0
  353. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserGather.ts +311 -0
  354. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserIterator.ts +167 -0
  355. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserSubService.tsx +583 -0
  356. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserSubServiceUI.tsx +187 -0
  357. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserTracks.tsx +477 -0
  358. package/bundle/hkp-frontend/src/runtime/browser/services/Buffer.ts +11 -0
  359. package/bundle/hkp-frontend/src/runtime/browser/services/Cache.ts +134 -0
  360. package/bundle/hkp-frontend/src/runtime/browser/services/CacheUI.tsx +125 -0
  361. package/bundle/hkp-frontend/src/runtime/browser/services/Camera.ts +90 -0
  362. package/bundle/hkp-frontend/src/runtime/browser/services/CameraUI.tsx +321 -0
  363. package/bundle/hkp-frontend/src/runtime/browser/services/Canvas.ts +139 -0
  364. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/canvasDraw.ts +543 -0
  365. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/canvasUtils.ts +39 -0
  366. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/index.tsx +287 -0
  367. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/canvasDraw.test.ts +355 -0
  368. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/canvasUtils.test.ts +89 -0
  369. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/fullscreen.test.tsx +26 -0
  370. package/bundle/hkp-frontend/src/runtime/browser/services/Changes.ts +201 -0
  371. package/bundle/hkp-frontend/src/runtime/browser/services/ChangesUI.tsx +85 -0
  372. package/bundle/hkp-frontend/src/runtime/browser/services/ChunkedFileProvider.tsx +183 -0
  373. package/bundle/hkp-frontend/src/runtime/browser/services/Configurator.ts +258 -0
  374. package/bundle/hkp-frontend/src/runtime/browser/services/ConfiguratorUI.tsx +83 -0
  375. package/bundle/hkp-frontend/src/runtime/browser/services/ConsideredHacker.tsx +28 -0
  376. package/bundle/hkp-frontend/src/runtime/browser/services/Debounce.ts +75 -0
  377. package/bundle/hkp-frontend/src/runtime/browser/services/DebounceUI.tsx +70 -0
  378. package/bundle/hkp-frontend/src/runtime/browser/services/Decrypt.ts +127 -0
  379. package/bundle/hkp-frontend/src/runtime/browser/services/DecryptUI.tsx +39 -0
  380. package/bundle/hkp-frontend/src/runtime/browser/services/Delay.tsx +110 -0
  381. package/bundle/hkp-frontend/src/runtime/browser/services/Detect.ts +214 -0
  382. package/bundle/hkp-frontend/src/runtime/browser/services/DetectUI.tsx +86 -0
  383. package/bundle/hkp-frontend/src/runtime/browser/services/Download.ts +120 -0
  384. package/bundle/hkp-frontend/src/runtime/browser/services/DownloadUI.tsx +61 -0
  385. package/bundle/hkp-frontend/src/runtime/browser/services/Encode.ts +138 -0
  386. package/bundle/hkp-frontend/src/runtime/browser/services/EncodeUI.tsx +52 -0
  387. package/bundle/hkp-frontend/src/runtime/browser/services/Encrypt.ts +125 -0
  388. package/bundle/hkp-frontend/src/runtime/browser/services/EncryptUI.tsx +39 -0
  389. package/bundle/hkp-frontend/src/runtime/browser/services/FFT.tsx +238 -0
  390. package/bundle/hkp-frontend/src/runtime/browser/services/FFTUI.tsx +112 -0
  391. package/bundle/hkp-frontend/src/runtime/browser/services/FeedbackService.ts +247 -0
  392. package/bundle/hkp-frontend/src/runtime/browser/services/FeedbackServiceUI.tsx +35 -0
  393. package/bundle/hkp-frontend/src/runtime/browser/services/Fetcher.tsx +232 -0
  394. package/bundle/hkp-frontend/src/runtime/browser/services/FetcherUI.tsx +154 -0
  395. package/bundle/hkp-frontend/src/runtime/browser/services/FileSource.tsx +171 -0
  396. package/bundle/hkp-frontend/src/runtime/browser/services/Filter.tsx +18 -0
  397. package/bundle/hkp-frontend/src/runtime/browser/services/FilterUI.tsx +89 -0
  398. package/bundle/hkp-frontend/src/runtime/browser/services/FlatMap.ts +68 -0
  399. package/bundle/hkp-frontend/src/runtime/browser/services/FlatMapUI.tsx +38 -0
  400. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLife.ts +210 -0
  401. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeRenderer.ts +182 -0
  402. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeRendererUI.tsx +48 -0
  403. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeUI.tsx +58 -0
  404. package/bundle/hkp-frontend/src/runtime/browser/services/GatherUI.tsx +84 -0
  405. package/bundle/hkp-frontend/src/runtime/browser/services/GifEncoder.tsx +651 -0
  406. package/bundle/hkp-frontend/src/runtime/browser/services/GithubAPI.ts +294 -0
  407. package/bundle/hkp-frontend/src/runtime/browser/services/GithubComponents.tsx +389 -0
  408. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSink.tsx +109 -0
  409. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSinkUI.tsx +143 -0
  410. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSource.tsx +86 -0
  411. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSourceUI.tsx +162 -0
  412. package/bundle/hkp-frontend/src/runtime/browser/services/GroupBy.ts +11 -0
  413. package/bundle/hkp-frontend/src/runtime/browser/services/HTTPUploader.ts +102 -0
  414. package/bundle/hkp-frontend/src/runtime/browser/services/Hacker.ts +73 -0
  415. package/bundle/hkp-frontend/src/runtime/browser/services/HackerUI.tsx +134 -0
  416. package/bundle/hkp-frontend/src/runtime/browser/services/Hash.ts +134 -0
  417. package/bundle/hkp-frontend/src/runtime/browser/services/HashUI.tsx +45 -0
  418. package/bundle/hkp-frontend/src/runtime/browser/services/Hold.ts +288 -0
  419. package/bundle/hkp-frontend/src/runtime/browser/services/HoldUI.tsx +43 -0
  420. package/bundle/hkp-frontend/src/runtime/browser/services/HttpClient.ts +558 -0
  421. package/bundle/hkp-frontend/src/runtime/browser/services/HttpClientUI.tsx +212 -0
  422. package/bundle/hkp-frontend/src/runtime/browser/services/HttpUploaderTokenInjector.ts +149 -0
  423. package/bundle/hkp-frontend/src/runtime/browser/services/IfService.ts +231 -0
  424. package/bundle/hkp-frontend/src/runtime/browser/services/IfServiceUI.tsx +50 -0
  425. package/bundle/hkp-frontend/src/runtime/browser/services/ImagePicker.tsx +118 -0
  426. package/bundle/hkp-frontend/src/runtime/browser/services/Injector.ts +61 -0
  427. package/bundle/hkp-frontend/src/runtime/browser/services/InjectorUI.tsx +389 -0
  428. package/bundle/hkp-frontend/src/runtime/browser/services/Input.ts +214 -0
  429. package/bundle/hkp-frontend/src/runtime/browser/services/InputUI.tsx +71 -0
  430. package/bundle/hkp-frontend/src/runtime/browser/services/IteratorUI.tsx +59 -0
  431. package/bundle/hkp-frontend/src/runtime/browser/services/LZCompress.ts +63 -0
  432. package/bundle/hkp-frontend/src/runtime/browser/services/Limit.ts +39 -0
  433. package/bundle/hkp-frontend/src/runtime/browser/services/LimitUI.tsx +41 -0
  434. package/bundle/hkp-frontend/src/runtime/browser/services/LocalStorage.ts +65 -0
  435. package/bundle/hkp-frontend/src/runtime/browser/services/LocalStorageUI.tsx +72 -0
  436. package/bundle/hkp-frontend/src/runtime/browser/services/Map.ts +14 -0
  437. package/bundle/hkp-frontend/src/runtime/browser/services/MapUI.tsx +334 -0
  438. package/bundle/hkp-frontend/src/runtime/browser/services/MapUIModeAssist.tsx +61 -0
  439. package/bundle/hkp-frontend/src/runtime/browser/services/MatchFilter.ts +11 -0
  440. package/bundle/hkp-frontend/src/runtime/browser/services/MicrophoneMonitor.ts +190 -0
  441. package/bundle/hkp-frontend/src/runtime/browser/services/MicrophoneMonitorUI.tsx +94 -0
  442. package/bundle/hkp-frontend/src/runtime/browser/services/Monitor.tsx +15 -0
  443. package/bundle/hkp-frontend/src/runtime/browser/services/MonitorUI.tsx +281 -0
  444. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPrompt.ts +237 -0
  445. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/BusyIndicator.tsx +18 -0
  446. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/PromptInput.tsx +71 -0
  447. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/StreamingPreview.tsx +24 -0
  448. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/index.tsx +156 -0
  449. package/bundle/hkp-frontend/src/runtime/browser/services/OpenAIPrompt.ts +254 -0
  450. package/bundle/hkp-frontend/src/runtime/browser/services/OpenAIPromptUI.tsx +189 -0
  451. package/bundle/hkp-frontend/src/runtime/browser/services/Output.tsx +145 -0
  452. package/bundle/hkp-frontend/src/runtime/browser/services/OutputUI.tsx +118 -0
  453. package/bundle/hkp-frontend/src/runtime/browser/services/PeerChatTemplate.json +43 -0
  454. package/bundle/hkp-frontend/src/runtime/browser/services/PeerConnection.ts +260 -0
  455. package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocket.tsx +268 -0
  456. package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocketReceiverTemplate.json +29 -0
  457. package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocketUI.tsx +341 -0
  458. package/bundle/hkp-frontend/src/runtime/browser/services/PlaceholderUI.tsx +72 -0
  459. package/bundle/hkp-frontend/src/runtime/browser/services/QrCode.ts +63 -0
  460. package/bundle/hkp-frontend/src/runtime/browser/services/QrCodeUI.tsx +197 -0
  461. package/bundle/hkp-frontend/src/runtime/browser/services/Select.ts +40 -0
  462. package/bundle/hkp-frontend/src/runtime/browser/services/SelectUI.tsx +41 -0
  463. package/bundle/hkp-frontend/src/runtime/browser/services/ServiceBase.ts +50 -0
  464. package/bundle/hkp-frontend/src/runtime/browser/services/SetRuntimeVariable.ts +65 -0
  465. package/bundle/hkp-frontend/src/runtime/browser/services/SetRuntimeVariableUI.tsx +50 -0
  466. package/bundle/hkp-frontend/src/runtime/browser/services/Sign.ts +182 -0
  467. package/bundle/hkp-frontend/src/runtime/browser/services/SignUI.tsx +55 -0
  468. package/bundle/hkp-frontend/src/runtime/browser/services/Smooth.ts +101 -0
  469. package/bundle/hkp-frontend/src/runtime/browser/services/SmoothUI.tsx +50 -0
  470. package/bundle/hkp-frontend/src/runtime/browser/services/Sort.ts +59 -0
  471. package/bundle/hkp-frontend/src/runtime/browser/services/SortUI.tsx +61 -0
  472. package/bundle/hkp-frontend/src/runtime/browser/services/Sound.ts +541 -0
  473. package/bundle/hkp-frontend/src/runtime/browser/services/SoundUI.tsx +183 -0
  474. package/bundle/hkp-frontend/src/runtime/browser/services/SpeechSynth.ts +56 -0
  475. package/bundle/hkp-frontend/src/runtime/browser/services/SpeechSynthUI.tsx +108 -0
  476. package/bundle/hkp-frontend/src/runtime/browser/services/Spotify.tsx +111 -0
  477. package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyAPI.ts +113 -0
  478. package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyComponents.tsx +104 -0
  479. package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyUI.tsx +186 -0
  480. package/bundle/hkp-frontend/src/runtime/browser/services/Spread.ts +117 -0
  481. package/bundle/hkp-frontend/src/runtime/browser/services/SpreadUI.tsx +38 -0
  482. package/bundle/hkp-frontend/src/runtime/browser/services/Sql.ts +448 -0
  483. package/bundle/hkp-frontend/src/runtime/browser/services/SqlInspector.tsx +332 -0
  484. package/bundle/hkp-frontend/src/runtime/browser/services/SqlUI.tsx +226 -0
  485. package/bundle/hkp-frontend/src/runtime/browser/services/State.ts +149 -0
  486. package/bundle/hkp-frontend/src/runtime/browser/services/Stopper.ts +29 -0
  487. package/bundle/hkp-frontend/src/runtime/browser/services/Switch.tsx +419 -0
  488. package/bundle/hkp-frontend/src/runtime/browser/services/SwitchUI.tsx +171 -0
  489. package/bundle/hkp-frontend/src/runtime/browser/services/TickRuleDelta.ts +101 -0
  490. package/bundle/hkp-frontend/src/runtime/browser/services/TickRuleDeltaUI.tsx +56 -0
  491. package/bundle/hkp-frontend/src/runtime/browser/services/Timeline.ts +709 -0
  492. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/TimelinePanel.tsx +79 -0
  493. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/TimelineRows.tsx +574 -0
  494. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/Transport.tsx +141 -0
  495. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/index.tsx +119 -0
  496. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/model.ts +425 -0
  497. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/parts.tsx +708 -0
  498. package/bundle/hkp-frontend/src/runtime/browser/services/Timer.ts +15 -0
  499. package/bundle/hkp-frontend/src/runtime/browser/services/TimerUI.tsx +213 -0
  500. package/bundle/hkp-frontend/src/runtime/browser/services/TracksUI.tsx +81 -0
  501. package/bundle/hkp-frontend/src/runtime/browser/services/TriggerPad.ts +108 -0
  502. package/bundle/hkp-frontend/src/runtime/browser/services/TriggerPadUI.tsx +160 -0
  503. package/bundle/hkp-frontend/src/runtime/browser/services/UuidGenerator.ts +74 -0
  504. package/bundle/hkp-frontend/src/runtime/browser/services/UuidGeneratorUI.tsx +59 -0
  505. package/bundle/hkp-frontend/src/runtime/browser/services/WaveformDisplay.tsx +104 -0
  506. package/bundle/hkp-frontend/src/runtime/browser/services/WebsocketClient.ts +114 -0
  507. package/bundle/hkp-frontend/src/runtime/browser/services/WebsocketClientUI.tsx +42 -0
  508. package/bundle/hkp-frontend/src/runtime/browser/services/WorkflowBoardBuilder.ts +499 -0
  509. package/bundle/hkp-frontend/src/runtime/browser/services/WorkflowBoardBuilderUI.tsx +521 -0
  510. package/bundle/hkp-frontend/src/runtime/browser/services/XYPad.ts +68 -0
  511. package/bundle/hkp-frontend/src/runtime/browser/services/XYPadUI.tsx +274 -0
  512. package/bundle/hkp-frontend/src/runtime/browser/services/audio/audioHelper.ts +36 -0
  513. package/bundle/hkp-frontend/src/runtime/browser/services/base/Batcher.ts +76 -0
  514. package/bundle/hkp-frontend/src/runtime/browser/services/base/Buffer.ts +142 -0
  515. package/bundle/hkp-frontend/src/runtime/browser/services/base/Filter.ts +125 -0
  516. package/bundle/hkp-frontend/src/runtime/browser/services/base/GroupBy.ts +101 -0
  517. package/bundle/hkp-frontend/src/runtime/browser/services/base/Map.ts +543 -0
  518. package/bundle/hkp-frontend/src/runtime/browser/services/base/MatchFilter.ts +49 -0
  519. package/bundle/hkp-frontend/src/runtime/browser/services/base/Monitor.ts +75 -0
  520. package/bundle/hkp-frontend/src/runtime/browser/services/base/Reduce.ts +74 -0
  521. package/bundle/hkp-frontend/src/runtime/browser/services/base/Timer.ts +342 -0
  522. package/bundle/hkp-frontend/src/runtime/browser/services/base/bundle.js +7375 -0
  523. package/bundle/hkp-frontend/src/runtime/browser/services/base/eval.ts +208 -0
  524. package/bundle/hkp-frontend/src/runtime/browser/services/base/expressionEval.ts +223 -0
  525. package/bundle/hkp-frontend/src/runtime/browser/services/base/helpers.ts +10 -0
  526. package/bundle/hkp-frontend/src/runtime/browser/services/base/index.ts +37 -0
  527. package/bundle/hkp-frontend/src/runtime/browser/services/camera/videoCapture.ts +78 -0
  528. package/bundle/hkp-frontend/src/runtime/browser/services/changes-modes.ts +9 -0
  529. package/bundle/hkp-frontend/src/runtime/browser/services/colorpalette.ts +26 -0
  530. package/bundle/hkp-frontend/src/runtime/browser/services/detect/DetectionPreview.tsx +76 -0
  531. package/bundle/hkp-frontend/src/runtime/browser/services/detect/mediapipe.ts +34 -0
  532. package/bundle/hkp-frontend/src/runtime/browser/services/detect/models/README.md +14 -0
  533. package/bundle/hkp-frontend/src/runtime/browser/services/detect/models/blaze_face_short_range.tflite +0 -0
  534. package/bundle/hkp-frontend/src/runtime/browser/services/detect-modes.ts +7 -0
  535. package/bundle/hkp-frontend/src/runtime/browser/services/encode-modes.ts +10 -0
  536. package/bundle/hkp-frontend/src/runtime/browser/services/helpers.ts +300 -0
  537. package/bundle/hkp-frontend/src/runtime/browser/services/http-client-methods.ts +10 -0
  538. package/bundle/hkp-frontend/src/runtime/browser/services/sql-database.ts +594 -0
  539. package/bundle/hkp-frontend/src/runtime/browser/services/sql-dump.ts +192 -0
  540. package/bundle/hkp-frontend/src/runtime/browser/services/sql-inspect.ts +130 -0
  541. package/bundle/hkp-frontend/src/runtime/browser/services/sql-inspector.css +155 -0
  542. package/bundle/hkp-frontend/src/runtime/browser/services/sql-modes.ts +27 -0
  543. package/bundle/hkp-frontend/src/runtime/browser/services/tests/TESTING_APPROACH.md +169 -0
  544. package/bundle/hkp-frontend/src/runtime/browser/services/tests/__snapshots__/service-ui.future-enhancements.test.tsx.snap +5 -0
  545. package/bundle/hkp-frontend/src/runtime/browser/services/tests/audio-input-permissions.test.ts +42 -0
  546. package/bundle/hkp-frontend/src/runtime/browser/services/tests/audiolizeLanes.test.ts +70 -0
  547. package/bundle/hkp-frontend/src/runtime/browser/services/tests/browser-scopes.test.ts +305 -0
  548. package/bundle/hkp-frontend/src/runtime/browser/services/tests/cache-service.test.ts +53 -0
  549. package/bundle/hkp-frontend/src/runtime/browser/services/tests/camera-video-capture.test.ts +24 -0
  550. package/bundle/hkp-frontend/src/runtime/browser/services/tests/changes-service.test.ts +133 -0
  551. package/bundle/hkp-frontend/src/runtime/browser/services/tests/crypto-secrets.test.ts +196 -0
  552. package/bundle/hkp-frontend/src/runtime/browser/services/tests/detect-service.test.ts +119 -0
  553. package/bundle/hkp-frontend/src/runtime/browser/services/tests/download.test.ts +100 -0
  554. package/bundle/hkp-frontend/src/runtime/browser/services/tests/expressionEval.test.ts +117 -0
  555. package/bundle/hkp-frontend/src/runtime/browser/services/tests/fetcher-panel.test.tsx +35 -0
  556. package/bundle/hkp-frontend/src/runtime/browser/services/tests/fetcher-service.test.ts +80 -0
  557. package/bundle/hkp-frontend/src/runtime/browser/services/tests/filter-service.test.ts +37 -0
  558. package/bundle/hkp-frontend/src/runtime/browser/services/tests/github-secrets.test.ts +108 -0
  559. package/bundle/hkp-frontend/src/runtime/browser/services/tests/group-by-board.test.ts +42 -0
  560. package/bundle/hkp-frontend/src/runtime/browser/services/tests/hold-service.test.ts +199 -0
  561. package/bundle/hkp-frontend/src/runtime/browser/services/tests/http-client-service.test.ts +474 -0
  562. package/bundle/hkp-frontend/src/runtime/browser/services/tests/http-uploader-token-injector.test.ts +152 -0
  563. package/bundle/hkp-frontend/src/runtime/browser/services/tests/iterator-gather-service.test.ts +277 -0
  564. package/bundle/hkp-frontend/src/runtime/browser/services/tests/map-service.test.ts +1047 -0
  565. package/bundle/hkp-frontend/src/runtime/browser/services/tests/map-ui.test.tsx +70 -0
  566. package/bundle/hkp-frontend/src/runtime/browser/services/tests/nested-rhythm-board.test.ts +311 -0
  567. package/bundle/hkp-frontend/src/runtime/browser/services/tests/night-groove-board.test.ts +290 -0
  568. package/bundle/hkp-frontend/src/runtime/browser/services/tests/pad-groove-board.test.ts +230 -0
  569. package/bundle/hkp-frontend/src/runtime/browser/services/tests/peer-host-discovery.test.ts +77 -0
  570. package/bundle/hkp-frontend/src/runtime/browser/services/tests/peer-socket-discovery.test.ts +69 -0
  571. package/bundle/hkp-frontend/src/runtime/browser/services/tests/pipeline-names.test.ts +63 -0
  572. package/bundle/hkp-frontend/src/runtime/browser/services/tests/secret-canary.test.ts +121 -0
  573. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-modules.contract.test.ts +229 -0
  574. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.advanced.test.tsx +670 -0
  575. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.future-enhancements.test.tsx +219 -0
  576. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.integration.test.tsx +432 -0
  577. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.smoke.test.tsx +140 -0
  578. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sound-service.test.ts +293 -0
  579. package/bundle/hkp-frontend/src/runtime/browser/services/tests/spread-service.test.ts +137 -0
  580. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-dump.test.ts +172 -0
  581. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-inspect.test.ts +163 -0
  582. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-inspector.test.tsx +121 -0
  583. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql.test.ts +702 -0
  584. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sub-service-in-block.test.tsx +84 -0
  585. package/bundle/hkp-frontend/src/runtime/browser/services/tests/switch-service.test.ts +254 -0
  586. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-board.test.ts +218 -0
  587. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-service.test.ts +1002 -0
  588. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-ui-model.test.ts +230 -0
  589. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-ui.test.tsx +371 -0
  590. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timer-service.test.ts +902 -0
  591. package/bundle/hkp-frontend/src/runtime/browser/services/tests/tracks-service.test.ts +275 -0
  592. package/bundle/hkp-frontend/src/runtime/browser/services/tests/tracks-ui.test.tsx +126 -0
  593. package/bundle/hkp-frontend/src/runtime/browser/services/tests/triggerpad-recorder-board.test.ts +100 -0
  594. package/bundle/hkp-frontend/src/runtime/browser/services/tests/uuid-generator-service.test.ts +214 -0
  595. package/bundle/hkp-frontend/src/runtime/browser/services/timeline-core.ts +410 -0
  596. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/DefaultWorkflowBoard.ts +90 -0
  597. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/RefinementSession.ts +121 -0
  598. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/SystemPromptCatalog.ts +245 -0
  599. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/catalog/browser-service-specs.json +110 -0
  600. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/catalog/runtime-capabilities.json +37 -0
  601. package/bundle/hkp-frontend/src/runtime/browser/tests/asset-service.test.ts +73 -0
  602. package/bundle/hkp-frontend/src/runtime/browser/tests/board-persistence.integration.test.tsx +391 -0
  603. package/bundle/hkp-frontend/src/runtime/browser/tests/browser-runtime.identity-binding.test.tsx +81 -0
  604. package/bundle/hkp-frontend/src/runtime/browser/tests/demo-boards.regression.test.tsx +386 -0
  605. package/bundle/hkp-frontend/src/runtime/browser/tests/failed-call-lifecycle.test.ts +56 -0
  606. package/bundle/hkp-frontend/src/runtime/browser/tests/http-client.integration.test.ts +146 -0
  607. package/bundle/hkp-frontend/src/runtime/browser/tests/nested-run.integration.test.ts +415 -0
  608. package/bundle/hkp-frontend/src/runtime/browser/tests/replay-next.test.ts +391 -0
  609. package/bundle/hkp-frontend/src/runtime/browser/tests/rerun.test.ts +71 -0
  610. package/bundle/hkp-frontend/src/runtime/browser/tests/run-no-input.test.ts +72 -0
  611. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-add.integration.test.tsx +256 -0
  612. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-operations.integration.test.tsx +310 -0
  613. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-processing.integration.test.ts +311 -0
  614. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-removal.integration.test.tsx +454 -0
  615. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-update.identity.integration.test.tsx +145 -0
  616. package/bundle/hkp-frontend/src/runtime/browser/tests/service-operations.integration.test.tsx +511 -0
  617. package/bundle/hkp-node/src/address.ts +72 -0
  618. package/bundle/hkp-node/src/assets.ts +582 -0
  619. package/bundle/hkp-node/src/auth.ts +369 -0
  620. package/bundle/hkp-node/src/callReport.ts +281 -0
  621. package/bundle/hkp-node/src/coordinator/auth.ts +85 -0
  622. package/bundle/hkp-node/src/coordinator/binaryFrame.ts +189 -0
  623. package/bundle/hkp-node/src/coordinator/boardStore.ts +0 -0
  624. package/bundle/hkp-node/src/coordinator/bridge.ts +242 -0
  625. package/bundle/hkp-node/src/coordinator/bridgeProtocol.ts +200 -0
  626. package/bundle/hkp-node/src/coordinator/coordinator.ts +594 -0
  627. package/bundle/hkp-node/src/coordinator/facadeAccess.ts +426 -0
  628. package/bundle/hkp-node/src/coordinator/fileBoardStore.ts +159 -0
  629. package/bundle/hkp-node/src/coordinator/frameLimits.ts +41 -0
  630. package/bundle/hkp-node/src/coordinator/index.ts +12 -0
  631. package/bundle/hkp-node/src/coordinator/join.ts +62 -0
  632. package/bundle/hkp-node/src/coordinator/logStore.ts +335 -0
  633. package/bundle/hkp-node/src/coordinator/members.ts +133 -0
  634. package/bundle/hkp-node/src/coordinator/mount.ts +124 -0
  635. package/bundle/hkp-node/src/coordinator/participantProtocol.ts +169 -0
  636. package/bundle/hkp-node/src/coordinator/participants.ts +666 -0
  637. package/bundle/hkp-node/src/coordinator/router.ts +416 -0
  638. package/bundle/hkp-node/src/coordinator/session.ts +1610 -0
  639. package/bundle/hkp-node/src/coordinator/types.ts +95 -0
  640. package/bundle/hkp-node/src/coordinatorLinks.ts +712 -0
  641. package/bundle/hkp-node/src/credentialedFetch.ts +122 -0
  642. package/bundle/hkp-node/src/egress.ts +344 -0
  643. package/bundle/hkp-node/src/expressionEval.ts +223 -0
  644. package/bundle/hkp-node/src/index.ts +470 -0
  645. package/bundle/hkp-node/src/instance.ts +172 -0
  646. package/bundle/hkp-node/src/mounts.ts +296 -0
  647. package/bundle/hkp-node/src/origins.ts +201 -0
  648. package/bundle/hkp-node/src/reset.ts +187 -0
  649. package/bundle/hkp-node/src/runtime.ts +1345 -0
  650. package/bundle/hkp-node/src/secrets.ts +292 -0
  651. package/bundle/hkp-node/src/server.ts +2120 -0
  652. package/bundle/hkp-node/src/services/asset.ts +150 -0
  653. package/bundle/hkp-node/src/services/claudeModels.ts +370 -0
  654. package/bundle/hkp-node/src/services/communication-dispatcher.ts +735 -0
  655. package/bundle/hkp-node/src/services/conversations.ts +914 -0
  656. package/bundle/hkp-node/src/services/database.ts +386 -0
  657. package/bundle/hkp-node/src/services/document-extract.ts +575 -0
  658. package/bundle/hkp-node/src/services/expression.ts +417 -0
  659. package/bundle/hkp-node/src/services/fileStore.ts +369 -0
  660. package/bundle/hkp-node/src/services/filesystem.ts +280 -0
  661. package/bundle/hkp-node/src/services/gather.ts +335 -0
  662. package/bundle/hkp-node/src/services/hold.ts +275 -0
  663. package/bundle/hkp-node/src/services/http-client.ts +525 -0
  664. package/bundle/hkp-node/src/services/http-server.ts +1222 -0
  665. package/bundle/hkp-node/src/services/imap-email.ts +627 -0
  666. package/bundle/hkp-node/src/services/injector.ts +135 -0
  667. package/bundle/hkp-node/src/services/iterator.ts +203 -0
  668. package/bundle/hkp-node/src/services/join.ts +226 -0
  669. package/bundle/hkp-node/src/services/map.ts +632 -0
  670. package/bundle/hkp-node/src/services/monitor.ts +128 -0
  671. package/bundle/hkp-node/src/services/nested-pipeline.ts +405 -0
  672. package/bundle/hkp-node/src/services/peer-server.ts +268 -0
  673. package/bundle/hkp-node/src/services/queue-store.ts +301 -0
  674. package/bundle/hkp-node/src/services/queue.ts +316 -0
  675. package/bundle/hkp-node/src/services/recordStore.ts +341 -0
  676. package/bundle/hkp-node/src/services/rss-parse.ts +281 -0
  677. package/bundle/hkp-node/src/services/rss.ts +392 -0
  678. package/bundle/hkp-node/src/services/smtp-email.ts +398 -0
  679. package/bundle/hkp-node/src/services/spread.ts +153 -0
  680. package/bundle/hkp-node/src/services/sql-dump.ts +192 -0
  681. package/bundle/hkp-node/src/services/sql.ts +429 -0
  682. package/bundle/hkp-node/src/services/stopper.ts +69 -0
  683. package/bundle/hkp-node/src/services/storage.ts +332 -0
  684. package/bundle/hkp-node/src/services/store.ts +609 -0
  685. package/bundle/hkp-node/src/services/stream.ts +367 -0
  686. package/bundle/hkp-node/src/services/sub-service.ts +600 -0
  687. package/bundle/hkp-node/src/services/telegram-listener.ts +263 -0
  688. package/bundle/hkp-node/src/services/telegram-sender.ts +136 -0
  689. package/bundle/hkp-node/src/services/text-generation.ts +1249 -0
  690. package/bundle/hkp-node/src/services/timer.ts +273 -0
  691. package/bundle/hkp-node/src/services/tracks.ts +381 -0
  692. package/bundle/hkp-node/src/services/websocket-reader.ts +364 -0
  693. package/bundle/hkp-node/src/types.ts +465 -0
  694. package/bundle/hkp-node/src/wsTickets.ts +77 -0
  695. package/bundle/hkp-node/src/yas.ts +95 -0
  696. package/bundle/hkp-python/src/hkp/__init__.py +1 -0
  697. package/bundle/hkp-python/src/hkp/__main__.py +241 -0
  698. package/bundle/hkp-python/src/hkp/address.py +56 -0
  699. package/bundle/hkp-python/src/hkp/assets.py +439 -0
  700. package/bundle/hkp-python/src/hkp/auth.py +252 -0
  701. package/bundle/hkp-python/src/hkp/binary_frame.py +100 -0
  702. package/bundle/hkp-python/src/hkp/call_report.py +201 -0
  703. package/bundle/hkp-python/src/hkp/coordinator_links.py +667 -0
  704. package/bundle/hkp-python/src/hkp/data.py +118 -0
  705. package/bundle/hkp-python/src/hkp/egress.py +310 -0
  706. package/bundle/hkp-python/src/hkp/mount.py +46 -0
  707. package/bundle/hkp-python/src/hkp/mounts.py +288 -0
  708. package/bundle/hkp-python/src/hkp/origins.py +169 -0
  709. package/bundle/hkp-python/src/hkp/runtime.py +1131 -0
  710. package/bundle/hkp-python/src/hkp/secrets.py +261 -0
  711. package/bundle/hkp-python/src/hkp/server.py +1714 -0
  712. package/bundle/hkp-python/src/hkp/services/__init__.py +0 -0
  713. package/bundle/hkp-python/src/hkp/services/asset.py +123 -0
  714. package/bundle/hkp-python/src/hkp/services/audio_encode.py +190 -0
  715. package/bundle/hkp-python/src/hkp/services/expression.py +942 -0
  716. package/bundle/hkp-python/src/hkp/services/gather.py +266 -0
  717. package/bundle/hkp-python/src/hkp/services/hold.py +246 -0
  718. package/bundle/hkp-python/src/hkp/services/http_client.py +444 -0
  719. package/bundle/hkp-python/src/hkp/services/http_server.py +790 -0
  720. package/bundle/hkp-python/src/hkp/services/iterator.py +141 -0
  721. package/bundle/hkp-python/src/hkp/services/join.py +173 -0
  722. package/bundle/hkp-python/src/hkp/services/map_service.py +452 -0
  723. package/bundle/hkp-python/src/hkp/services/monitor.py +99 -0
  724. package/bundle/hkp-python/src/hkp/services/nested_pipeline.py +278 -0
  725. package/bundle/hkp-python/src/hkp/services/skill_router.py +388 -0
  726. package/bundle/hkp-python/src/hkp/services/speech_to_text.py +186 -0
  727. package/bundle/hkp-python/src/hkp/services/spread.py +114 -0
  728. package/bundle/hkp-python/src/hkp/services/stopper.py +59 -0
  729. package/bundle/hkp-python/src/hkp/services/sub_service.py +417 -0
  730. package/bundle/hkp-python/src/hkp/services/text_generation.py +498 -0
  731. package/bundle/hkp-python/src/hkp/services/text_to_speech.py +237 -0
  732. package/bundle/hkp-python/src/hkp/services/timer.py +267 -0
  733. package/bundle/hkp-python/src/hkp/services/tracks.py +251 -0
  734. package/bundle/hkp-python/src/hkp/types.py +412 -0
  735. package/bundle/hkp-python/src/hkp/ws_tickets.py +54 -0
  736. package/bundle/hkp-python/src/hkp/yas.py +192 -0
  737. package/bundle/hkp-rt/lib/CMakeLists.txt +193 -0
  738. package/bundle/hkp-rt/lib/hkp-bundles/CMakeLists.txt +55 -0
  739. package/bundle/hkp-rt/lib/hkp-bundles/plugin_register.cpp +14 -0
  740. package/bundle/hkp-rt/lib/include/app.h +201 -0
  741. package/bundle/hkp-rt/lib/include/assets.h +239 -0
  742. package/bundle/hkp-rt/lib/include/auth.h +167 -0
  743. package/bundle/hkp-rt/lib/include/call_report.h +197 -0
  744. package/bundle/hkp-rt/lib/include/coordinator_links.h +127 -0
  745. package/bundle/hkp-rt/lib/include/discovery_hooks.h +29 -0
  746. package/bundle/hkp-rt/lib/include/egress.h +379 -0
  747. package/bundle/hkp-rt/lib/include/files.h +275 -0
  748. package/bundle/hkp-rt/lib/include/log_entry.h +131 -0
  749. package/bundle/hkp-rt/lib/include/mounts.h +139 -0
  750. package/bundle/hkp-rt/lib/include/origins.h +363 -0
  751. package/bundle/hkp-rt/lib/include/registry.h +119 -0
  752. package/bundle/hkp-rt/lib/include/secrets.h +414 -0
  753. package/bundle/hkp-rt/lib/include/server.h +122 -0
  754. package/bundle/hkp-rt/lib/include/service.h +190 -0
  755. package/bundle/hkp-rt/lib/include/slot_store.h +41 -0
  756. package/bundle/hkp-rt/lib/include/standalone_config.h +253 -0
  757. package/bundle/hkp-rt/lib/include/types/audio.h +3 -0
  758. package/bundle/hkp-rt/lib/include/types/data.h +152 -0
  759. package/bundle/hkp-rt/lib/include/types/message.h +56 -0
  760. package/bundle/hkp-rt/lib/include/types/models.h +154 -0
  761. package/bundle/hkp-rt/lib/include/types/owns_me.h +19 -0
  762. package/bundle/hkp-rt/lib/include/types/ringbuffer.h +86 -0
  763. package/bundle/hkp-rt/lib/include/types/types.h +33 -0
  764. package/bundle/hkp-rt/lib/include/types/validation.h +205 -0
  765. package/bundle/hkp-rt/lib/src/address.h +88 -0
  766. package/bundle/hkp-rt/lib/src/app.cpp +591 -0
  767. package/bundle/hkp-rt/lib/src/assets.cpp +686 -0
  768. package/bundle/hkp-rt/lib/src/binary_frame.h +154 -0
  769. package/bundle/hkp-rt/lib/src/common/expression.h +1481 -0
  770. package/bundle/hkp-rt/lib/src/common/inja.h +36 -0
  771. package/bundle/hkp-rt/lib/src/common/link_socket.cpp +437 -0
  772. package/bundle/hkp-rt/lib/src/common/link_socket.h +97 -0
  773. package/bundle/hkp-rt/lib/src/common/realtime_wakeup.h +120 -0
  774. package/bundle/hkp-rt/lib/src/common/stream_broadcast.h +250 -0
  775. package/bundle/hkp-rt/lib/src/common/string_util.h +31 -0
  776. package/bundle/hkp-rt/lib/src/common/websocket_client_session.cpp +217 -0
  777. package/bundle/hkp-rt/lib/src/common/websocket_client_session.h +37 -0
  778. package/bundle/hkp-rt/lib/src/common/websocket_config.h +119 -0
  779. package/bundle/hkp-rt/lib/src/common/websocket_protocol.h +32 -0
  780. package/bundle/hkp-rt/lib/src/common/websocket_server.cpp +82 -0
  781. package/bundle/hkp-rt/lib/src/common/websocket_server.h +57 -0
  782. package/bundle/hkp-rt/lib/src/common/websocket_server_listener.cpp +115 -0
  783. package/bundle/hkp-rt/lib/src/common/websocket_server_listener.h +35 -0
  784. package/bundle/hkp-rt/lib/src/common/websocket_server_session.cpp +172 -0
  785. package/bundle/hkp-rt/lib/src/common/websocket_server_session.h +53 -0
  786. package/bundle/hkp-rt/lib/src/common.h +13 -0
  787. package/bundle/hkp-rt/lib/src/coordinator_links.cpp +1142 -0
  788. package/bundle/hkp-rt/lib/src/discovery/discovery.cpp +707 -0
  789. package/bundle/hkp-rt/lib/src/discovery/discovery.h +89 -0
  790. package/bundle/hkp-rt/lib/src/http/auth.cpp +569 -0
  791. package/bundle/hkp-rt/lib/src/http/front_door.cpp +518 -0
  792. package/bundle/hkp-rt/lib/src/http/front_door.h +131 -0
  793. package/bundle/hkp-rt/lib/src/http/server.cpp +1539 -0
  794. package/bundle/hkp-rt/lib/src/http/ws_tickets.h +125 -0
  795. package/bundle/hkp-rt/lib/src/mount.h +63 -0
  796. package/bundle/hkp-rt/lib/src/process_context.h +335 -0
  797. package/bundle/hkp-rt/lib/src/process_depth.h +20 -0
  798. package/bundle/hkp-rt/lib/src/registry.cpp +233 -0
  799. package/bundle/hkp-rt/lib/src/runtime.cpp +986 -0
  800. package/bundle/hkp-rt/lib/src/runtime.h +225 -0
  801. package/bundle/hkp-rt/lib/src/runtime_host.h +180 -0
  802. package/bundle/hkp-rt/lib/src/service.cpp +315 -0
  803. package/bundle/hkp-rt/lib/src/services/asset.h +185 -0
  804. package/bundle/hkp-rt/lib/src/services/audio_encode.cpp +372 -0
  805. package/bundle/hkp-rt/lib/src/services/audio_encode.h +97 -0
  806. package/bundle/hkp-rt/lib/src/services/cache.h +362 -0
  807. package/bundle/hkp-rt/lib/src/services/cache_subservices.h +463 -0
  808. package/bundle/hkp-rt/lib/src/services/core_audio.cpp +384 -0
  809. package/bundle/hkp-rt/lib/src/services/core_audio.h +22 -0
  810. package/bundle/hkp-rt/lib/src/services/core_input.h +337 -0
  811. package/bundle/hkp-rt/lib/src/services/core_output.h +370 -0
  812. package/bundle/hkp-rt/lib/src/services/ffmpeg/detail.cpp +749 -0
  813. package/bundle/hkp-rt/lib/src/services/ffmpeg/detail.h +29 -0
  814. package/bundle/hkp-rt/lib/src/services/ffmpeg/ffmpeg.cpp +193 -0
  815. package/bundle/hkp-rt/lib/src/services/ffmpeg/ffmpeg.h +40 -0
  816. package/bundle/hkp-rt/lib/src/services/ffmpeg/types.h +120 -0
  817. package/bundle/hkp-rt/lib/src/services/fft_service.h +190 -0
  818. package/bundle/hkp-rt/lib/src/services/filesystem.h +309 -0
  819. package/bundle/hkp-rt/lib/src/services/filter.h +208 -0
  820. package/bundle/hkp-rt/lib/src/services/gather.h +272 -0
  821. package/bundle/hkp-rt/lib/src/services/hold.h +304 -0
  822. package/bundle/hkp-rt/lib/src/services/http_client.cpp +347 -0
  823. package/bundle/hkp-rt/lib/src/services/http_client.h +67 -0
  824. package/bundle/hkp-rt/lib/src/services/http_client_impl.h +45 -0
  825. package/bundle/hkp-rt/lib/src/services/http_client_template_examples.md +202 -0
  826. package/bundle/hkp-rt/lib/src/services/http_server/http_listener.cpp +130 -0
  827. package/bundle/hkp-rt/lib/src/services/http_server/http_listener.h +33 -0
  828. package/bundle/hkp-rt/lib/src/services/http_server/http_server.cpp +351 -0
  829. package/bundle/hkp-rt/lib/src/services/http_server/http_server.h +79 -0
  830. package/bundle/hkp-rt/lib/src/services/http_server/http_server_impl.cpp +230 -0
  831. package/bundle/hkp-rt/lib/src/services/http_server/http_server_impl.h +64 -0
  832. package/bundle/hkp-rt/lib/src/services/http_server/http_server_subservices.cpp +950 -0
  833. package/bundle/hkp-rt/lib/src/services/http_server/http_server_subservices.h +253 -0
  834. package/bundle/hkp-rt/lib/src/services/http_server/http_session.cpp +495 -0
  835. package/bundle/hkp-rt/lib/src/services/http_server/http_session.h +169 -0
  836. package/bundle/hkp-rt/lib/src/services/http_server/http_stream_listener.cpp +270 -0
  837. package/bundle/hkp-rt/lib/src/services/http_server/http_stream_listener.h +104 -0
  838. package/bundle/hkp-rt/lib/src/services/http_server/request_decode.h +164 -0
  839. package/bundle/hkp-rt/lib/src/services/if_service.h +210 -0
  840. package/bundle/hkp-rt/lib/src/services/ifft_service.h +198 -0
  841. package/bundle/hkp-rt/lib/src/services/injector.h +162 -0
  842. package/bundle/hkp-rt/lib/src/services/iterator.h +201 -0
  843. package/bundle/hkp-rt/lib/src/services/map.h +641 -0
  844. package/bundle/hkp-rt/lib/src/services/monitor.h +161 -0
  845. package/bundle/hkp-rt/lib/src/services/mp3_frames.h +119 -0
  846. package/bundle/hkp-rt/lib/src/services/mp4_to_wav.cpp +281 -0
  847. package/bundle/hkp-rt/lib/src/services/mp4_to_wav.h +263 -0
  848. package/bundle/hkp-rt/lib/src/services/peer_server/peer_registry.cpp +88 -0
  849. package/bundle/hkp-rt/lib/src/services/peer_server/peer_registry.h +43 -0
  850. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server.h +163 -0
  851. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_listener.cpp +133 -0
  852. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_listener.h +46 -0
  853. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_session.cpp +165 -0
  854. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_session.h +44 -0
  855. package/bundle/hkp-rt/lib/src/services/peer_server/peer_ws_session.cpp +184 -0
  856. package/bundle/hkp-rt/lib/src/services/peer_server/peer_ws_session.h +55 -0
  857. package/bundle/hkp-rt/lib/src/services/receiver_session.h +172 -0
  858. package/bundle/hkp-rt/lib/src/services/root_certificates.h +3959 -0
  859. package/bundle/hkp-rt/lib/src/services/sha256_openssl.h +49 -0
  860. package/bundle/hkp-rt/lib/src/services/speech_http.h +306 -0
  861. package/bundle/hkp-rt/lib/src/services/speech_to_text.cpp +595 -0
  862. package/bundle/hkp-rt/lib/src/services/speech_to_text.h +69 -0
  863. package/bundle/hkp-rt/lib/src/services/static.cpp +45 -0
  864. package/bundle/hkp-rt/lib/src/services/static.h +41 -0
  865. package/bundle/hkp-rt/lib/src/services/stopper.h +72 -0
  866. package/bundle/hkp-rt/lib/src/services/sub_service.h +286 -0
  867. package/bundle/hkp-rt/lib/src/services/text_generation.cpp +1132 -0
  868. package/bundle/hkp-rt/lib/src/services/text_generation.h +71 -0
  869. package/bundle/hkp-rt/lib/src/services/text_to_speech.cpp +853 -0
  870. package/bundle/hkp-rt/lib/src/services/text_to_speech.h +97 -0
  871. package/bundle/hkp-rt/lib/src/services/timer.h +300 -0
  872. package/bundle/hkp-rt/lib/src/services/tracks.h +397 -0
  873. package/bundle/hkp-rt/lib/src/services/tts_inflect.cpp +149 -0
  874. package/bundle/hkp-rt/lib/src/services/tts_inflect.h +82 -0
  875. package/bundle/hkp-rt/lib/src/services/wav_reader.h +213 -0
  876. package/bundle/hkp-rt/lib/src/services/websocket_client_service.h +182 -0
  877. package/bundle/hkp-rt/lib/src/services/websocket_reader.h +148 -0
  878. package/bundle/hkp-rt/lib/src/services/websocket_server_service.h +196 -0
  879. package/bundle/hkp-rt/lib/src/services/websocket_writer.cpp +641 -0
  880. package/bundle/hkp-rt/lib/src/services/websocket_writer.h +117 -0
  881. package/bundle/hkp-rt/lib/src/sub_runtime.cpp +234 -0
  882. package/bundle/hkp-rt/lib/src/sub_runtime.h +160 -0
  883. package/bundle/hkp-rt/lib/src/types/data.cpp +237 -0
  884. package/bundle/hkp-rt/lib/src/types/message.cpp +148 -0
  885. package/bundle/hkp-rt/lib/src/types/models.cpp +83 -0
  886. package/bundle/hkp-rt/lib/src/types/ringbuffer.cpp +336 -0
  887. package/bundle/hkp-rt/lib/src/uuid.h +12 -0
  888. package/bundle/readymade-mcp-commits.json +5 -0
  889. package/dist/cli.d.ts +3 -0
  890. package/dist/cli.d.ts.map +1 -0
  891. package/dist/cli.js +79 -0
  892. package/dist/git.d.ts +8 -0
  893. package/dist/git.d.ts.map +1 -0
  894. package/dist/git.js +53 -0
  895. package/dist/http.d.ts +17 -0
  896. package/dist/http.d.ts.map +1 -0
  897. package/dist/http.js +130 -0
  898. package/dist/index.d.ts +7 -0
  899. package/dist/index.d.ts.map +1 -0
  900. package/dist/index.js +6 -0
  901. package/dist/repository.d.ts +49 -0
  902. package/dist/repository.d.ts.map +1 -0
  903. package/dist/repository.js +452 -0
  904. package/dist/schemas.d.ts +156 -0
  905. package/dist/schemas.d.ts.map +1 -0
  906. package/dist/schemas.js +43 -0
  907. package/dist/server.d.ts +4 -0
  908. package/dist/server.d.ts.map +1 -0
  909. package/dist/server.js +83 -0
  910. package/dist/types.d.ts +63 -0
  911. package/dist/types.d.ts.map +1 -0
  912. package/dist/types.js +20 -0
  913. package/dist/validation.d.ts +9 -0
  914. package/dist/validation.d.ts.map +1 -0
  915. package/dist/validation.js +101 -0
  916. package/package.json +52 -4
@@ -0,0 +1,1481 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * Expression evaluation for services that let a board author write small
5
+ * dynamic terms — a Map template's `key=` rows, for example.
6
+ *
7
+ * An expression is a single JavaScript-style expression evaluated with the
8
+ * incoming data bound to `params` and the helper functions below in scope. The
9
+ * browser and Node runtimes evaluate the same sources, so the dialect and the
10
+ * helper set are kept aligned: a template authored in the shared Map UI behaves
11
+ * the same whichever runtime hosts the service. Helpers that need a browser
12
+ * (DOM, vault, AudioContext) have no counterpart here.
13
+ *
14
+ * Supported: literals (number, string, true/false/null), array literals,
15
+ * identifiers, member and index access, calls into the builtin table, unary
16
+ * `!`/`-`/`+`, `* / %`, `+ -`, `< <= > >=`, `== != === !==`, `&& ||` and the
17
+ * ternary operator. There are no assignments, no statements and no lambdas —
18
+ * `find`/`filter` take their predicate as an expression string with the element
19
+ * bound to `item` (and its position to `index`).
20
+ *
21
+ * Expression e = Expression::parse("round(params.value * 2)");
22
+ * json result = e.evaluate(input); // throws EvaluationError on failure
23
+ *
24
+ * A member of nothing is nothing: `params.a.b` with no `a` is null, as in the
25
+ * browser, Node and Python runtimes. Whoever wants to know which reads came up
26
+ * empty passes an `OnMissing`.
27
+ */
28
+
29
+ #include <algorithm>
30
+ #include <array>
31
+ #include <cctype>
32
+ #include <chrono>
33
+ #include <cmath>
34
+ #include <ctime>
35
+ #include <functional>
36
+ #include <iomanip>
37
+ #include <iostream>
38
+ #include <limits>
39
+ #include <map>
40
+ #include <memory>
41
+ #include <optional>
42
+ #include <random>
43
+ #include <sstream>
44
+ #include <stdexcept>
45
+ #include <string>
46
+ #include <utility>
47
+ #include <vector>
48
+
49
+ #include <nlohmann/json.hpp>
50
+
51
+ #include "../uuid.h"
52
+
53
+ namespace hkp {
54
+ namespace expression {
55
+
56
+ using json = nlohmann::json;
57
+
58
+ class ParseError : public std::runtime_error
59
+ {
60
+ public:
61
+ explicit ParseError(const std::string& what) : std::runtime_error(what) {}
62
+ };
63
+
64
+ class EvaluationError : public std::runtime_error
65
+ {
66
+ public:
67
+ explicit EvaluationError(const std::string& what) : std::runtime_error(what) {}
68
+ };
69
+
70
+ // Variables visible to an expression. Always holds "params"; find/filter add
71
+ // "item" and "index" while evaluating their predicate.
72
+ using Scope = std::map<std::string, json>;
73
+
74
+ // Told the path of a read that found nothing — `params.titel` — once per chain:
75
+ // in `params.a.b.c` with no `a`, only `params.a` is reported.
76
+ using OnMissing = std::function<void(const std::string&)>;
77
+
78
+ // ── Value helpers ────────────────────────────────────────────────────────────
79
+
80
+ inline bool isTruthy(const json& value)
81
+ {
82
+ if (value.is_null())
83
+ {
84
+ return false;
85
+ }
86
+ if (value.is_boolean())
87
+ {
88
+ return value.get<bool>();
89
+ }
90
+ if (value.is_number())
91
+ {
92
+ return value.get<double>() != 0.0;
93
+ }
94
+ if (value.is_string())
95
+ {
96
+ return !value.get<std::string>().empty();
97
+ }
98
+ return true; // objects and arrays are truthy, empty or not
99
+ }
100
+
101
+ inline double toNumber(const json& value)
102
+ {
103
+ if (value.is_number())
104
+ {
105
+ return value.get<double>();
106
+ }
107
+ if (value.is_boolean())
108
+ {
109
+ return value.get<bool>() ? 1.0 : 0.0;
110
+ }
111
+ if (value.is_string())
112
+ {
113
+ try
114
+ {
115
+ size_t consumed = 0;
116
+ const auto& text = value.get_ref<const std::string&>();
117
+ double parsed = std::stod(text, &consumed);
118
+ while (consumed < text.size() && std::isspace(static_cast<unsigned char>(text[consumed])))
119
+ {
120
+ ++consumed;
121
+ }
122
+ return consumed == text.size() ? parsed : std::nan("");
123
+ }
124
+ catch (const std::exception&)
125
+ {
126
+ return std::nan("");
127
+ }
128
+ }
129
+ if (value.is_null())
130
+ {
131
+ return 0.0;
132
+ }
133
+ return std::nan("");
134
+ }
135
+
136
+ // Numbers are rendered the way JSON.stringify would: integral values without a
137
+ // decimal tail, so string concatenation does not turn 42 into "42.0".
138
+ inline std::string toText(const json& value)
139
+ {
140
+ if (value.is_string())
141
+ {
142
+ return value.get<std::string>();
143
+ }
144
+ if (value.is_null())
145
+ {
146
+ return "null";
147
+ }
148
+ if (value.is_boolean())
149
+ {
150
+ return value.get<bool>() ? "true" : "false";
151
+ }
152
+ if (value.is_number_integer())
153
+ {
154
+ return std::to_string(value.get<int64_t>());
155
+ }
156
+ if (value.is_number_float())
157
+ {
158
+ double number = value.get<double>();
159
+ if (std::isnan(number) || std::isinf(number))
160
+ {
161
+ return std::isnan(number) ? "NaN" : (number > 0 ? "Infinity" : "-Infinity");
162
+ }
163
+ if (number == std::floor(number) && std::fabs(number) < 1e15)
164
+ {
165
+ return std::to_string(static_cast<int64_t>(number));
166
+ }
167
+ std::ostringstream out;
168
+ out << std::setprecision(15) << number;
169
+ return out.str();
170
+ }
171
+ return value.dump();
172
+ }
173
+
174
+ // A double result that is integral is stored as an integer, so downstream
175
+ // consumers see 4 rather than 4.0. NaN has no JSON representation and becomes
176
+ // null, mirroring what JSON.stringify does with it in the other runtimes.
177
+ inline json fromNumber(double number)
178
+ {
179
+ if (std::isnan(number) || std::isinf(number))
180
+ {
181
+ return json();
182
+ }
183
+ if (number == std::floor(number) && std::fabs(number) < 9.2e18)
184
+ {
185
+ return json(static_cast<int64_t>(number));
186
+ }
187
+ return json(number);
188
+ }
189
+
190
+ // ── Date helpers (moment-style token subset shared with the other runtimes) ──
191
+
192
+ inline const std::vector<std::string>& monthNames()
193
+ {
194
+ static const std::vector<std::string> names = {
195
+ "January", "February", "March", "April", "May", "June",
196
+ "July", "August", "September", "October", "November", "December"};
197
+ return names;
198
+ }
199
+
200
+ inline const std::vector<std::string>& weekdayNames()
201
+ {
202
+ static const std::vector<std::string> names = {
203
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
204
+ return names;
205
+ }
206
+
207
+ struct FormatToken
208
+ {
209
+ bool literal = false;
210
+ std::string text; // token name, or the literal text
211
+ };
212
+
213
+ inline std::vector<FormatToken> tokenizeFormat(const std::string& format)
214
+ {
215
+ static const std::vector<std::string> tokens = {
216
+ "YYYY", "YY", "MMMM", "MMM", "MM", "M", "DD", "D", "dddd", "ddd",
217
+ "HH", "H", "hh", "h", "mm", "m", "ss", "s", "A", "a"};
218
+
219
+ std::vector<FormatToken> result;
220
+ size_t i = 0;
221
+ std::string literal;
222
+
223
+ auto flushLiteral = [&]() {
224
+ if (!literal.empty())
225
+ {
226
+ result.push_back(FormatToken{true, literal});
227
+ literal.clear();
228
+ }
229
+ };
230
+
231
+ while (i < format.size())
232
+ {
233
+ if (format[i] == '[')
234
+ {
235
+ const size_t end = format.find(']', i);
236
+ if (end != std::string::npos)
237
+ {
238
+ literal += format.substr(i + 1, end - i - 1);
239
+ i = end + 1;
240
+ continue;
241
+ }
242
+ }
243
+
244
+ bool matched = false;
245
+ for (const auto& token : tokens)
246
+ {
247
+ if (format.compare(i, token.size(), token) == 0)
248
+ {
249
+ flushLiteral();
250
+ result.push_back(FormatToken{false, token});
251
+ i += token.size();
252
+ matched = true;
253
+ break;
254
+ }
255
+ }
256
+
257
+ if (!matched)
258
+ {
259
+ literal += format[i];
260
+ ++i;
261
+ }
262
+ }
263
+
264
+ flushLiteral();
265
+ return result;
266
+ }
267
+
268
+ inline std::string pad(int value, int width = 2)
269
+ {
270
+ std::ostringstream out;
271
+ out << std::setw(width) << std::setfill('0') << value;
272
+ return out.str();
273
+ }
274
+
275
+ inline std::string formatTime(const std::tm& tm, const std::string& format)
276
+ {
277
+ std::string result;
278
+ const int hours12 = (tm.tm_hour % 12 == 0) ? 12 : tm.tm_hour % 12;
279
+
280
+ for (const auto& token : tokenizeFormat(format))
281
+ {
282
+ if (token.literal)
283
+ {
284
+ result += token.text;
285
+ continue;
286
+ }
287
+
288
+ const std::string& t = token.text;
289
+ if (t == "YYYY") { result += std::to_string(tm.tm_year + 1900); }
290
+ else if (t == "YY") { result += pad((tm.tm_year + 1900) % 100); }
291
+ else if (t == "MMMM") { result += monthNames()[tm.tm_mon]; }
292
+ else if (t == "MMM") { result += monthNames()[tm.tm_mon].substr(0, 3); }
293
+ else if (t == "MM") { result += pad(tm.tm_mon + 1); }
294
+ else if (t == "M") { result += std::to_string(tm.tm_mon + 1); }
295
+ else if (t == "DD") { result += pad(tm.tm_mday); }
296
+ else if (t == "D") { result += std::to_string(tm.tm_mday); }
297
+ else if (t == "dddd") { result += weekdayNames()[tm.tm_wday % 7]; }
298
+ else if (t == "ddd") { result += weekdayNames()[tm.tm_wday % 7].substr(0, 3); }
299
+ else if (t == "HH") { result += pad(tm.tm_hour); }
300
+ else if (t == "H") { result += std::to_string(tm.tm_hour); }
301
+ else if (t == "hh") { result += pad(hours12); }
302
+ else if (t == "h") { result += std::to_string(hours12); }
303
+ else if (t == "mm") { result += pad(tm.tm_min); }
304
+ else if (t == "m") { result += std::to_string(tm.tm_min); }
305
+ else if (t == "ss") { result += pad(tm.tm_sec); }
306
+ else if (t == "s") { result += std::to_string(tm.tm_sec); }
307
+ else if (t == "A") { result += tm.tm_hour < 12 ? "AM" : "PM"; }
308
+ else if (t == "a") { result += tm.tm_hour < 12 ? "am" : "pm"; }
309
+ }
310
+
311
+ return result;
312
+ }
313
+
314
+ // Reads a date written in the token subset above. Returns false when the text
315
+ // does not line up with the format, leaving the caller to fall back.
316
+ inline bool parseTime(const std::string& text, const std::string& format, std::tm& out)
317
+ {
318
+ std::tm tm{};
319
+ tm.tm_year = 70;
320
+ tm.tm_mday = 1;
321
+ tm.tm_isdst = -1;
322
+ bool pm = false;
323
+ bool hours12 = false;
324
+
325
+ size_t pos = 0;
326
+ const std::string trimmedText = [&]() {
327
+ size_t begin = text.find_first_not_of(" \t");
328
+ size_t end = text.find_last_not_of(" \t");
329
+ return begin == std::string::npos ? std::string() : text.substr(begin, end - begin + 1);
330
+ }();
331
+
332
+ auto readNumber = [&](int maxDigits) -> int {
333
+ size_t start = pos;
334
+ while (pos < trimmedText.size() && pos - start < static_cast<size_t>(maxDigits) &&
335
+ std::isdigit(static_cast<unsigned char>(trimmedText[pos])))
336
+ {
337
+ ++pos;
338
+ }
339
+ if (pos == start)
340
+ {
341
+ return -1;
342
+ }
343
+ return std::stoi(trimmedText.substr(start, pos - start));
344
+ };
345
+
346
+ auto readName = [&]() -> std::string {
347
+ size_t start = pos;
348
+ while (pos < trimmedText.size() && std::isalpha(static_cast<unsigned char>(trimmedText[pos])))
349
+ {
350
+ ++pos;
351
+ }
352
+ return trimmedText.substr(start, pos - start);
353
+ };
354
+
355
+ for (const auto& token : tokenizeFormat(format))
356
+ {
357
+ if (token.literal)
358
+ {
359
+ if (trimmedText.compare(pos, token.text.size(), token.text) != 0)
360
+ {
361
+ return false;
362
+ }
363
+ pos += token.text.size();
364
+ continue;
365
+ }
366
+
367
+ const std::string& t = token.text;
368
+ if (t == "YYYY" || t == "YY")
369
+ {
370
+ const int value = readNumber(t.size() == 4 ? 4 : 2);
371
+ if (value < 0) { return false; }
372
+ tm.tm_year = (t == "YYYY" ? value : 2000 + value) - 1900;
373
+ }
374
+ else if (t == "MMMM" || t == "MMM")
375
+ {
376
+ const std::string name = readName();
377
+ if (name.empty()) { return false; }
378
+ const auto& months = monthNames();
379
+ auto it = std::find_if(months.begin(), months.end(), [&](const std::string& month) {
380
+ return month.size() >= name.size() &&
381
+ std::equal(name.begin(), name.end(), month.begin(), [](char a, char b) {
382
+ return std::tolower(static_cast<unsigned char>(a)) ==
383
+ std::tolower(static_cast<unsigned char>(b));
384
+ });
385
+ });
386
+ if (it == months.end()) { return false; }
387
+ tm.tm_mon = static_cast<int>(std::distance(months.begin(), it));
388
+ }
389
+ else if (t == "dddd" || t == "ddd")
390
+ {
391
+ if (readName().empty()) { return false; } // weekday carries no information
392
+ }
393
+ else if (t == "A" || t == "a")
394
+ {
395
+ const std::string name = readName();
396
+ if (name.size() != 2) { return false; }
397
+ pm = std::tolower(static_cast<unsigned char>(name[0])) == 'p';
398
+ }
399
+ else
400
+ {
401
+ const int value = readNumber(2);
402
+ if (value < 0) { return false; }
403
+ if (t == "MM" || t == "M") { tm.tm_mon = value - 1; }
404
+ else if (t == "DD" || t == "D") { tm.tm_mday = value; }
405
+ else if (t == "HH" || t == "H") { tm.tm_hour = value; }
406
+ else if (t == "hh" || t == "h") { tm.tm_hour = value; hours12 = true; }
407
+ else if (t == "mm" || t == "m") { tm.tm_min = value; }
408
+ else if (t == "ss" || t == "s") { tm.tm_sec = value; }
409
+ }
410
+ }
411
+
412
+ if (pos != trimmedText.size())
413
+ {
414
+ return false;
415
+ }
416
+
417
+ if (hours12)
418
+ {
419
+ tm.tm_hour = (tm.tm_hour % 12) + (pm ? 12 : 0);
420
+ }
421
+
422
+ std::tm normalized = tm;
423
+ const std::time_t stamp = std::mktime(&normalized);
424
+ if (stamp == static_cast<std::time_t>(-1))
425
+ {
426
+ return false;
427
+ }
428
+
429
+ out = normalized;
430
+ return true;
431
+ }
432
+
433
+ // Milliseconds since the epoch for anything the other runtimes accept as a
434
+ // timestamp: a number, or an ISO-8601 string.
435
+ inline bool toEpochMillis(const json& value, int64_t& out)
436
+ {
437
+ if (value.is_number())
438
+ {
439
+ out = static_cast<int64_t>(value.get<double>());
440
+ return true;
441
+ }
442
+
443
+ if (!value.is_string())
444
+ {
445
+ return false;
446
+ }
447
+
448
+ const std::string text = value.get<std::string>();
449
+ std::tm tm{};
450
+ tm.tm_isdst = -1;
451
+ std::istringstream in(text);
452
+ in >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
453
+ if (in.fail())
454
+ {
455
+ std::istringstream dateOnly(text);
456
+ dateOnly >> std::get_time(&tm, "%Y-%m-%d");
457
+ if (dateOnly.fail())
458
+ {
459
+ return false;
460
+ }
461
+ }
462
+
463
+ // Trailing "Z" or "+00:00" means UTC; anything else is read as local time,
464
+ // which is what a bare "2026-07-30T12:00:00" means everywhere else too.
465
+ const bool utc = text.find('Z') != std::string::npos ||
466
+ text.find("+00:00") != std::string::npos;
467
+ #ifdef _WIN32
468
+ const std::time_t stamp = utc ? _mkgmtime(&tm) : std::mktime(&tm);
469
+ #else
470
+ const std::time_t stamp = utc ? timegm(&tm) : std::mktime(&tm);
471
+ #endif
472
+ if (stamp == static_cast<std::time_t>(-1))
473
+ {
474
+ return false;
475
+ }
476
+
477
+ out = static_cast<int64_t>(stamp) * 1000;
478
+ return true;
479
+ }
480
+
481
+ inline int64_t nowMillis()
482
+ {
483
+ return std::chrono::duration_cast<std::chrono::milliseconds>(
484
+ std::chrono::system_clock::now().time_since_epoch())
485
+ .count();
486
+ }
487
+
488
+ // ── AST ──────────────────────────────────────────────────────────────────────
489
+
490
+ class Expression;
491
+
492
+ namespace detail {
493
+
494
+ struct Node;
495
+ using NodePtr = std::shared_ptr<const Node>;
496
+
497
+ using Builtin = std::function<json(const std::vector<json>&)>;
498
+ const std::map<std::string, Builtin>& builtins();
499
+
500
+ struct Node
501
+ {
502
+ enum class Kind
503
+ {
504
+ Literal,
505
+ Identifier,
506
+ Member, // object.property / object[property]
507
+ Call,
508
+ Unary,
509
+ Binary,
510
+ Logical,
511
+ Conditional,
512
+ ArrayLiteral
513
+ };
514
+
515
+ Kind kind = Kind::Literal;
516
+ json value; // Literal
517
+ std::string name; // Identifier, Member property, Unary/Binary/Logical operator
518
+ bool computed = false; // Member: true for object[expr]
519
+ NodePtr left; // Member object, Unary/Binary operand, Conditional test, Call callee
520
+ NodePtr right; // Binary right, Member computed property, Conditional consequent
521
+ NodePtr third; // Conditional alternate
522
+ std::vector<NodePtr> items; // Call arguments, array literal items
523
+ };
524
+
525
+ // Flattens an identifier/member chain into a dotted name, so `uuid.v4` can be
526
+ // looked up in the builtin table. Returns false for anything else.
527
+ inline bool calleeName(const NodePtr& node, std::string& out)
528
+ {
529
+ if (!node)
530
+ {
531
+ return false;
532
+ }
533
+ if (node->kind == Node::Kind::Identifier)
534
+ {
535
+ out = node->name;
536
+ return true;
537
+ }
538
+ if (node->kind == Node::Kind::Member && !node->computed)
539
+ {
540
+ std::string prefix;
541
+ if (!calleeName(node->left, prefix))
542
+ {
543
+ return false;
544
+ }
545
+ out = prefix + "." + node->name;
546
+ return true;
547
+ }
548
+ return false;
549
+ }
550
+
551
+ class Parser
552
+ {
553
+ public:
554
+ explicit Parser(const std::string& source) : m_source(source) {}
555
+
556
+ NodePtr parse()
557
+ {
558
+ skipSpace();
559
+ NodePtr node = parseExpression();
560
+ skipSpace();
561
+ if (m_pos != m_source.size())
562
+ {
563
+ throw ParseError("unexpected '" + m_source.substr(m_pos) + "'");
564
+ }
565
+ return node;
566
+ }
567
+
568
+ private:
569
+ NodePtr parseExpression() { return parseConditional(); }
570
+
571
+ NodePtr parseConditional()
572
+ {
573
+ NodePtr test = parseBinary(0);
574
+ skipSpace();
575
+ if (peek() != '?')
576
+ {
577
+ return test;
578
+ }
579
+ ++m_pos;
580
+ NodePtr consequent = parseExpression();
581
+ skipSpace();
582
+ expect(':');
583
+ NodePtr alternate = parseExpression();
584
+
585
+ auto node = std::make_shared<Node>();
586
+ node->kind = Node::Kind::Conditional;
587
+ node->left = test;
588
+ node->right = consequent;
589
+ node->third = alternate;
590
+ return node;
591
+ }
592
+
593
+ // Precedence-climbing over the binary operators, lowest level first.
594
+ NodePtr parseBinary(int level)
595
+ {
596
+ static const std::vector<std::vector<std::string>> levels = {
597
+ {"||"},
598
+ {"&&"},
599
+ {"===", "!==", "==", "!="},
600
+ {"<=", ">=", "<", ">"},
601
+ {"+", "-"},
602
+ {"*", "/", "%"}};
603
+
604
+ if (level >= static_cast<int>(levels.size()))
605
+ {
606
+ return parseUnary();
607
+ }
608
+
609
+ NodePtr left = parseBinary(level + 1);
610
+ while (true)
611
+ {
612
+ skipSpace();
613
+ std::string matched;
614
+ for (const auto& op : levels[level])
615
+ {
616
+ if (m_source.compare(m_pos, op.size(), op) == 0)
617
+ {
618
+ // "&&" must not be read as "&", and "=>"/"=" are not operators here.
619
+ matched = op;
620
+ break;
621
+ }
622
+ }
623
+ if (matched.empty())
624
+ {
625
+ return left;
626
+ }
627
+
628
+ m_pos += matched.size();
629
+ NodePtr right = parseBinary(level + 1);
630
+
631
+ auto node = std::make_shared<Node>();
632
+ node->kind = (matched == "&&" || matched == "||") ? Node::Kind::Logical
633
+ : Node::Kind::Binary;
634
+ node->name = matched;
635
+ node->left = left;
636
+ node->right = right;
637
+ left = node;
638
+ }
639
+ }
640
+
641
+ NodePtr parseUnary()
642
+ {
643
+ skipSpace();
644
+ const char c = peek();
645
+ if (c == '!' || c == '-' || c == '+')
646
+ {
647
+ if (c == '!' && m_source.compare(m_pos, 2, "!=") == 0)
648
+ {
649
+ throw ParseError("unexpected '!='");
650
+ }
651
+ ++m_pos;
652
+ auto node = std::make_shared<Node>();
653
+ node->kind = Node::Kind::Unary;
654
+ node->name = std::string(1, c);
655
+ node->left = parseUnary();
656
+ return node;
657
+ }
658
+ return parsePostfix();
659
+ }
660
+
661
+ NodePtr parsePostfix()
662
+ {
663
+ NodePtr node = parsePrimary();
664
+ while (true)
665
+ {
666
+ skipSpace();
667
+ const char c = peek();
668
+ if (c == '.')
669
+ {
670
+ ++m_pos;
671
+ skipSpace();
672
+ auto member = std::make_shared<Node>();
673
+ member->kind = Node::Kind::Member;
674
+ member->left = node;
675
+ member->name = parseIdentifier();
676
+ node = member;
677
+ }
678
+ else if (c == '[')
679
+ {
680
+ ++m_pos;
681
+ auto member = std::make_shared<Node>();
682
+ member->kind = Node::Kind::Member;
683
+ member->computed = true;
684
+ member->left = node;
685
+ member->right = parseExpression();
686
+ skipSpace();
687
+ expect(']');
688
+ node = member;
689
+ }
690
+ else if (c == '(')
691
+ {
692
+ ++m_pos;
693
+ auto call = std::make_shared<Node>();
694
+ call->kind = Node::Kind::Call;
695
+ call->left = node;
696
+ call->items = parseArguments(')');
697
+ node = call;
698
+ }
699
+ else
700
+ {
701
+ return node;
702
+ }
703
+ }
704
+ }
705
+
706
+ std::vector<NodePtr> parseArguments(char closing)
707
+ {
708
+ std::vector<NodePtr> args;
709
+ skipSpace();
710
+ if (peek() == closing)
711
+ {
712
+ ++m_pos;
713
+ return args;
714
+ }
715
+
716
+ while (true)
717
+ {
718
+ args.push_back(parseExpression());
719
+ skipSpace();
720
+ if (peek() == ',')
721
+ {
722
+ ++m_pos;
723
+ continue;
724
+ }
725
+ expect(closing);
726
+ return args;
727
+ }
728
+ }
729
+
730
+ NodePtr parsePrimary()
731
+ {
732
+ skipSpace();
733
+ const char c = peek();
734
+
735
+ if (c == '\0')
736
+ {
737
+ throw ParseError("unexpected end of expression");
738
+ }
739
+
740
+ if (c == '(')
741
+ {
742
+ ++m_pos;
743
+ NodePtr node = parseExpression();
744
+ skipSpace();
745
+ expect(')');
746
+ return node;
747
+ }
748
+
749
+ if (c == '[')
750
+ {
751
+ ++m_pos;
752
+ auto node = std::make_shared<Node>();
753
+ node->kind = Node::Kind::ArrayLiteral;
754
+ node->items = parseArguments(']');
755
+ return node;
756
+ }
757
+
758
+ if (c == '\'' || c == '"')
759
+ {
760
+ auto node = std::make_shared<Node>();
761
+ node->kind = Node::Kind::Literal;
762
+ node->value = parseString(c);
763
+ return node;
764
+ }
765
+
766
+ if (std::isdigit(static_cast<unsigned char>(c)) ||
767
+ (c == '.' && std::isdigit(static_cast<unsigned char>(peek(1)))))
768
+ {
769
+ auto node = std::make_shared<Node>();
770
+ node->kind = Node::Kind::Literal;
771
+ node->value = parseNumber();
772
+ return node;
773
+ }
774
+
775
+ const std::string name = parseIdentifier();
776
+ auto node = std::make_shared<Node>();
777
+ if (name == "true" || name == "false")
778
+ {
779
+ node->kind = Node::Kind::Literal;
780
+ node->value = (name == "true");
781
+ }
782
+ else if (name == "null" || name == "undefined")
783
+ {
784
+ node->kind = Node::Kind::Literal;
785
+ node->value = json();
786
+ }
787
+ else
788
+ {
789
+ node->kind = Node::Kind::Identifier;
790
+ node->name = name;
791
+ }
792
+ return node;
793
+ }
794
+
795
+ json parseString(char quote)
796
+ {
797
+ ++m_pos; // opening quote
798
+ std::string text;
799
+ while (m_pos < m_source.size() && m_source[m_pos] != quote)
800
+ {
801
+ char c = m_source[m_pos];
802
+ if (c == '\\' && m_pos + 1 < m_source.size())
803
+ {
804
+ ++m_pos;
805
+ switch (m_source[m_pos])
806
+ {
807
+ case 'n': c = '\n'; break;
808
+ case 't': c = '\t'; break;
809
+ case 'r': c = '\r'; break;
810
+ default: c = m_source[m_pos]; break;
811
+ }
812
+ }
813
+ text += c;
814
+ ++m_pos;
815
+ }
816
+ if (m_pos >= m_source.size())
817
+ {
818
+ throw ParseError("unterminated string literal");
819
+ }
820
+ ++m_pos; // closing quote
821
+ return json(text);
822
+ }
823
+
824
+ json parseNumber()
825
+ {
826
+ const size_t start = m_pos;
827
+ while (m_pos < m_source.size() &&
828
+ (std::isdigit(static_cast<unsigned char>(m_source[m_pos])) ||
829
+ m_source[m_pos] == '.' || m_source[m_pos] == 'e' || m_source[m_pos] == 'E' ||
830
+ ((m_source[m_pos] == '+' || m_source[m_pos] == '-') && m_pos > start &&
831
+ (m_source[m_pos - 1] == 'e' || m_source[m_pos - 1] == 'E'))))
832
+ {
833
+ ++m_pos;
834
+ }
835
+
836
+ const std::string text = m_source.substr(start, m_pos - start);
837
+ try
838
+ {
839
+ return fromNumber(std::stod(text));
840
+ }
841
+ catch (const std::exception&)
842
+ {
843
+ throw ParseError("invalid number '" + text + "'");
844
+ }
845
+ }
846
+
847
+ std::string parseIdentifier()
848
+ {
849
+ skipSpace();
850
+ const size_t start = m_pos;
851
+ while (m_pos < m_source.size() &&
852
+ (std::isalnum(static_cast<unsigned char>(m_source[m_pos])) ||
853
+ m_source[m_pos] == '_' || m_source[m_pos] == '$'))
854
+ {
855
+ ++m_pos;
856
+ }
857
+ if (m_pos == start)
858
+ {
859
+ throw ParseError("expected an identifier at position " + std::to_string(start));
860
+ }
861
+ return m_source.substr(start, m_pos - start);
862
+ }
863
+
864
+ void skipSpace()
865
+ {
866
+ while (m_pos < m_source.size() &&
867
+ std::isspace(static_cast<unsigned char>(m_source[m_pos])))
868
+ {
869
+ ++m_pos;
870
+ }
871
+ }
872
+
873
+ void expect(char c)
874
+ {
875
+ if (peek() != c)
876
+ {
877
+ throw ParseError(std::string("expected '") + c + "'");
878
+ }
879
+ ++m_pos;
880
+ }
881
+
882
+ char peek(size_t offset = 0) const
883
+ {
884
+ return m_pos + offset < m_source.size() ? m_source[m_pos + offset] : '\0';
885
+ }
886
+
887
+ const std::string m_source;
888
+ size_t m_pos = 0;
889
+ };
890
+
891
+ json evaluateNode(const NodePtr& node, const Scope& scope);
892
+
893
+ // Who hears about reads that found nothing during the evaluation that asked —
894
+ // and only that one: a find/filter predicate evaluated inside it reports
895
+ // nothing, as in the other runtimes. Set by `ReportingMissing` for one call.
896
+ inline thread_local const OnMissing* currentOnMissing = nullptr;
897
+
898
+ struct ReportingMissing
899
+ {
900
+ explicit ReportingMissing(const OnMissing* onMissing) : m_previous(currentOnMissing)
901
+ {
902
+ currentOnMissing = onMissing;
903
+ }
904
+ ~ReportingMissing() { currentOnMissing = m_previous; }
905
+ ReportingMissing(const ReportingMissing&) = delete;
906
+ ReportingMissing& operator=(const ReportingMissing&) = delete;
907
+
908
+ private:
909
+ const OnMissing* m_previous;
910
+ };
911
+
912
+ // How a read is named when it is reported: `params.items[0].title`.
913
+ inline std::string pathOf(const NodePtr& node)
914
+ {
915
+ if (!node)
916
+ {
917
+ return "…";
918
+ }
919
+ if (node->kind == Node::Kind::Identifier)
920
+ {
921
+ return node->name;
922
+ }
923
+ if (node->kind == Node::Kind::Member)
924
+ {
925
+ const std::string object = pathOf(node->left);
926
+ if (!node->computed)
927
+ {
928
+ return object + "." + node->name;
929
+ }
930
+ if (node->right && node->right->kind == Node::Kind::Literal)
931
+ {
932
+ return object + "[" + node->right->value.dump() + "]";
933
+ }
934
+ return object + "[…]";
935
+ }
936
+ return "…";
937
+ }
938
+
939
+ // What object[key] finds, or nothing when nothing is there. One set of rules
940
+ // for every container, so what a read finds and whether it found anything
941
+ // cannot disagree: an array or a string is a sequence — its `length`, or the
942
+ // item at an index within it — and an object is read by the key as text.
943
+ inline std::optional<json> memberOf(const json& object, const json& key)
944
+ {
945
+ if (object.is_array() || object.is_string())
946
+ {
947
+ const size_t size = object.is_array() ? object.size() : object.get_ref<const std::string&>().size();
948
+ if (key.is_string() && key.get_ref<const std::string&>() == "length")
949
+ {
950
+ return json(static_cast<int64_t>(size));
951
+ }
952
+ const double index = toNumber(key);
953
+ if (std::isnan(index) || index < 0 || index >= static_cast<double>(size))
954
+ {
955
+ return std::nullopt;
956
+ }
957
+ const auto at = static_cast<size_t>(index);
958
+ return object.is_array() ? object[at] : json(std::string(1, object.get_ref<const std::string&>()[at]));
959
+ }
960
+
961
+ if (object.is_object())
962
+ {
963
+ auto it = object.find(toText(key));
964
+ if (it != object.end())
965
+ {
966
+ return *it;
967
+ }
968
+ }
969
+
970
+ return std::nullopt;
971
+ }
972
+
973
+ // A member read's value, and whether it found something there. A read past a
974
+ // link that came up empty was reported with it; one past a link that is there
975
+ // but null is reported itself. Only a member read can tell the two apart, which
976
+ // is why the chain is walked here rather than through evaluateNode.
977
+ inline std::pair<json, bool> readMember(const NodePtr& node, const Scope& scope)
978
+ {
979
+ json object;
980
+ bool objectFound = true;
981
+ if (node->left && node->left->kind == Node::Kind::Member)
982
+ {
983
+ auto read = readMember(node->left, scope);
984
+ object = std::move(read.first);
985
+ objectFound = read.second;
986
+ }
987
+ else
988
+ {
989
+ object = evaluateNode(node->left, scope);
990
+ }
991
+ const json key = node->computed ? evaluateNode(node->right, scope) : json(node->name);
992
+ if (auto value = memberOf(object, key))
993
+ {
994
+ return {std::move(*value), true};
995
+ }
996
+ if (currentOnMissing && objectFound)
997
+ {
998
+ (*currentOnMissing)(pathOf(node));
999
+ }
1000
+ return {json(), false};
1001
+ }
1002
+
1003
+ inline bool looseEquals(const json& left, const json& right)
1004
+ {
1005
+ if (left.is_number() && right.is_number())
1006
+ {
1007
+ return toNumber(left) == toNumber(right);
1008
+ }
1009
+ if ((left.is_number() && right.is_string()) || (left.is_string() && right.is_number()))
1010
+ {
1011
+ const double a = toNumber(left);
1012
+ const double b = toNumber(right);
1013
+ return !std::isnan(a) && !std::isnan(b) && a == b;
1014
+ }
1015
+ if (left.is_null() && right.is_null())
1016
+ {
1017
+ return true;
1018
+ }
1019
+ return left == right;
1020
+ }
1021
+
1022
+ inline json applyBinary(const std::string& op, const json& left, const json& right)
1023
+ {
1024
+ if (op == "+")
1025
+ {
1026
+ if (left.is_string() || right.is_string())
1027
+ {
1028
+ return json(toText(left) + toText(right));
1029
+ }
1030
+ return fromNumber(toNumber(left) + toNumber(right));
1031
+ }
1032
+ if (op == "-") { return fromNumber(toNumber(left) - toNumber(right)); }
1033
+ if (op == "*") { return fromNumber(toNumber(left) * toNumber(right)); }
1034
+ if (op == "/") { return fromNumber(toNumber(left) / toNumber(right)); }
1035
+ if (op == "%") { return fromNumber(std::fmod(toNumber(left), toNumber(right))); }
1036
+
1037
+ if (op == "==") { return json(looseEquals(left, right)); }
1038
+ if (op == "!=") { return json(!looseEquals(left, right)); }
1039
+ if (op == "===") { return json(left == right); }
1040
+ if (op == "!==") { return json(left != right); }
1041
+
1042
+ if (left.is_string() && right.is_string())
1043
+ {
1044
+ const std::string& a = left.get_ref<const std::string&>();
1045
+ const std::string& b = right.get_ref<const std::string&>();
1046
+ if (op == "<") { return json(a < b); }
1047
+ if (op == "<=") { return json(a <= b); }
1048
+ if (op == ">") { return json(a > b); }
1049
+ if (op == ">=") { return json(a >= b); }
1050
+ }
1051
+
1052
+ const double a = toNumber(left);
1053
+ const double b = toNumber(right);
1054
+ if (op == "<") { return json(a < b); }
1055
+ if (op == "<=") { return json(a <= b); }
1056
+ if (op == ">") { return json(a > b); }
1057
+ if (op == ">=") { return json(a >= b); }
1058
+
1059
+ throw EvaluationError("unknown operator '" + op + "'");
1060
+ }
1061
+
1062
+ inline json evaluateNode(const NodePtr& node, const Scope& scope)
1063
+ {
1064
+ if (!node)
1065
+ {
1066
+ return json();
1067
+ }
1068
+
1069
+ switch (node->kind)
1070
+ {
1071
+ case Node::Kind::Literal:
1072
+ return node->value;
1073
+
1074
+ case Node::Kind::Identifier:
1075
+ {
1076
+ auto it = scope.find(node->name);
1077
+ if (it != scope.end())
1078
+ {
1079
+ return it->second;
1080
+ }
1081
+ if (builtins().count(node->name))
1082
+ {
1083
+ // A builtin referenced without a call has no value of its own.
1084
+ throw EvaluationError("'" + node->name + "' must be called");
1085
+ }
1086
+ return json();
1087
+ }
1088
+
1089
+ case Node::Kind::Member:
1090
+ return readMember(node, scope).first;
1091
+
1092
+ case Node::Kind::ArrayLiteral:
1093
+ {
1094
+ json result = json::array();
1095
+ for (const auto& item : node->items)
1096
+ {
1097
+ result.push_back(evaluateNode(item, scope));
1098
+ }
1099
+ return result;
1100
+ }
1101
+
1102
+ case Node::Kind::Call:
1103
+ {
1104
+ std::string name;
1105
+ if (!calleeName(node->left, name))
1106
+ {
1107
+ throw EvaluationError("only builtin functions can be called");
1108
+ }
1109
+ auto it = builtins().find(name);
1110
+ if (it == builtins().end())
1111
+ {
1112
+ throw EvaluationError("unknown function '" + name + "'");
1113
+ }
1114
+
1115
+ std::vector<json> args;
1116
+ args.reserve(node->items.size());
1117
+ for (const auto& item : node->items)
1118
+ {
1119
+ args.push_back(evaluateNode(item, scope));
1120
+ }
1121
+ return it->second(args);
1122
+ }
1123
+
1124
+ case Node::Kind::Unary:
1125
+ {
1126
+ const json operand = evaluateNode(node->left, scope);
1127
+ if (node->name == "!") { return json(!isTruthy(operand)); }
1128
+ if (node->name == "-") { return fromNumber(-toNumber(operand)); }
1129
+ return fromNumber(toNumber(operand));
1130
+ }
1131
+
1132
+ case Node::Kind::Logical:
1133
+ {
1134
+ const json left = evaluateNode(node->left, scope);
1135
+ if (node->name == "&&")
1136
+ {
1137
+ return isTruthy(left) ? evaluateNode(node->right, scope) : left;
1138
+ }
1139
+ return isTruthy(left) ? left : evaluateNode(node->right, scope);
1140
+ }
1141
+
1142
+ case Node::Kind::Binary:
1143
+ return applyBinary(node->name,
1144
+ evaluateNode(node->left, scope),
1145
+ evaluateNode(node->right, scope));
1146
+
1147
+ case Node::Kind::Conditional:
1148
+ return isTruthy(evaluateNode(node->left, scope))
1149
+ ? evaluateNode(node->right, scope)
1150
+ : evaluateNode(node->third, scope);
1151
+ }
1152
+
1153
+ return json();
1154
+ }
1155
+
1156
+ } // namespace detail
1157
+
1158
+ /**
1159
+ * A parsed expression. Parsing happens once — when a service is configured —
1160
+ * so evaluating per input costs only the tree walk.
1161
+ */
1162
+ class Expression
1163
+ {
1164
+ public:
1165
+ Expression() = default;
1166
+
1167
+ static Expression parse(const std::string& source)
1168
+ {
1169
+ Expression expression;
1170
+ expression.m_source = source;
1171
+ expression.m_root = detail::Parser(source).parse();
1172
+ return expression;
1173
+ }
1174
+
1175
+ json evaluate(const json& params, const OnMissing* onMissing = nullptr) const
1176
+ {
1177
+ return evaluate(Scope{{"params", params}}, onMissing);
1178
+ }
1179
+
1180
+ // `onMissing` hears about every read that found nothing, once per chain.
1181
+ json evaluate(const Scope& scope, const OnMissing* onMissing = nullptr) const
1182
+ {
1183
+ if (!m_root)
1184
+ {
1185
+ throw EvaluationError("expression is empty");
1186
+ }
1187
+ detail::ReportingMissing reporting(onMissing);
1188
+ return detail::evaluateNode(m_root, scope);
1189
+ }
1190
+
1191
+ const std::string& source() const { return m_source; }
1192
+
1193
+ private:
1194
+ std::string m_source;
1195
+ detail::NodePtr m_root;
1196
+ };
1197
+
1198
+ namespace detail {
1199
+
1200
+ inline json argAt(const std::vector<json>& args, size_t index)
1201
+ {
1202
+ return index < args.size() ? args[index] : json();
1203
+ }
1204
+
1205
+ // find/filter take their predicate as an expression string, parsed per call and
1206
+ // evaluated with the element bound to `item` and its position to `index`.
1207
+ inline bool matchesPredicate(const Expression& predicate, const json& item, size_t index)
1208
+ {
1209
+ return isTruthy(predicate.evaluate(Scope{
1210
+ {"item", item},
1211
+ {"index", json(static_cast<int64_t>(index))}}));
1212
+ }
1213
+
1214
+ inline const std::map<std::string, Builtin>& builtins()
1215
+ {
1216
+ static const std::map<std::string, Builtin> table = {
1217
+ {"print", [](const std::vector<json>& args) -> json {
1218
+ std::cout << toText(argAt(args, 0)) << std::endl;
1219
+ return json();
1220
+ }},
1221
+ {"log", [](const std::vector<json>& args) -> json {
1222
+ std::cout << toText(argAt(args, 0)) << std::endl;
1223
+ return json();
1224
+ }},
1225
+ {"round", [](const std::vector<json>& args) -> json {
1226
+ return fromNumber(std::round(toNumber(argAt(args, 0))));
1227
+ }},
1228
+ {"sin", [](const std::vector<json>& args) -> json {
1229
+ return json(std::sin(toNumber(argAt(args, 0))));
1230
+ }},
1231
+ {"min", [](const std::vector<json>& args) -> json {
1232
+ double result = std::numeric_limits<double>::infinity();
1233
+ for (const auto& arg : args) { result = std::min(result, toNumber(arg)); }
1234
+ return fromNumber(result);
1235
+ }},
1236
+ {"max", [](const std::vector<json>& args) -> json {
1237
+ double result = -std::numeric_limits<double>::infinity();
1238
+ for (const auto& arg : args) { result = std::max(result, toNumber(arg)); }
1239
+ return fromNumber(result);
1240
+ }},
1241
+ {"rand", [](const std::vector<json>&) -> json {
1242
+ static std::mt19937 engine{std::random_device{}()};
1243
+ static std::uniform_real_distribution<double> distribution(0.0, 1.0);
1244
+ return json(distribution(engine));
1245
+ }},
1246
+ {"number", [](const std::vector<json>& args) -> json {
1247
+ return fromNumber(toNumber(argAt(args, 0)));
1248
+ }},
1249
+ {"string", [](const std::vector<json>& args) -> json {
1250
+ return json(toText(argAt(args, 0)));
1251
+ }},
1252
+ {"stringify", [](const std::vector<json>& args) -> json {
1253
+ return json(argAt(args, 0).dump());
1254
+ }},
1255
+ {"parse", [](const std::vector<json>& args) -> json {
1256
+ const json arg = argAt(args, 0);
1257
+ if (!arg.is_string()) { return json("<parse undefined>"); }
1258
+ try { return json::parse(arg.get_ref<const std::string&>()); }
1259
+ catch (const std::exception&) { return json(); }
1260
+ }},
1261
+ {"concat", [](const std::vector<json>& args) -> json {
1262
+ std::string result;
1263
+ for (const auto& arg : args) { result += toText(arg); }
1264
+ return json(result);
1265
+ }},
1266
+ // An array's elements as one text, e.g. the parts a gather collected:
1267
+ // join(params.items, ''). An empty element is nothing, as Array.join has it.
1268
+ {"join", [](const std::vector<json>& args) -> json {
1269
+ const json arg = argAt(args, 0);
1270
+ const json separatorArg = argAt(args, 1);
1271
+ const std::string separator = separatorArg.is_null() ? "" : toText(separatorArg);
1272
+ if (!arg.is_array()) { return json(arg.is_null() ? "" : toText(arg)); }
1273
+ std::string result;
1274
+ for (size_t i = 0; i < arg.size(); ++i)
1275
+ {
1276
+ if (i > 0) { result += separator; }
1277
+ if (!arg[i].is_null()) { result += toText(arg[i]); }
1278
+ }
1279
+ return json(result);
1280
+ }},
1281
+ {"encodeURI",[](const std::vector<json>& args) -> json {
1282
+ static const std::string unreserved =
1283
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
1284
+ "-_.!~*'();/?:@&=+$,#";
1285
+ std::ostringstream out;
1286
+ for (unsigned char c : toText(argAt(args, 0)))
1287
+ {
1288
+ if (unreserved.find(static_cast<char>(c)) != std::string::npos)
1289
+ {
1290
+ out << c;
1291
+ }
1292
+ else
1293
+ {
1294
+ out << '%' << std::uppercase << std::hex << std::setw(2)
1295
+ << std::setfill('0') << static_cast<int>(c) << std::nouppercase << std::dec;
1296
+ }
1297
+ }
1298
+ return json(out.str());
1299
+ }},
1300
+ {"slug", [](const std::vector<json>& args) -> json {
1301
+ std::string result;
1302
+ for (char c : toText(argAt(args, 0)))
1303
+ {
1304
+ const char lower = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
1305
+ if ((lower >= 'a' && lower <= 'z') || (lower >= '0' && lower <= '9') ||
1306
+ lower == '_' || lower == '-')
1307
+ {
1308
+ result += lower;
1309
+ }
1310
+ }
1311
+ return json(result);
1312
+ }},
1313
+ {"now", [](const std::vector<json>&) -> json {
1314
+ return json(nowMillis());
1315
+ }},
1316
+ {"range", [](const std::vector<json>& args) -> json {
1317
+ json result = json::array();
1318
+ const double count = std::round(toNumber(argAt(args, 0)));
1319
+ for (int64_t i = 0; i < static_cast<int64_t>(std::max(0.0, count)); ++i)
1320
+ {
1321
+ result.push_back(i);
1322
+ }
1323
+ return result;
1324
+ }},
1325
+ {"sum", [](const std::vector<json>& args) -> json {
1326
+ const json arg = argAt(args, 0);
1327
+ if (!arg.is_array()) { return arg; }
1328
+ double total = 0.0;
1329
+ for (const auto& entry : arg) { total += toNumber(entry); }
1330
+ return fromNumber(total);
1331
+ }},
1332
+ {"avg", [](const std::vector<json>& args) -> json {
1333
+ const json arg = argAt(args, 0);
1334
+ if (!arg.is_array()) { return arg; }
1335
+ if (arg.empty()) { return json(); }
1336
+ double total = 0.0;
1337
+ for (const auto& entry : arg) { total += toNumber(entry); }
1338
+ return fromNumber(total / static_cast<double>(arg.size()));
1339
+ }},
1340
+ {"flatSum", [](const std::vector<json>& args) -> json {
1341
+ const json arg = argAt(args, 0);
1342
+ if (!arg.is_array()) { return fromNumber(0); }
1343
+ double total = 0.0;
1344
+ for (const auto& entry : arg)
1345
+ {
1346
+ if (entry.is_array())
1347
+ {
1348
+ for (const auto& inner : entry) { total += toNumber(inner); }
1349
+ }
1350
+ else
1351
+ {
1352
+ total += toNumber(entry);
1353
+ }
1354
+ }
1355
+ return fromNumber(total);
1356
+ }},
1357
+ {"at", [](const std::vector<json>& args) -> json {
1358
+ const json arg = argAt(args, 0);
1359
+ if (!arg.is_array() || arg.empty()) { return json(); }
1360
+ const double index = std::fabs(std::round(toNumber(argAt(args, 1))));
1361
+ return arg[static_cast<size_t>(index) % arg.size()];
1362
+ }},
1363
+ {"slice", [](const std::vector<json>& args) -> json {
1364
+ const json arg = argAt(args, 0);
1365
+ if (!arg.is_array()) { return json::array(); }
1366
+ const int64_t offset = static_cast<int64_t>(toNumber(argAt(args, 1)));
1367
+ const double rawStep = toNumber(argAt(args, 2));
1368
+ const int64_t step = std::isnan(rawStep) || rawStep < 1 ? 1 : static_cast<int64_t>(rawStep);
1369
+ const double rawEnd = toNumber(argAt(args, 3));
1370
+ const int64_t end = std::isnan(rawEnd) ? static_cast<int64_t>(arg.size())
1371
+ : static_cast<int64_t>(rawEnd);
1372
+ json result = json::array();
1373
+ for (int64_t i = std::max<int64_t>(0, offset);
1374
+ i < std::min<int64_t>(end, static_cast<int64_t>(arg.size())); ++i)
1375
+ {
1376
+ if ((i - std::max<int64_t>(0, offset)) % step == 0)
1377
+ {
1378
+ result.push_back(arg[static_cast<size_t>(i)]);
1379
+ }
1380
+ }
1381
+ return result;
1382
+ }},
1383
+ {"find", [](const std::vector<json>& args) -> json {
1384
+ const json arg = argAt(args, 0);
1385
+ const json predicateSource = argAt(args, 1);
1386
+ if (!arg.is_array() || !predicateSource.is_string()) { return json(); }
1387
+ const Expression predicate =
1388
+ Expression::parse(predicateSource.get_ref<const std::string&>());
1389
+ for (size_t i = 0; i < arg.size(); ++i)
1390
+ {
1391
+ if (matchesPredicate(predicate, arg[i], i)) { return arg[i]; }
1392
+ }
1393
+ return json();
1394
+ }},
1395
+ {"filter", [](const std::vector<json>& args) -> json {
1396
+ const json arg = argAt(args, 0);
1397
+ const json predicateSource = argAt(args, 1);
1398
+ json result = json::array();
1399
+ if (!arg.is_array() || !predicateSource.is_string()) { return result; }
1400
+ const Expression predicate =
1401
+ Expression::parse(predicateSource.get_ref<const std::string&>());
1402
+ for (size_t i = 0; i < arg.size(); ++i)
1403
+ {
1404
+ if (matchesPredicate(predicate, arg[i], i)) { result.push_back(arg[i]); }
1405
+ }
1406
+ return result;
1407
+ }},
1408
+ {"isFuture", [](const std::vector<json>& args) -> json {
1409
+ int64_t millis = 0;
1410
+ if (!toEpochMillis(argAt(args, 0), millis)) { return json(false); }
1411
+ return json(millis >= nowMillis());
1412
+ }},
1413
+ {"isPast", [](const std::vector<json>& args) -> json {
1414
+ int64_t millis = 0;
1415
+ if (!toEpochMillis(argAt(args, 0), millis)) { return json(false); }
1416
+ return json(millis < nowMillis());
1417
+ }},
1418
+ {"formatNow", [](const std::vector<json>& args) -> json {
1419
+ const std::time_t stamp = std::time(nullptr);
1420
+ std::tm tm{};
1421
+ #ifdef _WIN32
1422
+ localtime_s(&tm, &stamp);
1423
+ #else
1424
+ localtime_r(&stamp, &tm);
1425
+ #endif
1426
+ return json(formatTime(tm, toText(argAt(args, 0))));
1427
+ }},
1428
+ {"reformatDate", [](const std::vector<json>& args) -> json {
1429
+ const std::string text = toText(argAt(args, 0));
1430
+ const std::string inputFormat = toText(argAt(args, 1));
1431
+ const std::string outputFormat = toText(argAt(args, 2));
1432
+
1433
+ std::tm tm{};
1434
+ if (!parseTime(text, inputFormat, tm))
1435
+ {
1436
+ int64_t millis = 0;
1437
+ if (!toEpochMillis(argAt(args, 0), millis)) { return json(text); }
1438
+ const std::time_t stamp = static_cast<std::time_t>(millis / 1000);
1439
+ #ifdef _WIN32
1440
+ localtime_s(&tm, &stamp);
1441
+ #else
1442
+ localtime_r(&stamp, &tm);
1443
+ #endif
1444
+ }
1445
+ return json(formatTime(tm, outputFormat));
1446
+ }},
1447
+ {"uuid.v4", [](const std::vector<json>&) -> json {
1448
+ return json(generateUUID());
1449
+ }},
1450
+ {"uuid.v7", [](const std::vector<json>&) -> json {
1451
+ // Time-ordered: 48 bits of epoch millis, then version/variant bits over
1452
+ // random data, rendered in the canonical 8-4-4-4-12 form.
1453
+ static std::mt19937 engine{std::random_device{}()};
1454
+ std::uniform_int_distribution<int> byte(0, 255);
1455
+ std::array<unsigned char, 16> bytes{};
1456
+ for (auto& b : bytes) { b = static_cast<unsigned char>(byte(engine)); }
1457
+
1458
+ const uint64_t millis = static_cast<uint64_t>(nowMillis());
1459
+ for (int i = 0; i < 6; ++i)
1460
+ {
1461
+ bytes[i] = static_cast<unsigned char>((millis >> (8 * (5 - i))) & 0xff);
1462
+ }
1463
+ bytes[6] = static_cast<unsigned char>((bytes[6] & 0x0f) | 0x70);
1464
+ bytes[8] = static_cast<unsigned char>((bytes[8] & 0x3f) | 0x80);
1465
+
1466
+ std::ostringstream out;
1467
+ out << std::hex << std::setfill('0');
1468
+ for (size_t i = 0; i < bytes.size(); ++i)
1469
+ {
1470
+ if (i == 4 || i == 6 || i == 8 || i == 10) { out << '-'; }
1471
+ out << std::setw(2) << static_cast<int>(bytes[i]);
1472
+ }
1473
+ return json(out.str());
1474
+ }},
1475
+ };
1476
+ return table;
1477
+ }
1478
+
1479
+ } // namespace detail
1480
+ } // namespace expression
1481
+ } // namespace hkp