@pyric/cli 0.1.0-alpha.11 → 0.1.0-alpha.13

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 (424) hide show
  1. package/dist/cli/serve.js +4 -4
  2. package/dist/cli/serve.js.map +1 -1
  3. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  4. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  5. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  6. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  7. package/dist/conformance/.generated/can-i-use.js +2 -2
  8. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  9. package/dist/serve/bundler.d.ts +13 -8
  10. package/dist/serve/bundler.d.ts.map +1 -1
  11. package/dist/serve/bundler.js +31 -36
  12. package/dist/serve/bundler.js.map +1 -1
  13. package/dist/serve/docs-ui/docs/_rhythm/index.html +1 -1
  14. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +1 -1
  15. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +1 -1
  16. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +1 -1
  17. package/dist/serve/docs-ui/docs/ai-compat/index.html +1 -1
  18. package/dist/serve/docs-ui/docs/api-reference/index.html +2 -2
  19. package/dist/serve/docs-ui/docs/api-reference.md +1 -1
  20. package/dist/serve/docs-ui/docs/app-compat/index.html +1 -1
  21. package/dist/serve/docs-ui/docs/auth-compat/index.html +1 -1
  22. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +44 -22
  23. package/dist/serve/docs-ui/docs/build/ai-logic.md +69 -21
  24. package/dist/serve/docs-ui/docs/build/authentication/index.html +1 -1
  25. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +1 -1
  26. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +1 -1
  27. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +1 -1
  28. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +1 -1
  29. package/dist/serve/docs-ui/docs/conformance-scores/index.html +1 -1
  30. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +1 -1
  31. package/dist/serve/docs-ui/docs/database-compat/index.html +1 -1
  32. package/dist/serve/docs-ui/docs/firestore-compat/index.html +1 -1
  33. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +1 -1
  34. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
  35. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works.md +2 -0
  36. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +3 -2
  37. package/dist/serve/docs-ui/docs/get-started/start-building.md +3 -1
  38. package/dist/serve/docs-ui/docs/index.json +349 -29
  39. package/dist/serve/docs-ui/docs/messaging-compat/index.html +1 -1
  40. package/dist/serve/docs-ui/docs/observe/resolve-runtime-status/index.html +28 -0
  41. package/dist/serve/docs-ui/docs/observe/resolve-runtime-status.md +47 -0
  42. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +1 -1
  43. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +1 -1
  44. package/dist/serve/docs-ui/docs/overview/index.html +1 -1
  45. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  46. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  47. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  48. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  49. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
  50. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
  51. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  52. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +1 -1
  53. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  54. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +1 -1
  55. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +1 -1
  56. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  57. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  58. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  59. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  60. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  61. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  62. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  63. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  64. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  65. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  66. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  67. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +168 -76
  68. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +156 -73
  69. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  70. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +11 -8
  71. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +17 -4
  72. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1 -1
  73. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1 -1
  74. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  75. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  76. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +1 -1
  77. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
  78. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  79. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +37 -14
  80. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +28 -8
  81. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +1 -1
  82. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  83. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  84. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  85. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  86. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  87. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  88. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  89. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  90. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  91. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  92. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  93. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  94. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
  95. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  96. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  97. package/dist/serve/docs-ui/docs/rules-compat/index.html +1 -1
  98. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +1 -1
  99. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  100. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +1 -1
  101. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  102. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +1 -1
  103. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  104. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +1 -1
  105. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  106. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +1 -1
  107. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +1 -1
  108. package/dist/serve/docs-ui/docs/storage-compat/index.html +1 -1
  109. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  110. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  111. package/dist/serve/docs-ui/docs/tutorial/index.html +429 -0
  112. package/dist/serve/docs-ui/docs/tutorial.md +701 -0
  113. package/dist/serve/docs-ui/llms.txt +3 -1
  114. package/dist/serve/entries/init.d.ts.map +1 -1
  115. package/dist/serve/entries/init.js +3 -0
  116. package/dist/serve/entries/init.js.map +1 -1
  117. package/dist/serve/entries/runtime.d.ts.map +1 -1
  118. package/dist/serve/entries/runtime.js +20 -5
  119. package/dist/serve/entries/runtime.js.map +1 -1
  120. package/dist/serve/entries/worker-runtime.d.ts +2 -2
  121. package/dist/serve/entries/worker-runtime.d.ts.map +1 -1
  122. package/dist/serve/entries/worker-runtime.js +45 -10
  123. package/dist/serve/entries/worker-runtime.js.map +1 -1
  124. package/dist/serve/runtime/chip-config.d.ts +19 -0
  125. package/dist/serve/runtime/chip-config.d.ts.map +1 -0
  126. package/dist/serve/runtime/chip-config.js +19 -0
  127. package/dist/serve/runtime/chip-config.js.map +1 -0
  128. package/dist/serve/runtime/chip-install.d.ts +10 -0
  129. package/dist/serve/runtime/chip-install.d.ts.map +1 -0
  130. package/dist/serve/runtime/chip-install.js +15 -0
  131. package/dist/serve/runtime/chip-install.js.map +1 -0
  132. package/dist/serve/runtime/chip.d.ts +17 -0
  133. package/dist/serve/runtime/chip.d.ts.map +1 -0
  134. package/dist/serve/runtime/chip.js +257 -0
  135. package/dist/serve/runtime/chip.js.map +1 -0
  136. package/dist/serve/runtime/manifest.d.ts +22 -0
  137. package/dist/serve/runtime/manifest.d.ts.map +1 -0
  138. package/dist/serve/runtime/manifest.js +20 -0
  139. package/dist/serve/runtime/manifest.js.map +1 -0
  140. package/dist/serve/runtime/status.d.ts +49 -0
  141. package/dist/serve/runtime/status.d.ts.map +1 -0
  142. package/dist/serve/runtime/status.js +164 -0
  143. package/dist/serve/runtime/status.js.map +1 -0
  144. package/dist/serve/runtime/worker-connection.d.ts +4 -0
  145. package/dist/serve/runtime/worker-connection.d.ts.map +1 -0
  146. package/dist/serve/runtime/worker-connection.js +11 -0
  147. package/dist/serve/runtime/worker-connection.js.map +1 -0
  148. package/dist/serve/runtime/worker-generation.d.ts +14 -0
  149. package/dist/serve/runtime/worker-generation.d.ts.map +1 -0
  150. package/dist/serve/runtime/worker-generation.js +56 -0
  151. package/dist/serve/runtime/worker-generation.js.map +1 -0
  152. package/dist/serve/runtime/worker-replacement.d.ts +18 -0
  153. package/dist/serve/runtime/worker-replacement.d.ts.map +1 -0
  154. package/dist/serve/runtime/worker-replacement.js +29 -0
  155. package/dist/serve/runtime/worker-replacement.js.map +1 -0
  156. package/dist/serve/standalone-assets.d.ts +2 -2
  157. package/dist/serve/standalone-assets.d.ts.map +1 -1
  158. package/dist/serve/standalone-assets.js +1 -1
  159. package/dist/serve/standalone-assets.js.map +1 -1
  160. package/dist/serve/studio-ui/assets/{RulesCodeEditor-CxVYcZXw.js → RulesCodeEditor-BDlH-5lp.js} +1 -1
  161. package/dist/serve/studio-ui/assets/{index-cpSfgQ7H.js → index-Bf9SSE8L.js} +5 -5
  162. package/dist/serve/studio-ui/assets/{seed-DeuFKi4J.js → seed-D_UjxfOU.js} +1 -1
  163. package/dist/serve/studio-ui/index.html +1 -1
  164. package/dist/serve/vite-ai-config.d.ts +25 -0
  165. package/dist/serve/vite-ai-config.d.ts.map +1 -0
  166. package/dist/serve/vite-ai-config.js +45 -0
  167. package/dist/serve/vite-ai-config.js.map +1 -0
  168. package/dist/serve/vite-plugin.d.ts +17 -36
  169. package/dist/serve/vite-plugin.d.ts.map +1 -1
  170. package/dist/serve/vite-plugin.js +38 -57
  171. package/dist/serve/vite-plugin.js.map +1 -1
  172. package/dist/serve/vite-rules-source.d.ts +8 -0
  173. package/dist/serve/vite-rules-source.d.ts.map +1 -0
  174. package/dist/serve/vite-rules-source.js +23 -0
  175. package/dist/serve/vite-rules-source.js.map +1 -0
  176. package/dist/serve/vite-worker-runtime.d.ts +20 -0
  177. package/dist/serve/vite-worker-runtime.d.ts.map +1 -0
  178. package/dist/serve/vite-worker-runtime.js +25 -0
  179. package/dist/serve/vite-worker-runtime.js.map +1 -0
  180. package/dist/serve/worker/client/connection.d.ts +7 -2
  181. package/dist/serve/worker/client/connection.d.ts.map +1 -1
  182. package/dist/serve/worker/client/connection.js +13 -16
  183. package/dist/serve/worker/client/connection.js.map +1 -1
  184. package/dist/serve/worker/client/core.d.ts +7 -0
  185. package/dist/serve/worker/client/core.d.ts.map +1 -1
  186. package/dist/serve/worker/client/core.js +28 -0
  187. package/dist/serve/worker/client/core.js.map +1 -1
  188. package/dist/serve/worker/client/runtime-control.d.ts +8 -0
  189. package/dist/serve/worker/client/runtime-control.d.ts.map +1 -0
  190. package/dist/serve/worker/client/runtime-control.js +11 -0
  191. package/dist/serve/worker/client/runtime-control.js.map +1 -0
  192. package/dist/serve/worker/entry.js +44 -2
  193. package/dist/serve/worker/entry.js.map +1 -1
  194. package/dist/serve/worker/host/core.js +1 -1
  195. package/dist/serve/worker/host/core.js.map +1 -1
  196. package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
  197. package/dist/serve/worker/host/firestore-writes.js +3 -2
  198. package/dist/serve/worker/host/firestore-writes.js.map +1 -1
  199. package/dist/serve/worker/host/studio.js +1 -1
  200. package/dist/serve/worker/host/studio.js.map +1 -1
  201. package/dist/serve/worker/host-context.d.ts +1 -1
  202. package/dist/serve/worker/host-context.d.ts.map +1 -1
  203. package/dist/serve/worker/index.d.ts +2 -1
  204. package/dist/serve/worker/index.d.ts.map +1 -1
  205. package/dist/serve/worker/index.js +2 -1
  206. package/dist/serve/worker/index.js.map +1 -1
  207. package/dist/serve/worker/protocol.d.ts +15 -1
  208. package/dist/serve/worker/protocol.d.ts.map +1 -1
  209. package/dist/serve/worker/protocol.js +2 -2
  210. package/dist/serve/worker/protocol.js.map +1 -1
  211. package/dist/serve/worker/retirement.d.ts +21 -0
  212. package/dist/serve/worker/retirement.d.ts.map +1 -0
  213. package/dist/serve/worker/retirement.js +97 -0
  214. package/dist/serve/worker/retirement.js.map +1 -0
  215. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  216. package/dist/serve/worker/serve-init.js +5 -6
  217. package/dist/serve/worker/serve-init.js.map +1 -1
  218. package/dist/vite.d.ts +1 -0
  219. package/dist/vite.d.ts.map +1 -1
  220. package/dist/vite.js.map +1 -1
  221. package/package.json +6 -4
  222. package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
  223. package/src/assurance/attachment.ts +211 -0
  224. package/src/assurance/browser.ts +80 -0
  225. package/src/assurance/campaign.ts +496 -0
  226. package/src/assurance/capabilities.ts +446 -0
  227. package/src/assurance/cases.ts +43 -0
  228. package/src/assurance/index.ts +75 -0
  229. package/src/assurance/runner.ts +885 -0
  230. package/src/assurance/tool-names.ts +15 -0
  231. package/src/assurance/tools.ts +830 -0
  232. package/src/assurance/types.ts +352 -0
  233. package/src/assurance/validation.ts +434 -0
  234. package/src/bridge/client/bridge.ts +550 -0
  235. package/src/bridge/client/dispatch.ts +137 -0
  236. package/src/bridge/client.ts +45 -0
  237. package/src/bridge/protocol.ts +351 -0
  238. package/src/bridge/server/audit.ts +53 -0
  239. package/src/bridge/server/bridge.ts +597 -0
  240. package/src/bridge/server/headless.ts +160 -0
  241. package/src/bridge/server/json-schema-to-zod.ts +108 -0
  242. package/src/bridge/server/local-bridge.ts +66 -0
  243. package/src/bridge/server/logger.ts +50 -0
  244. package/src/bridge/server/mcp-contract.ts +93 -0
  245. package/src/bridge/server/mcp.ts +129 -0
  246. package/src/bridge/server/peer.ts +232 -0
  247. package/src/bridge/server/standalone.ts +347 -0
  248. package/src/bridge/server/tool-metadata.ts +99 -0
  249. package/src/bridge/server.ts +28 -0
  250. package/src/cli/can-i-use.ts +50 -0
  251. package/src/cli/cli.test.ts +493 -0
  252. package/src/cli/database-rules.ts +329 -0
  253. package/src/cli/dev-runner.ts +282 -0
  254. package/src/cli/firebase-json.ts +100 -0
  255. package/src/cli/firestore-indexes.ts +70 -0
  256. package/src/cli/index.ts +425 -0
  257. package/src/cli/init.ts +260 -0
  258. package/src/cli/mcp-proxy.ts +196 -0
  259. package/src/cli/parse-args.ts +80 -0
  260. package/src/cli/rules.ts +259 -0
  261. package/src/cli/scope.ts +67 -0
  262. package/src/cli/serve.ts +996 -0
  263. package/src/cli/service-commands.ts +73 -0
  264. package/src/cli/snapshot.ts +164 -0
  265. package/src/cli/storage-rules.ts +172 -0
  266. package/src/cli/verify.ts +416 -0
  267. package/src/conformance/.generated/can-i-use-browser.ts +113 -0
  268. package/src/conformance/.generated/can-i-use.ts +117 -0
  269. package/src/conformance/.generated/conformance-docs.ts +14 -0
  270. package/src/conformance/browser.ts +24 -0
  271. package/src/conformance/can-i-use-tool.ts +51 -0
  272. package/src/conformance/can-i-use.ts +18 -0
  273. package/src/conformance/docs.ts +8 -0
  274. package/src/conformance/index.ts +20 -0
  275. package/src/conformance/tools.ts +16 -0
  276. package/src/credentials/core/memoize-ttl.ts +142 -0
  277. package/src/credentials/core/types.ts +10 -0
  278. package/src/credentials/node/from-adc.ts +96 -0
  279. package/src/credentials/node/from-service-account.ts +133 -0
  280. package/src/credentials/node/index.ts +6 -0
  281. package/src/discover/concurrency.ts +127 -0
  282. package/src/discover/crawler-adapter.ts +142 -0
  283. package/src/discover/crawler.ts +1127 -0
  284. package/src/discover/credential-free.ts +27 -0
  285. package/src/discover/findCollectionGroup.ts +131 -0
  286. package/src/discover/firestore-source.ts +59 -0
  287. package/src/discover/index.ts +5 -0
  288. package/src/discover/merge.ts +523 -0
  289. package/src/discover/session.ts +402 -0
  290. package/src/discover/tools.ts +201 -0
  291. package/src/discover/types.ts +187 -0
  292. package/src/discover/wire.ts +324 -0
  293. package/src/functions-rtdb/child.ts +382 -0
  294. package/src/functions-rtdb/delivery.ts +7 -0
  295. package/src/functions-rtdb/discovery.ts +136 -0
  296. package/src/functions-rtdb/event.ts +64 -0
  297. package/src/functions-rtdb/execution.ts +111 -0
  298. package/src/functions-rtdb/in-memory-delivery.ts +40 -0
  299. package/src/functions-rtdb/project.ts +74 -0
  300. package/src/functions-rtdb/projection.ts +104 -0
  301. package/src/functions-rtdb/reference-pattern.ts +20 -0
  302. package/src/functions-rtdb/remote-delivery.ts +23 -0
  303. package/src/pkg-version.ts +49 -0
  304. package/src/register/esm-exports.ts +63 -0
  305. package/src/register/hooks.ts +30 -0
  306. package/src/register/index.ts +150 -0
  307. package/src/register/mapping.ts +33 -0
  308. package/src/remote/index.ts +1050 -0
  309. package/src/rtdb/crawl-snapshot.ts +118 -0
  310. package/src/rtdb/inspection.ts +137 -0
  311. package/src/rtdb/load-rules-document.ts +56 -0
  312. package/src/rtdb/rules-generation-tool.ts +38 -0
  313. package/src/rtdb/rules-json.ts +29 -0
  314. package/src/serve/activity-guard.ts +29 -0
  315. package/src/serve/activity-route.ts +164 -0
  316. package/src/serve/activity-warning.ts +26 -0
  317. package/src/serve/bridge-mount.ts +200 -0
  318. package/src/serve/bundler.ts +519 -0
  319. package/src/serve/capture-store.ts +65 -0
  320. package/src/serve/discovery.ts +199 -0
  321. package/src/serve/entries/ai.ts +292 -0
  322. package/src/serve/entries/app-backend.ts +4 -0
  323. package/src/serve/entries/app-client.ts +26 -0
  324. package/src/serve/entries/app-session-store.ts +47 -0
  325. package/src/serve/entries/app.ts +11 -0
  326. package/src/serve/entries/auth-helper-core.ts +181 -0
  327. package/src/serve/entries/auth-helper-dom.ts +134 -0
  328. package/src/serve/entries/auth-helper-runtime.ts +20 -0
  329. package/src/serve/entries/auth.ts +255 -0
  330. package/src/serve/entries/bridge-url.ts +31 -0
  331. package/src/serve/entries/database.ts +129 -0
  332. package/src/serve/entries/firestore.ts +232 -0
  333. package/src/serve/entries/init.ts +49 -0
  334. package/src/serve/entries/keepalive.ts +46 -0
  335. package/src/serve/entries/messaging-sw.ts +75 -0
  336. package/src/serve/entries/messaging.ts +96 -0
  337. package/src/serve/entries/runtime.ts +556 -0
  338. package/src/serve/entries/session-store.ts +97 -0
  339. package/src/serve/entries/storage.ts +92 -0
  340. package/src/serve/entries/tab-sync-wiring.ts +274 -0
  341. package/src/serve/entries/worker-runtime.ts +135 -0
  342. package/src/serve/init-payload.ts +42 -0
  343. package/src/serve/namespace.ts +675 -0
  344. package/src/serve/open-browser.ts +68 -0
  345. package/src/serve/rules.ts +272 -0
  346. package/src/serve/runtime/chip-config.ts +30 -0
  347. package/src/serve/runtime/chip-install.ts +27 -0
  348. package/src/serve/runtime/chip.ts +282 -0
  349. package/src/serve/runtime/manifest.ts +37 -0
  350. package/src/serve/runtime/status.ts +216 -0
  351. package/src/serve/runtime/worker-connection.ts +14 -0
  352. package/src/serve/runtime/worker-generation.ts +75 -0
  353. package/src/serve/runtime/worker-replacement.ts +42 -0
  354. package/src/serve/sandbox-marker.ts +31 -0
  355. package/src/serve/server.ts +428 -0
  356. package/src/serve/standalone-assets.ts +180 -0
  357. package/src/serve/state-store.ts +166 -0
  358. package/src/serve/studio/disk-project-store.ts +185 -0
  359. package/src/serve/studio/disk-workspace.ts +162 -0
  360. package/src/serve/studio/index.ts +20 -0
  361. package/src/serve/studio/routes.ts +237 -0
  362. package/src/serve/studio/store-types.ts +48 -0
  363. package/src/serve/studio/studio-storage.test.ts +289 -0
  364. package/src/serve/vite-ai-config.ts +77 -0
  365. package/src/serve/vite-plugin.ts +1075 -0
  366. package/src/serve/vite-rules-source.ts +28 -0
  367. package/src/serve/vite-worker-runtime.ts +51 -0
  368. package/src/serve/worker/activity-bootstrap.ts +24 -0
  369. package/src/serve/worker/client/admin-firestore.ts +38 -0
  370. package/src/serve/worker/client/ai.ts +124 -0
  371. package/src/serve/worker/client/auth.ts +489 -0
  372. package/src/serve/worker/client/connection.ts +227 -0
  373. package/src/serve/worker/client/core.ts +384 -0
  374. package/src/serve/worker/client/disconnect.ts +45 -0
  375. package/src/serve/worker/client/firestore-reads.ts +181 -0
  376. package/src/serve/worker/client/firestore-refs.ts +226 -0
  377. package/src/serve/worker/client/firestore-writes.ts +232 -0
  378. package/src/serve/worker/client/handles.ts +91 -0
  379. package/src/serve/worker/client/messaging.ts +119 -0
  380. package/src/serve/worker/client/presence.ts +174 -0
  381. package/src/serve/worker/client/rtdb.ts +311 -0
  382. package/src/serve/worker/client/rules.ts +63 -0
  383. package/src/serve/worker/client/runtime-control.ts +22 -0
  384. package/src/serve/worker/client/service-worker-connection.ts +59 -0
  385. package/src/serve/worker/client/snapshots.ts +86 -0
  386. package/src/serve/worker/client/storage.ts +195 -0
  387. package/src/serve/worker/client/studio.ts +88 -0
  388. package/src/serve/worker/client.ts +57 -0
  389. package/src/serve/worker/durable-persistence.ts +137 -0
  390. package/src/serve/worker/entry.ts +223 -0
  391. package/src/serve/worker/host/admin-firestore.ts +88 -0
  392. package/src/serve/worker/host/connection.ts +179 -0
  393. package/src/serve/worker/host/core.ts +387 -0
  394. package/src/serve/worker/host/dispatch.ts +316 -0
  395. package/src/serve/worker/host/firestore-reads.ts +117 -0
  396. package/src/serve/worker/host/firestore-writes.ts +456 -0
  397. package/src/serve/worker/host/presence.ts +312 -0
  398. package/src/serve/worker/host/rtdb.ts +136 -0
  399. package/src/serve/worker/host/rules.ts +128 -0
  400. package/src/serve/worker/host/storage.ts +312 -0
  401. package/src/serve/worker/host/studio.ts +75 -0
  402. package/src/serve/worker/host/subscriptions.ts +238 -0
  403. package/src/serve/worker/host-ai.ts +165 -0
  404. package/src/serve/worker/host-auth.ts +469 -0
  405. package/src/serve/worker/host-context.ts +273 -0
  406. package/src/serve/worker/host-events.ts +94 -0
  407. package/src/serve/worker/host-messaging.ts +240 -0
  408. package/src/serve/worker/host.ts +47 -0
  409. package/src/serve/worker/index.ts +196 -0
  410. package/src/serve/worker/presence-timing.ts +15 -0
  411. package/src/serve/worker/protocol.ts +1124 -0
  412. package/src/serve/worker/retirement.ts +125 -0
  413. package/src/serve/worker/serve-init.ts +605 -0
  414. package/src/serve/worker/service-worker-channel.ts +33 -0
  415. package/src/serve/worker/service-worker-relay.ts +86 -0
  416. package/src/serve/writer-lock.ts +53 -0
  417. package/src/verify/cases.ts +233 -0
  418. package/src/verify/fixture.ts +258 -0
  419. package/src/verify/index.ts +519 -0
  420. package/src/verify/tools.ts +108 -0
  421. package/src/version/compat-target.ts +17 -0
  422. package/src/vite.ts +18 -0
  423. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -31
  424. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -29
@@ -0,0 +1,316 @@
1
+ /**
2
+ * SharedWorker host — the message dispatcher + port cleanup.
3
+ *
4
+ * The top of the host: `handleMessage` opens the op's ambient-provenance
5
+ * window and hands to `dispatchMessage`, which peels off the auth / AI /
6
+ * messaging / event families (their sibling `host-*.ts` modules), then routes
7
+ * ops to `handleOp` (the firestore/rules/admin/rtdb/storage/connection/studio
8
+ * orchestrator) and subs to the subscription registry. `cleanupPort` tears a
9
+ * disconnected port's per-subsystem state down.
10
+ *
11
+ * `handleOp` resolves the op's Firestore handle ONCE (the `db`/`lens`
12
+ * preamble) — the eager lens/session resolution every op sees — then dispatches
13
+ * to the per-family `handle*Op` handlers. This is the single unit-testable seam:
14
+ * tests build a real `HostCtx` over an in-memory sandbox and call
15
+ * `handleMessage` directly with fake ports.
16
+ */
17
+
18
+ import type { InboundMessage, OpMessage, ToolMessage } from '../protocol.js';
19
+ import {
20
+ isAuthSub,
21
+ isEventSub,
22
+ isRtdbSub,
23
+ isAiSub,
24
+ isMessagingSub,
25
+ isPresenceSub,
26
+ } from '../protocol.js';
27
+ // The canonical agent tool dispatcher — reused on the worker so a bridged agent
28
+ // executes against THIS sandbox (one backend for app + Studio + agent), instead
29
+ // of a separate in-page sandbox.
30
+ import { buildSandboxDispatcher } from '../../../bridge/client/dispatch.js';
31
+ import { firebaseOptionsEqual } from 'pyric/app/internal';
32
+
33
+ import { activityJourneyId, type HostCtx, type PortLike, ok, fail } from '../host-context.js';
34
+ import {
35
+ authSubsFor,
36
+ isAuthOp,
37
+ handleAuthOp,
38
+ handleAuthSub,
39
+ handleAuthUnsub,
40
+ cleanupPortSession,
41
+ } from '../host-auth.js';
42
+ import {
43
+ eventSubsFor,
44
+ handleEventSub,
45
+ handleEventUnsub,
46
+ } from '../host-events.js';
47
+ import { isAiOp, handleAiOp, handleAiSub } from '../host-ai.js';
48
+ import {
49
+ isMessagingOp,
50
+ handleMessagingOp,
51
+ handleMessagingSub,
52
+ cleanupPortMessaging,
53
+ } from '../host-messaging.js';
54
+ import {
55
+ lensDb,
56
+ lensProvenance,
57
+ sessionDb,
58
+ opProvenance,
59
+ } from './core.js';
60
+ import { isFirestoreReadOp, handleFirestoreReadOp } from './firestore-reads.js';
61
+ import { isFirestoreWriteOp, handleFirestoreWriteOp } from './firestore-writes.js';
62
+ import { isRulesOp, handleRulesOp } from './rules.js';
63
+ import { isAdminFirestoreOp, handleAdminFirestoreOp } from './admin-firestore.js';
64
+ import { isRtdbOp, handleRtdbOp } from './rtdb.js';
65
+ import { isStorageOp, handleStorageOp } from './storage.js';
66
+ import { isConnectionOp, handleConnectionOp } from './connection.js';
67
+ import { isStudioOp, handleStudioOp } from './studio.js';
68
+ import {
69
+ isPresenceOp,
70
+ handlePresenceOp,
71
+ handlePresenceSub,
72
+ handlePresenceUnsub,
73
+ cleanupPortPresence,
74
+ } from './presence.js';
75
+ import { handleSub, handleRtdbSub, handleUnsub, dropPortSessionSubs } from './subscriptions.js';
76
+
77
+ function configConflictError(): Error & { code: string } {
78
+ return Object.assign(
79
+ new Error('Pyric currently supports one Firebase configuration per runtime'),
80
+ { code: 'app/multiple-configs-not-supported' },
81
+ );
82
+ }
83
+
84
+ // ─── Op orchestrator ────────────────────────────────────────────────────────
85
+
86
+ async function handleOp(ctx: HostCtx, port: PortLike, msg: OpMessage): Promise<void> {
87
+ // Explicit lens (Studio admin / as / app-session) → lensDb; no lens → the
88
+ // PORT'S SESSION (#754), so app ops run as whoever this tab signed in as.
89
+ const db = msg.actAs ? lensDb(ctx, msg.actAs) : sessionDb(ctx, port);
90
+ // Provenance the op runs under. Stamped onto the unified event stream's
91
+ // `authLens` by the emit path (C1 field / T1 emit). For `{ mode: 'as', uid }`
92
+ // the resolved `db` already carries `auth: { uid }`, so a rules eval emits
93
+ // under that identity; `lens` is the canonical normalised value the host
94
+ // hands forward when the explicit emit-time stamp seam exists (see lensProvenance).
95
+ const lens = lensProvenance(msg.actAs);
96
+ void lens;
97
+
98
+ // Firestore reads/writes run against the resolved `db` (lens/session)
99
+ // computed above; peeled off to their family modules.
100
+ if (isFirestoreReadOp(msg.method)) return handleFirestoreReadOp(ctx, port, msg, db);
101
+ if (isFirestoreWriteOp(msg.method)) return handleFirestoreWriteOp(ctx, port, msg, db);
102
+ if (isRulesOp(msg.method)) return handleRulesOp(ctx, port, msg, db);
103
+ if (isAdminFirestoreOp(msg.method)) return handleAdminFirestoreOp(ctx, port, msg);
104
+ if (isRtdbOp(msg.method)) return handleRtdbOp(ctx, port, msg);
105
+ if (isStorageOp(msg.method)) return handleStorageOp(ctx, port, msg);
106
+ if (isConnectionOp(msg.method)) return handleConnectionOp(ctx, port, msg);
107
+ if (isStudioOp(msg.method)) return handleStudioOp(ctx, port, msg);
108
+ if (isPresenceOp(msg.method)) return handlePresenceOp(ctx, port, msg);
109
+
110
+ // Auth (`auth.*`), AI (`ai.*`), and messaging (`messaging.*`) ops are routed
111
+ // to their handlers by dispatchMessage BEFORE reaching handleOp, so any
112
+ // method landing here is genuinely unknown.
113
+ fail(port, msg.id, new Error(`Unknown method: ${String((msg as { method: unknown }).method)}`));
114
+ }
115
+
116
+ // ─── Main dispatch ────────────────────────────────────────────────────────
117
+
118
+ /**
119
+ * Agent tool-call dispatch. The bridge peer forwards `tool` messages so the
120
+ * agent runs the canonical sandbox tool set against THIS worker's sandbox (the
121
+ * same instance the app + Studio use) instead of a separate in-page backend.
122
+ * Replies with a `res` whose value is the `{ ok, summary, data }` result.
123
+ */
124
+ async function handleTool(ctx: HostCtx, port: PortLike, msg: ToolMessage): Promise<void> {
125
+ try {
126
+ ctx.toolDispatch ??= buildSandboxDispatcher(ctx.sandbox);
127
+ const result = await ctx.toolDispatch(msg.name, msg.args ?? {});
128
+ // Pre-serialize via JSON BEFORE the structured-clone hop over the port. Read
129
+ // results carry real firebase wrapper instances (Timestamp/GeoPoint/Bytes/
130
+ // VectorValue) whose toJSON() produces the canonical agent-facing shapes.
131
+ // structuredClone would strip those prototypes (losing toJSON) and post
132
+ // mangled internals, and would throw DataCloneError on any non-cloneable
133
+ // field. JSON.stringify here runs toJSON() while the instances are intact and
134
+ // yields a plain, clone-safe object — matching the in-page path, which
135
+ // JSON-stringified at the bridge. A serialization error lands in the catch
136
+ // below, never in postMessage.
137
+ ok(port, msg.id, JSON.parse(JSON.stringify(result)));
138
+ } catch (e) {
139
+ fail(port, msg.id, e);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Handle one inbound message from a port.
145
+ *
146
+ * This is the primary unit-testable seam. Tests create a real `HostCtx`
147
+ * backed by an in-memory pyric sandbox and call this function directly
148
+ * with fake port objects, exercising the full op+subscription lifecycle
149
+ * without a real SharedWorker.
150
+ */
151
+ export async function handleMessage(
152
+ ctx: HostCtx,
153
+ port: PortLike,
154
+ msg: InboundMessage,
155
+ ): Promise<void> {
156
+ if (msg.t === 'appConfig') {
157
+ if (ctx.appOptions === undefined) {
158
+ ctx.appOptions = structuredClone(msg.options);
159
+ } else if (!firebaseOptionsEqual(ctx.appOptions, msg.options)) {
160
+ (ctx.rejectedConfigPorts ??= new WeakSet()).add(port);
161
+ }
162
+ return;
163
+ }
164
+ // A rejected app port still owns host-side resources until its explicit
165
+ // disconnect handshake completes. Never swallow that teardown frame.
166
+ if (ctx.rejectedConfigPorts?.has(port) && msg.t !== 'disconnect') {
167
+ if (msg.t === 'op' || msg.t === 'tool') {
168
+ fail(port, msg.id, configConflictError());
169
+ } else if (msg.t === 'sub' && msg.target !== 'events') {
170
+ const error = configConflictError();
171
+ port.postMessage({
172
+ t: 'snap',
173
+ subId: msg.subId,
174
+ value: { __error: { code: error.code, message: error.message } },
175
+ });
176
+ }
177
+ return;
178
+ }
179
+ if (ctx.disconnectedPorts?.has(port) && msg.t !== 'disconnect') {
180
+ if (msg.t === 'op' || msg.t === 'tool') {
181
+ fail(
182
+ port,
183
+ msg.id,
184
+ Object.assign(new Error('Firebase App was deleted'), { code: 'app/app-deleted' }),
185
+ );
186
+ }
187
+ return;
188
+ }
189
+ // Op provenance, bound at dispatch by `opProvenance` (see its docs). Opened
190
+ // as the sandbox's SYNCHRONOUS ambient window so firestore/rtdb/auth emits —
191
+ // which run inside `dispatchMessage` before any await — pick it up. Storage
192
+ // ops emit AFTER async awaits, outside this window, so they thread the same
193
+ // provenance EXPLICITLY instead (see `handleOp`'s storage cases). Without the
194
+ // lens on admin ops, `verdictFor` mislabeled a rules BYPASS as ALLOW (the
195
+ // RTDB/Firestore asymmetry the traffic-metrics work flagged).
196
+ const isRemoteRelay = (msg as { relaySource?: 'remote' }).relaySource === 'remote';
197
+ const tracksFirestoreActivity = !isRemoteRelay && (msg.t === 'op'
198
+ ? isFirestoreReadOp(msg.method)
199
+ : msg.t === 'sub'
200
+ && msg.target !== null
201
+ && typeof msg.target === 'object'
202
+ && '__ref' in msg.target);
203
+ const prov = opProvenance(
204
+ msg,
205
+ tracksFirestoreActivity ? activityJourneyId(ctx, port) : undefined,
206
+ );
207
+ if (prov && ctx.sandbox.runWithProvenance) {
208
+ return ctx.sandbox.runWithProvenance(prov, () => dispatchMessage(ctx, port, msg));
209
+ }
210
+ return dispatchMessage(ctx, port, msg);
211
+ }
212
+
213
+ async function dispatchMessage(
214
+ ctx: HostCtx,
215
+ port: PortLike,
216
+ msg: InboundMessage,
217
+ ): Promise<void> {
218
+ if (msg.t === 'op') {
219
+ if (isAuthOp(msg.method)) {
220
+ await handleAuthOp(ctx, port, msg);
221
+ } else if (isAiOp(msg.method)) {
222
+ await handleAiOp(ctx, port, msg);
223
+ } else if (isMessagingOp(msg.method)) {
224
+ await handleMessagingOp(ctx, port, msg);
225
+ } else {
226
+ await handleOp(ctx, port, msg);
227
+ }
228
+ } else if (msg.t === 'sub') {
229
+ if (isAuthSub(msg)) {
230
+ handleAuthSub(ctx, port, msg);
231
+ } else if (isEventSub(msg)) {
232
+ handleEventSub(ctx, port, msg);
233
+ } else if (isRtdbSub(msg)) {
234
+ handleRtdbSub(ctx, port, msg);
235
+ } else if (isAiSub(msg)) {
236
+ // AI streams are FINITE subs registered in ctx.subs (so `unsub` cancels
237
+ // them); they auto-unsub on the terminal done/error snap. host-ai.ts.
238
+ handleAiSub(ctx, port, msg);
239
+ } else if (isMessagingSub(msg)) {
240
+ handleMessagingSub(ctx, port, msg);
241
+ } else if (isPresenceSub(msg)) {
242
+ handlePresenceSub(ctx, port, msg);
243
+ } else {
244
+ handleSub(ctx, port, msg);
245
+ }
246
+ } else if (msg.t === 'unsub') {
247
+ // An unsub may target an auth sub, an event-stream sub, a presence sub, or
248
+ // a Firestore listener — try the cheap routing registries first, then fall
249
+ // through to the Firestore listener teardown.
250
+ if (
251
+ !handleAuthUnsub(ctx, port, msg.subId) &&
252
+ !handleEventUnsub(ctx, port, msg.subId) &&
253
+ !handlePresenceUnsub(ctx, port, msg.subId)
254
+ ) {
255
+ handleUnsub(ctx, port, msg);
256
+ }
257
+ } else if (msg.t === 'disconnect') {
258
+ try {
259
+ cleanupPort(ctx, port);
260
+ ok(port, msg.id, undefined);
261
+ } catch (error) {
262
+ fail(port, msg.id, error);
263
+ }
264
+ } else if (msg.t === 'tool') {
265
+ await handleTool(ctx, port, msg);
266
+ }
267
+ }
268
+
269
+ // ─── Port cleanup ─────────────────────────────────────────────────────────
270
+
271
+ /**
272
+ * Tear down all subscriptions for a disconnected port.
273
+ * Called when a port's `close` event fires (browser best-effort) or
274
+ * when the entry point explicitly cleans up a port.
275
+ */
276
+ export function cleanupPort(ctx: HostCtx, port: PortLike): void {
277
+ (ctx.disconnectedPorts ??= new WeakSet()).add(port);
278
+ const failures: unknown[] = [];
279
+ const attempt = (cleanup: () => void): void => {
280
+ try {
281
+ cleanup();
282
+ } catch (error) {
283
+ failures.push(error);
284
+ }
285
+ };
286
+ // Drop the port's auth subscriptions (routing entries — no real listener
287
+ // to tear down), its per-port session, and its session-bound sub records
288
+ // (#754).
289
+ attempt(() => { authSubsFor(ctx).delete(port); });
290
+ attempt(() => { cleanupPortSession(ctx, port); });
291
+ attempt(() => { dropPortSessionSubs(ctx, port); });
292
+
293
+ // Drop the port's event-stream subscriptions too (also routing entries off
294
+ // the single shared `sandbox.onEvent` subscription — nothing to unsubscribe,
295
+ // just stop fanning out to a dead port).
296
+ attempt(() => { eventSubsFor(ctx).delete(port); });
297
+
298
+ // Drop the port's messaging broker client so a closed tab's last-reported
299
+ // visibility stops feeding the routing rule. Its delivery-handler unsubs
300
+ // live in `ctx.subs` and are torn down with the loop below.
301
+ attempt(() => { cleanupPortMessaging(ctx, port); });
302
+
303
+ // Presence: best-effort remove this port's logical client when it was the
304
+ // last association (lease expiry remains the correctness path).
305
+ attempt(() => { cleanupPortPresence(ctx, port); });
306
+
307
+ const portSubs = ctx.subs.get(port);
308
+ if (portSubs) {
309
+ for (const unsub of portSubs.values()) attempt(unsub);
310
+ ctx.subs.delete(port);
311
+ }
312
+ if (failures.length === 1) throw failures[0];
313
+ if (failures.length > 1) {
314
+ throw new AggregateError(failures, 'Multiple SharedWorker port resources failed to tear down');
315
+ }
316
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * SharedWorker host — Firestore read + aggregate + keyspace ops.
3
+ *
4
+ * The rule-gated read surface: `getDoc`/`getDocs`, the `count`/`aggregate`
5
+ * server aggregations, and the lens-independent keyspace enumeration
6
+ * (`listRootCollections`/`listSubcollections`, the Pyric Studio data browse).
7
+ *
8
+ * Routed here by the host dispatcher (host/dispatch.ts) with the op's resolved
9
+ * Firestore handle (`db` — already lens/session-resolved). This module never
10
+ * imports the dispatcher; it leans only on host-context + host/core.
11
+ */
12
+
13
+ import {
14
+ doc as pyricDoc,
15
+ getDoc,
16
+ getDocs,
17
+ getCountFromServer,
18
+ getAggregateFromServer,
19
+ type AggregateSpec,
20
+ type Firestore,
21
+ type Query,
22
+ } from 'pyric/firestore';
23
+ import { getInternalEnv } from 'pyric/sandbox/internal';
24
+
25
+ import type { OpMessage } from '../protocol.js';
26
+ import { type HostCtx, type PortLike, ok, fail } from '../host-context.js';
27
+ import { resolveTarget, serializeDocSnap } from './core.js';
28
+
29
+ /** The read/aggregate/keyspace op methods routed to {@link handleFirestoreReadOp}. */
30
+ const READ_METHODS = new Set<string>([
31
+ 'getDoc',
32
+ 'getDocs',
33
+ 'count',
34
+ 'aggregate',
35
+ 'listRootCollections',
36
+ 'listSubcollections',
37
+ ]);
38
+
39
+ export function isFirestoreReadOp(method: OpMessage['method']): boolean {
40
+ return READ_METHODS.has(method);
41
+ }
42
+
43
+ export async function handleFirestoreReadOp(
44
+ ctx: HostCtx,
45
+ port: PortLike,
46
+ msg: OpMessage,
47
+ db: Firestore,
48
+ ): Promise<void> {
49
+ const { sandbox } = ctx;
50
+ switch (msg.method) {
51
+ case 'getDoc': {
52
+ try {
53
+ const ref = pyricDoc(db, msg.path);
54
+ const snap = await getDoc(ref);
55
+ ok(port, msg.id, serializeDocSnap(snap as Parameters<typeof serializeDocSnap>[0]));
56
+ } catch (e) { fail(port, msg.id, e); }
57
+ break;
58
+ }
59
+
60
+ case 'getDocs': {
61
+ try {
62
+ const source = resolveTarget(db, msg.source);
63
+ // CollectionReference is always also queryable — getDocs accepts Query<T>
64
+ // and CollectionReference is structurally compatible at runtime even though
65
+ // the type system doesn't know that (CollectionReference has no `_isQuery`
66
+ // brand). Cast through Query to satisfy the type checker.
67
+ const snap = await getDocs(source as Query);
68
+ const docs = snap.docs.map((d) =>
69
+ serializeDocSnap(d as Parameters<typeof serializeDocSnap>[0]),
70
+ );
71
+ ok(port, msg.id, { docs });
72
+ } catch (e) { fail(port, msg.id, e); }
73
+ break;
74
+ }
75
+
76
+ case 'count': {
77
+ try {
78
+ const source = resolveTarget(db, msg.source);
79
+ const snap = await getCountFromServer(source as Query);
80
+ ok(port, msg.id, { count: snap.data().count });
81
+ } catch (e) { fail(port, msg.id, e); }
82
+ break;
83
+ }
84
+
85
+ case 'aggregate': {
86
+ // Multi-field aggregates (count/sum/average). The wire spec is
87
+ // structurally pyric/firestore's AggregateSpec, so it passes straight
88
+ // through; the reply data is plain numbers / null (empty-input average).
89
+ try {
90
+ const source = resolveTarget(db, msg.source);
91
+ const snap = await getAggregateFromServer(source as Query, msg.spec as AggregateSpec);
92
+ ok(port, msg.id, { data: snap.data() });
93
+ } catch (e) { fail(port, msg.id, e); }
94
+ break;
95
+ }
96
+
97
+ case 'listRootCollections': {
98
+ // Keyspace enumeration (Pyric Studio data browse). Lens-independent: it
99
+ // lists the collection ids present, not rule-gated reads.
100
+ try {
101
+ ok(port, msg.id, { ids: getInternalEnv(sandbox).listRootCollections() });
102
+ } catch (e) { fail(port, msg.id, e); }
103
+ break;
104
+ }
105
+
106
+ case 'listSubcollections': {
107
+ try {
108
+ ok(port, msg.id, { ids: getInternalEnv(sandbox).listSubcollections(msg.docPath) });
109
+ } catch (e) { fail(port, msg.id, e); }
110
+ break;
111
+ }
112
+
113
+ default: {
114
+ fail(port, msg.id, new Error(`Unknown method: ${String((msg as { method: unknown }).method)}`));
115
+ }
116
+ }
117
+ }