@pyric/cli 0.1.0-alpha.14 → 0.1.0-alpha.15

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 (599) hide show
  1. package/dist/assurance/.generated/conformance-verdicts.d.ts +120 -75
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  3. package/dist/assurance/.generated/conformance-verdicts.js +120 -75
  4. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  5. package/dist/cli/serve.d.ts +1 -1
  6. package/dist/cli/serve.d.ts.map +1 -1
  7. package/dist/cli/serve.js +207 -284
  8. package/dist/cli/serve.js.map +1 -1
  9. package/dist/cli/service-command-records/database-rules-generate.d.ts +4 -0
  10. package/dist/cli/service-command-records/database-rules-generate.d.ts.map +1 -0
  11. package/dist/cli/service-command-records/database-rules-generate.js +3 -0
  12. package/dist/cli/service-command-records/database-rules-generate.js.map +1 -0
  13. package/dist/cli/service-command-records/database-rules-lint.d.ts +4 -0
  14. package/dist/cli/service-command-records/database-rules-lint.d.ts.map +1 -0
  15. package/dist/cli/service-command-records/database-rules-lint.js +3 -0
  16. package/dist/cli/service-command-records/database-rules-lint.js.map +1 -0
  17. package/dist/cli/service-command-records/database-rules-simulate.d.ts +4 -0
  18. package/dist/cli/service-command-records/database-rules-simulate.d.ts.map +1 -0
  19. package/dist/cli/service-command-records/database-rules-simulate.js +3 -0
  20. package/dist/cli/service-command-records/database-rules-simulate.js.map +1 -0
  21. package/dist/cli/service-command-records/database-rules-validate.d.ts +4 -0
  22. package/dist/cli/service-command-records/database-rules-validate.d.ts.map +1 -0
  23. package/dist/cli/service-command-records/database-rules-validate.js +3 -0
  24. package/dist/cli/service-command-records/database-rules-validate.js.map +1 -0
  25. package/dist/cli/service-command-records/firestore-indexes-generate.d.ts +4 -0
  26. package/dist/cli/service-command-records/firestore-indexes-generate.d.ts.map +1 -0
  27. package/dist/cli/service-command-records/firestore-indexes-generate.js +3 -0
  28. package/dist/cli/service-command-records/firestore-indexes-generate.js.map +1 -0
  29. package/dist/cli/service-command-records/firestore-rules-lint.d.ts +4 -0
  30. package/dist/cli/service-command-records/firestore-rules-lint.d.ts.map +1 -0
  31. package/dist/cli/service-command-records/firestore-rules-lint.js +3 -0
  32. package/dist/cli/service-command-records/firestore-rules-lint.js.map +1 -0
  33. package/dist/cli/service-command-records/firestore-rules-resolve.d.ts +4 -0
  34. package/dist/cli/service-command-records/firestore-rules-resolve.d.ts.map +1 -0
  35. package/dist/cli/service-command-records/firestore-rules-resolve.js +3 -0
  36. package/dist/cli/service-command-records/firestore-rules-resolve.js.map +1 -0
  37. package/dist/cli/service-command-records/firestore-rules-simulate.d.ts +4 -0
  38. package/dist/cli/service-command-records/firestore-rules-simulate.d.ts.map +1 -0
  39. package/dist/cli/service-command-records/firestore-rules-simulate.js +3 -0
  40. package/dist/cli/service-command-records/firestore-rules-simulate.js.map +1 -0
  41. package/dist/cli/service-command-records/firestore-rules-validate.d.ts +4 -0
  42. package/dist/cli/service-command-records/firestore-rules-validate.d.ts.map +1 -0
  43. package/dist/cli/service-command-records/firestore-rules-validate.js +3 -0
  44. package/dist/cli/service-command-records/firestore-rules-validate.js.map +1 -0
  45. package/dist/cli/service-command-records/storage-rules-lint.d.ts +4 -0
  46. package/dist/cli/service-command-records/storage-rules-lint.d.ts.map +1 -0
  47. package/dist/cli/service-command-records/storage-rules-lint.js +3 -0
  48. package/dist/cli/service-command-records/storage-rules-lint.js.map +1 -0
  49. package/dist/cli/service-command-records/storage-rules-simulate.d.ts +4 -0
  50. package/dist/cli/service-command-records/storage-rules-simulate.d.ts.map +1 -0
  51. package/dist/cli/service-command-records/storage-rules-simulate.js +3 -0
  52. package/dist/cli/service-command-records/storage-rules-simulate.js.map +1 -0
  53. package/dist/cli/service-commands.d.ts +7 -0
  54. package/dist/cli/service-commands.d.ts.map +1 -1
  55. package/dist/cli/service-commands.generated.d.ts +35 -0
  56. package/dist/cli/service-commands.generated.d.ts.map +1 -0
  57. package/dist/cli/service-commands.generated.js +25 -0
  58. package/dist/cli/service-commands.generated.js.map +1 -0
  59. package/dist/cli/service-commands.js +23 -40
  60. package/dist/cli/service-commands.js.map +1 -1
  61. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  62. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  63. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  64. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  65. package/dist/conformance/.generated/can-i-use.js +1 -1
  66. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  67. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
  68. package/dist/conformance/.generated/conformance-docs.js +1 -1
  69. package/dist/conformance/.generated/conformance-docs.js.map +1 -1
  70. package/dist/functions-rtdb/development-runtime.d.ts +63 -0
  71. package/dist/functions-rtdb/development-runtime.d.ts.map +1 -0
  72. package/dist/functions-rtdb/development-runtime.js +244 -0
  73. package/dist/functions-rtdb/development-runtime.js.map +1 -0
  74. package/dist/serve/bridge-mount.d.ts +32 -2
  75. package/dist/serve/bridge-mount.d.ts.map +1 -1
  76. package/dist/serve/bridge-mount.js +232 -18
  77. package/dist/serve/bridge-mount.js.map +1 -1
  78. package/dist/serve/bundler.d.ts +2 -18
  79. package/dist/serve/bundler.d.ts.map +1 -1
  80. package/dist/serve/bundler.js +7 -35
  81. package/dist/serve/bundler.js.map +1 -1
  82. package/dist/serve/entries/app-client.d.ts.map +1 -1
  83. package/dist/serve/entries/app-client.js +5 -5
  84. package/dist/serve/entries/app-client.js.map +1 -1
  85. package/dist/serve/entries/auth-helper-core.d.ts +23 -6
  86. package/dist/serve/entries/auth-helper-core.d.ts.map +1 -1
  87. package/dist/serve/entries/auth-helper-core.js +55 -24
  88. package/dist/serve/entries/auth-helper-core.js.map +1 -1
  89. package/dist/serve/entries/database.d.ts +28 -0
  90. package/dist/serve/entries/database.d.ts.map +1 -1
  91. package/dist/serve/entries/database.js +95 -26
  92. package/dist/serve/entries/database.js.map +1 -1
  93. package/dist/serve/entries/init.d.ts.map +1 -1
  94. package/dist/serve/entries/init.js +21 -12
  95. package/dist/serve/entries/init.js.map +1 -1
  96. package/dist/serve/html-injection.d.ts +5 -0
  97. package/dist/serve/html-injection.d.ts.map +1 -0
  98. package/dist/serve/html-injection.js +59 -0
  99. package/dist/serve/html-injection.js.map +1 -0
  100. package/dist/serve/namespace.d.ts +6 -22
  101. package/dist/serve/namespace.d.ts.map +1 -1
  102. package/dist/serve/namespace.js +23 -145
  103. package/dist/serve/namespace.js.map +1 -1
  104. package/dist/serve/runtime/worker-replacement.d.ts +1 -2
  105. package/dist/serve/runtime/worker-replacement.d.ts.map +1 -1
  106. package/dist/serve/sandbox-session.d.ts +78 -0
  107. package/dist/serve/sandbox-session.d.ts.map +1 -0
  108. package/dist/serve/sandbox-session.js +171 -0
  109. package/dist/serve/sandbox-session.js.map +1 -0
  110. package/dist/serve/server.d.ts +5 -2
  111. package/dist/serve/server.d.ts.map +1 -1
  112. package/dist/serve/server.js +21 -5
  113. package/dist/serve/server.js.map +1 -1
  114. package/dist/serve/site-tree.d.ts +8 -0
  115. package/dist/serve/site-tree.d.ts.map +1 -0
  116. package/dist/serve/site-tree.js +113 -0
  117. package/dist/serve/site-tree.js.map +1 -0
  118. package/dist/serve/site-ui/_astro/RulesCodeEditor.CzwHdCi9.js +23 -0
  119. package/dist/serve/site-ui/_astro/_example_.jevZ7OdV.css +1 -0
  120. package/dist/serve/site-ui/_astro/_slug_.BoKXYrnu.css +1 -0
  121. package/dist/serve/site-ui/_astro/_studio_.BtYpqe1A.css +1 -0
  122. package/dist/serve/site-ui/_astro/app.BnMC0ywl.js +109 -0
  123. package/dist/serve/site-ui/_astro/app.BsFsMjn0.css +1 -0
  124. package/dist/serve/site-ui/_astro/app.DVXXR-WI.js +1 -0
  125. package/dist/serve/site-ui/_astro/chess-showcase.DzPO6kz0.js +1 -0
  126. package/dist/serve/site-ui/_astro/chess-source-explorer.C5k9c5yK.js +1 -0
  127. package/dist/serve/site-ui/_astro/chess-v2.CFHmd3UL.js +354 -0
  128. package/dist/serve/site-ui/_astro/client.D2ORs4B-.js +25 -0
  129. package/dist/serve/site-ui/_astro/example-runtime.CM0H02rx.js +291 -0
  130. package/dist/serve/site-ui/_astro/index.B4Kh80he.js +1 -0
  131. package/dist/serve/site-ui/_astro/index.DBy5LfQW.js +9 -0
  132. package/dist/serve/site-ui/_astro/index.DNyk7q8W.js +9 -0
  133. package/dist/serve/site-ui/_astro/jsx-runtime.D_zvdyIk.js +9 -0
  134. package/dist/serve/site-ui/_astro/reads.D1exkX1-.js +1 -0
  135. package/dist/serve/site-ui/_astro/sandbox-controls.BqMePr5V.js +1153 -0
  136. package/dist/serve/site-ui/_astro/seed.BCn5DhHS.js +20 -0
  137. package/dist/serve/site-ui/auth/index.html +11 -0
  138. package/dist/serve/site-ui/docs/_rhythm/index.html +100 -0
  139. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +43 -0
  140. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +26 -0
  141. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +70 -0
  142. package/dist/serve/{docs-ui → site-ui}/docs/ai-compat/index.html +3 -3
  143. package/dist/serve/site-ui/docs/api-reference/index.html +68 -0
  144. package/dist/serve/{docs-ui → site-ui}/docs/app-compat/index.html +3 -3
  145. package/dist/serve/{docs-ui → site-ui}/docs/auth-compat/index.html +3 -3
  146. package/dist/serve/site-ui/docs/build/ai-logic/index.html +64 -0
  147. package/dist/serve/site-ui/docs/build/authentication/index.html +66 -0
  148. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +84 -0
  149. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +71 -0
  150. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +66 -0
  151. package/dist/serve/{docs-ui → site-ui}/docs/build/cloud-storage.md +2 -2
  152. package/dist/serve/site-ui/docs/build/realtime-database/index.html +67 -0
  153. package/dist/serve/site-ui/docs/conformance-scores/index.html +50 -0
  154. package/dist/serve/{docs-ui → site-ui}/docs/conformance-scores.md +3 -3
  155. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +531 -0
  156. package/dist/serve/{docs-ui → site-ui}/docs/database-compat/index.html +211 -168
  157. package/dist/serve/{docs-ui → site-ui}/docs/database-compat.md +208 -170
  158. package/dist/serve/site-ui/docs/examples/chess/index.html +384 -0
  159. package/dist/serve/site-ui/docs/examples/chess.md +57 -0
  160. package/dist/serve/site-ui/docs/examples/index.html +3 -0
  161. package/dist/serve/site-ui/docs/examples.md +4 -0
  162. package/dist/serve/{docs-ui → site-ui}/docs/firestore-compat/index.html +55 -91
  163. package/dist/serve/{docs-ui → site-ui}/docs/firestore-compat.md +52 -88
  164. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +73 -0
  165. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +29 -0
  166. package/dist/serve/site-ui/docs/get-started/start-building/index.html +33 -0
  167. package/dist/serve/{docs-ui → site-ui}/docs/index.json +595 -26
  168. package/dist/serve/site-ui/docs/messaging-compat/index.html +324 -0
  169. package/dist/serve/{docs-ui → site-ui}/docs/messaging-compat.md +71 -1
  170. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +28 -0
  171. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +74 -0
  172. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +45 -0
  173. package/dist/serve/site-ui/docs/overview/index.html +17 -0
  174. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +186 -0
  175. package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-auth-reference-api/index.html +4 -4
  176. package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-database-reference-api/index.html +4 -4
  177. package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-firestore-reference-api/index.html +318 -202
  178. package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-firestore-reference-api.md +154 -27
  179. package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-messaging-reference-api/index.html +5 -5
  180. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +318 -0
  181. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ai-reference-api/index.html +5 -5
  182. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +160 -0
  183. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +425 -0
  184. package/dist/serve/{docs-ui → site-ui}/docs/pyric-auth-reference-api/index.html +5 -5
  185. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +60 -0
  186. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-assurance-reference-api/index.html +4 -4
  187. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-bridge-client-reference-api/index.html +4 -4
  188. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +507 -0
  189. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +258 -0
  190. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +51 -0
  191. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +308 -0
  192. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +68 -0
  193. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-discover-reference-api/index.html +4 -4
  194. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +11 -0
  195. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-remote-reference-api/index.html +4 -4
  196. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-serve-worker-reference-api/index.html +1186 -1384
  197. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-serve-worker-reference-api.md +817 -1291
  198. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-verify-reference-api/index.html +4 -4
  199. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +126 -0
  200. package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-vite-reference-api.md +1 -1
  201. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +2641 -0
  202. package/dist/serve/{docs-ui → site-ui}/docs/pyric-database-reference-api.md +1055 -158
  203. package/dist/serve/{docs-ui → site-ui}/docs/pyric-firestore-reference-api/index.html +311 -249
  204. package/dist/serve/{docs-ui → site-ui}/docs/pyric-firestore-reference-api.md +72 -54
  205. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +509 -0
  206. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +182 -0
  207. package/dist/serve/{docs-ui → site-ui}/docs/pyric-rules-reference-api/index.html +7 -26
  208. package/dist/serve/{docs-ui → site-ui}/docs/pyric-rules-reference-api.md +13 -23
  209. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +121 -0
  210. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +203 -0
  211. package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-reference-api/index.html +26 -5
  212. package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-reference-api.md +22 -22
  213. package/dist/serve/{docs-ui → site-ui}/docs/pyric-storage-reference-api/index.html +5 -15
  214. package/dist/serve/{docs-ui → site-ui}/docs/pyric-storage-reference-api.md +0 -13
  215. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +639 -0
  216. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +100 -0
  217. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-auth-reference-api/index.html +4 -4
  218. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +24 -0
  219. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-events-reference-api/index.html +4 -4
  220. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +136 -0
  221. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-firestore-reference-api/index.html +7 -7
  222. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-firestore-reference-api.md +4 -4
  223. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-primitives-reference-api/index.html +4 -4
  224. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rtdb-reference-api/index.html +4 -4
  225. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +16 -0
  226. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rules-reference-api/index.html +4 -4
  227. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +176 -0
  228. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-storage-reference-api/index.html +10 -11
  229. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-storage-reference-api.md +7 -8
  230. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +188 -0
  231. package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-traffic-reference-api/index.html +4 -4
  232. package/dist/serve/{docs-ui → site-ui}/docs/rules-compat/index.html +87 -57
  233. package/dist/serve/{docs-ui → site-ui}/docs/rules-compat.md +84 -54
  234. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +51 -0
  235. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +106 -0
  236. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +41 -0
  237. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +67 -0
  238. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +159 -0
  239. package/dist/serve/{docs-ui → site-ui}/docs/secure/rules-standard-library.md +2 -2
  240. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +47 -0
  241. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +95 -0
  242. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +82 -0
  243. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +37 -0
  244. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +75 -0
  245. package/dist/serve/{docs-ui → site-ui}/docs/storage-compat/index.html +8 -8
  246. package/dist/serve/{docs-ui → site-ui}/docs/storage-compat.md +5 -5
  247. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +132 -0
  248. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +861 -0
  249. package/dist/serve/site-ui/docs/trust/rules-standard-library.md +344 -0
  250. package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +582 -0
  251. package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research.md +448 -0
  252. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +14 -0
  253. package/dist/serve/{docs-ui → site-ui}/docs/tutorial/index.html +4 -4
  254. package/dist/serve/{docs-ui → site-ui}/docs/tutorial.md +1 -1
  255. package/dist/serve/site-ui/examples/chess/index.html +2 -0
  256. package/dist/serve/site-ui/examples/firestore-first-write/index.html +2 -0
  257. package/dist/serve/site-ui/firestore/index.html +11 -0
  258. package/dist/serve/site-ui/index.html +11 -0
  259. package/dist/serve/{docs-ui → site-ui}/llms.txt +6 -2
  260. package/dist/serve/site-ui/rtdb/index.html +11 -0
  261. package/dist/serve/site-ui/settings/index.html +11 -0
  262. package/dist/serve/site-ui/storage/index.html +11 -0
  263. package/dist/serve/site-ui/studio-routes.json +1 -0
  264. package/dist/serve/site-ui/traffic/index.html +11 -0
  265. package/dist/serve/standalone-assets.d.ts +4 -10
  266. package/dist/serve/standalone-assets.d.ts.map +1 -1
  267. package/dist/serve/standalone-assets.js +8 -21
  268. package/dist/serve/standalone-assets.js.map +1 -1
  269. package/dist/serve/vite-functions-development.d.ts +29 -0
  270. package/dist/serve/vite-functions-development.d.ts.map +1 -0
  271. package/dist/serve/vite-functions-development.js +150 -0
  272. package/dist/serve/vite-functions-development.js.map +1 -0
  273. package/dist/serve/vite-generation-bridge.d.ts +17 -0
  274. package/dist/serve/vite-generation-bridge.d.ts.map +1 -0
  275. package/dist/serve/vite-generation-bridge.js +47 -0
  276. package/dist/serve/vite-generation-bridge.js.map +1 -0
  277. package/dist/serve/vite-generation-functions.d.ts +35 -0
  278. package/dist/serve/vite-generation-functions.d.ts.map +1 -0
  279. package/dist/serve/vite-generation-functions.js +46 -0
  280. package/dist/serve/vite-generation-functions.js.map +1 -0
  281. package/dist/serve/vite-generation-middleware.d.ts +10 -0
  282. package/dist/serve/vite-generation-middleware.d.ts.map +1 -0
  283. package/dist/serve/vite-generation-middleware.js +40 -0
  284. package/dist/serve/vite-generation-middleware.js.map +1 -0
  285. package/dist/serve/vite-generation-rules-watch.d.ts +8 -0
  286. package/dist/serve/vite-generation-rules-watch.d.ts.map +1 -0
  287. package/dist/serve/vite-generation-rules-watch.js +33 -0
  288. package/dist/serve/vite-generation-rules-watch.js.map +1 -0
  289. package/dist/serve/vite-module-swap.d.ts +16 -0
  290. package/dist/serve/vite-module-swap.d.ts.map +1 -0
  291. package/dist/serve/vite-module-swap.js +96 -0
  292. package/dist/serve/vite-module-swap.js.map +1 -0
  293. package/dist/serve/vite-page-runtime.d.ts +29 -0
  294. package/dist/serve/vite-page-runtime.d.ts.map +1 -0
  295. package/dist/serve/vite-page-runtime.js +71 -0
  296. package/dist/serve/vite-page-runtime.js.map +1 -0
  297. package/dist/serve/vite-plugin.d.ts +44 -4
  298. package/dist/serve/vite-plugin.d.ts.map +1 -1
  299. package/dist/serve/vite-plugin.js +62 -864
  300. package/dist/serve/vite-plugin.js.map +1 -1
  301. package/dist/serve/vite-sandbox-generation.d.ts +57 -0
  302. package/dist/serve/vite-sandbox-generation.d.ts.map +1 -0
  303. package/dist/serve/vite-sandbox-generation.js +178 -0
  304. package/dist/serve/vite-sandbox-generation.js.map +1 -0
  305. package/dist/serve/worker/client/disconnect.d.ts.map +1 -1
  306. package/dist/serve/worker/client/disconnect.js +2 -0
  307. package/dist/serve/worker/client/disconnect.js.map +1 -1
  308. package/dist/serve/worker/client/handles.d.ts +5 -0
  309. package/dist/serve/worker/client/handles.d.ts.map +1 -1
  310. package/dist/serve/worker/client/handles.js.map +1 -1
  311. package/dist/serve/worker/client/pagehide.d.ts +13 -0
  312. package/dist/serve/worker/client/pagehide.d.ts.map +1 -0
  313. package/dist/serve/worker/client/pagehide.js +19 -0
  314. package/dist/serve/worker/client/pagehide.js.map +1 -0
  315. package/dist/serve/worker/client/rtdb-admin.d.ts +8 -0
  316. package/dist/serve/worker/client/rtdb-admin.d.ts.map +1 -0
  317. package/dist/serve/worker/client/rtdb-admin.js +39 -0
  318. package/dist/serve/worker/client/rtdb-admin.js.map +1 -0
  319. package/dist/serve/worker/client/rtdb-connection-lifecycle.d.ts +15 -0
  320. package/dist/serve/worker/client/rtdb-connection-lifecycle.d.ts.map +1 -0
  321. package/dist/serve/worker/client/rtdb-connection-lifecycle.js +45 -0
  322. package/dist/serve/worker/client/rtdb-connection-lifecycle.js.map +1 -0
  323. package/dist/serve/worker/client/rtdb-controls.d.ts +6 -0
  324. package/dist/serve/worker/client/rtdb-controls.d.ts.map +1 -0
  325. package/dist/serve/worker/client/rtdb-controls.js +8 -0
  326. package/dist/serve/worker/client/rtdb-controls.js.map +1 -0
  327. package/dist/serve/worker/client/rtdb-listeners.d.ts +24 -0
  328. package/dist/serve/worker/client/rtdb-listeners.d.ts.map +1 -0
  329. package/dist/serve/worker/client/rtdb-listeners.js +262 -0
  330. package/dist/serve/worker/client/rtdb-listeners.js.map +1 -0
  331. package/dist/serve/worker/client/rtdb-reads.d.ts +4 -0
  332. package/dist/serve/worker/client/rtdb-reads.d.ts.map +1 -0
  333. package/dist/serve/worker/client/rtdb-reads.js +11 -0
  334. package/dist/serve/worker/client/rtdb-reads.js.map +1 -0
  335. package/dist/serve/worker/client/rtdb-references.d.ts +19 -0
  336. package/dist/serve/worker/client/rtdb-references.d.ts.map +1 -0
  337. package/dist/serve/worker/client/rtdb-references.js +63 -0
  338. package/dist/serve/worker/client/rtdb-references.js.map +1 -0
  339. package/dist/serve/worker/client/rtdb-snapshots.d.ts +20 -0
  340. package/dist/serve/worker/client/rtdb-snapshots.d.ts.map +1 -0
  341. package/dist/serve/worker/client/rtdb-snapshots.js +64 -0
  342. package/dist/serve/worker/client/rtdb-snapshots.js.map +1 -0
  343. package/dist/serve/worker/client/rtdb-transactions.d.ts +14 -0
  344. package/dist/serve/worker/client/rtdb-transactions.d.ts.map +1 -0
  345. package/dist/serve/worker/client/rtdb-transactions.js +34 -0
  346. package/dist/serve/worker/client/rtdb-transactions.js.map +1 -0
  347. package/dist/serve/worker/client/rtdb-writes.d.ts +8 -0
  348. package/dist/serve/worker/client/rtdb-writes.d.ts.map +1 -0
  349. package/dist/serve/worker/client/rtdb-writes.js +65 -0
  350. package/dist/serve/worker/client/rtdb-writes.js.map +1 -0
  351. package/dist/serve/worker/client.d.ts +0 -2
  352. package/dist/serve/worker/client.d.ts.map +1 -1
  353. package/dist/serve/worker/client.js +0 -2
  354. package/dist/serve/worker/client.js.map +1 -1
  355. package/dist/serve/worker/entry.js +2 -2
  356. package/dist/serve/worker/entry.js.map +1 -1
  357. package/dist/serve/worker/host/dispatch.d.ts +2 -0
  358. package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
  359. package/dist/serve/worker/host/dispatch.js +24 -2
  360. package/dist/serve/worker/host/dispatch.js.map +1 -1
  361. package/dist/serve/worker/host/rtdb.d.ts +6 -2
  362. package/dist/serve/worker/host/rtdb.d.ts.map +1 -1
  363. package/dist/serve/worker/host/rtdb.js +224 -2
  364. package/dist/serve/worker/host/rtdb.js.map +1 -1
  365. package/dist/serve/worker/host/studio.d.ts.map +1 -1
  366. package/dist/serve/worker/host/studio.js +2 -0
  367. package/dist/serve/worker/host/studio.js.map +1 -1
  368. package/dist/serve/worker/host/subscriptions.d.ts.map +1 -1
  369. package/dist/serve/worker/host/subscriptions.js +3 -3
  370. package/dist/serve/worker/host/subscriptions.js.map +1 -1
  371. package/dist/serve/worker/host.d.ts +1 -1
  372. package/dist/serve/worker/host.d.ts.map +1 -1
  373. package/dist/serve/worker/host.js +1 -1
  374. package/dist/serve/worker/host.js.map +1 -1
  375. package/dist/serve/worker/index.d.ts +16 -1
  376. package/dist/serve/worker/index.d.ts.map +1 -1
  377. package/dist/serve/worker/index.js +17 -4
  378. package/dist/serve/worker/index.js.map +1 -1
  379. package/dist/serve/worker/protocol.d.ts +57 -0
  380. package/dist/serve/worker/protocol.d.ts.map +1 -1
  381. package/dist/serve/worker/protocol.js.map +1 -1
  382. package/dist/serve/worker/rtdb-value-equality.d.ts +3 -0
  383. package/dist/serve/worker/rtdb-value-equality.d.ts.map +1 -0
  384. package/dist/serve/worker/rtdb-value-equality.js +18 -0
  385. package/dist/serve/worker/rtdb-value-equality.js.map +1 -0
  386. package/dist/serve/worker/serve-init.js +2 -2
  387. package/dist/serve/worker/serve-init.js.map +1 -1
  388. package/dist/serve/worker/service-worker-relay.js +2 -2
  389. package/dist/serve/worker/service-worker-relay.js.map +1 -1
  390. package/package.json +7 -5
  391. package/src/assurance/.generated/conformance-verdicts.ts +120 -75
  392. package/src/cli/serve.ts +215 -307
  393. package/src/cli/service-command-records/database-rules-generate.ts +3 -0
  394. package/src/cli/service-command-records/database-rules-lint.ts +3 -0
  395. package/src/cli/service-command-records/database-rules-simulate.ts +3 -0
  396. package/src/cli/service-command-records/database-rules-validate.ts +3 -0
  397. package/src/cli/service-command-records/firestore-indexes-generate.ts +3 -0
  398. package/src/cli/service-command-records/firestore-rules-lint.ts +3 -0
  399. package/src/cli/service-command-records/firestore-rules-resolve.ts +3 -0
  400. package/src/cli/service-command-records/firestore-rules-simulate.ts +3 -0
  401. package/src/cli/service-command-records/firestore-rules-validate.ts +3 -0
  402. package/src/cli/service-command-records/storage-rules-lint.ts +3 -0
  403. package/src/cli/service-command-records/storage-rules-simulate.ts +3 -0
  404. package/src/cli/service-commands.generated.ts +27 -0
  405. package/src/cli/service-commands.test.ts +43 -0
  406. package/src/cli/service-commands.ts +36 -51
  407. package/src/conformance/.generated/can-i-use-browser.ts +1 -1
  408. package/src/conformance/.generated/can-i-use.ts +1 -1
  409. package/src/conformance/.generated/conformance-docs.ts +1 -1
  410. package/src/functions-rtdb/development-runtime.ts +299 -0
  411. package/src/serve/bridge-mount.ts +253 -19
  412. package/src/serve/bundler.ts +8 -34
  413. package/src/serve/entries/app-client.ts +5 -4
  414. package/src/serve/entries/auth-helper-core.ts +83 -30
  415. package/src/serve/entries/database.ts +180 -57
  416. package/src/serve/entries/init.ts +30 -20
  417. package/src/serve/html-injection.ts +65 -0
  418. package/src/serve/namespace.ts +26 -169
  419. package/src/serve/runtime/worker-replacement.ts +1 -1
  420. package/src/serve/sandbox-session.ts +233 -0
  421. package/src/serve/server.ts +20 -5
  422. package/src/serve/site-tree.ts +146 -0
  423. package/src/serve/standalone-assets.ts +9 -26
  424. package/src/serve/vite-functions-development.ts +201 -0
  425. package/src/serve/vite-generation-bridge.ts +66 -0
  426. package/src/serve/vite-generation-functions.ts +78 -0
  427. package/src/serve/vite-generation-middleware.ts +56 -0
  428. package/src/serve/vite-generation-rules-watch.ts +37 -0
  429. package/src/serve/vite-module-swap.ts +119 -0
  430. package/src/serve/vite-page-runtime.ts +100 -0
  431. package/src/serve/vite-plugin.ts +78 -883
  432. package/src/serve/vite-sandbox-generation.ts +255 -0
  433. package/src/serve/worker/client/disconnect.ts +3 -1
  434. package/src/serve/worker/client/handles.ts +5 -0
  435. package/src/serve/worker/client/pagehide.ts +31 -0
  436. package/src/serve/worker/client/rtdb-admin.ts +74 -0
  437. package/src/serve/worker/client/rtdb-connection-lifecycle.ts +52 -0
  438. package/src/serve/worker/client/rtdb-controls.ts +8 -0
  439. package/src/serve/worker/client/rtdb-listeners.ts +337 -0
  440. package/src/serve/worker/client/rtdb-reads.ts +12 -0
  441. package/src/serve/worker/client/rtdb-references.ts +85 -0
  442. package/src/serve/worker/client/rtdb-snapshots.ts +118 -0
  443. package/src/serve/worker/client/rtdb-transactions.ts +51 -0
  444. package/src/serve/worker/client/rtdb-writes.ts +74 -0
  445. package/src/serve/worker/client.ts +0 -2
  446. package/src/serve/worker/entry.ts +2 -2
  447. package/src/serve/worker/host/dispatch.ts +22 -2
  448. package/src/serve/worker/host/rtdb.ts +243 -2
  449. package/src/serve/worker/host/studio.ts +2 -0
  450. package/src/serve/worker/host/subscriptions.ts +8 -4
  451. package/src/serve/worker/host.ts +1 -1
  452. package/src/serve/worker/index.ts +58 -10
  453. package/src/serve/worker/protocol.ts +23 -2
  454. package/src/serve/worker/rtdb-value-equality.ts +17 -0
  455. package/src/serve/worker/serve-init.ts +2 -2
  456. package/src/serve/worker/service-worker-relay.ts +2 -2
  457. package/dist/serve/docs-ui/_astro/_slug_.DUci-duz.css +0 -1
  458. package/dist/serve/docs-ui/docs/_rhythm/index.html +0 -100
  459. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +0 -43
  460. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +0 -26
  461. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +0 -70
  462. package/dist/serve/docs-ui/docs/api-reference/index.html +0 -68
  463. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +0 -64
  464. package/dist/serve/docs-ui/docs/build/authentication/index.html +0 -66
  465. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +0 -70
  466. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +0 -71
  467. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +0 -66
  468. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +0 -67
  469. package/dist/serve/docs-ui/docs/conformance-scores/index.html +0 -50
  470. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +0 -531
  471. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +0 -73
  472. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +0 -29
  473. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +0 -33
  474. package/dist/serve/docs-ui/docs/messaging-compat/index.html +0 -265
  475. package/dist/serve/docs-ui/docs/observe/resolve-runtime-status/index.html +0 -28
  476. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +0 -74
  477. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +0 -45
  478. package/dist/serve/docs-ui/docs/overview/index.html +0 -17
  479. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +0 -186
  480. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +0 -318
  481. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +0 -160
  482. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +0 -425
  483. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +0 -60
  484. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +0 -507
  485. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +0 -258
  486. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +0 -51
  487. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +0 -308
  488. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +0 -68
  489. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +0 -11
  490. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +0 -126
  491. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +0 -1852
  492. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +0 -509
  493. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +0 -182
  494. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +0 -121
  495. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +0 -203
  496. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +0 -639
  497. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +0 -100
  498. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +0 -24
  499. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +0 -136
  500. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +0 -16
  501. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +0 -176
  502. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +0 -188
  503. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +0 -51
  504. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +0 -106
  505. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +0 -41
  506. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +0 -67
  507. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +0 -159
  508. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +0 -47
  509. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +0 -95
  510. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +0 -82
  511. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +0 -37
  512. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +0 -75
  513. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +0 -132
  514. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +0 -14
  515. package/dist/serve/docs-ui/index.html +0 -1
  516. package/dist/serve/studio-ui/assets/RulesCodeEditor-BDlH-5lp.js +0 -23
  517. package/dist/serve/studio-ui/assets/index-Bf9SSE8L.js +0 -1218
  518. package/dist/serve/studio-ui/assets/index-BlSGru_r.css +0 -1
  519. package/dist/serve/studio-ui/assets/seed-D_UjxfOU.js +0 -20
  520. package/dist/serve/studio-ui/index.html +0 -32
  521. package/dist/serve/worker/client/rtdb.d.ts +0 -36
  522. package/dist/serve/worker/client/rtdb.d.ts.map +0 -1
  523. package/dist/serve/worker/client/rtdb.js +0 -241
  524. package/dist/serve/worker/client/rtdb.js.map +0 -1
  525. package/src/serve/worker/client/rtdb.ts +0 -311
  526. /package/dist/serve/{docs-ui → site-ui}/404.html +0 -0
  527. /package/dist/serve/{docs-ui → site-ui}/_astro/_slug_.CXh9yTP1.css +0 -0
  528. /package/dist/serve/{docs-ui → site-ui}/docs/_rhythm.md +0 -0
  529. /package/dist/serve/{docs-ui → site-ui}/docs/agent/set-up-your-agent.md +0 -0
  530. /package/dist/serve/{docs-ui → site-ui}/docs/agent/watch-and-review.md +0 -0
  531. /package/dist/serve/{docs-ui → site-ui}/docs/agent/work-with-an-agent.md +0 -0
  532. /package/dist/serve/{docs-ui → site-ui}/docs/ai-compat.md +0 -0
  533. /package/dist/serve/{docs-ui → site-ui}/docs/api-reference.md +0 -0
  534. /package/dist/serve/{docs-ui → site-ui}/docs/app-compat.md +0 -0
  535. /package/dist/serve/{docs-ui → site-ui}/docs/auth-compat.md +0 -0
  536. /package/dist/serve/{docs-ui → site-ui}/docs/build/ai-logic.md +0 -0
  537. /package/dist/serve/{docs-ui → site-ui}/docs/build/authentication.md +0 -0
  538. /package/dist/serve/{docs-ui → site-ui}/docs/build/cloud-firestore.md +0 -0
  539. /package/dist/serve/{docs-ui → site-ui}/docs/build/cloud-messaging.md +0 -0
  540. /package/dist/serve/{docs-ui → site-ui}/docs/build/realtime-database.md +0 -0
  541. /package/dist/serve/{docs-ui → site-ui}/docs/create-pyric-reference-api.md +0 -0
  542. /package/dist/serve/{docs-ui → site-ui}/docs/functions-rtdb-compat.md +0 -0
  543. /package/dist/serve/{docs-ui → site-ui}/docs/get-started/how-the-swap-works.md +0 -0
  544. /package/dist/serve/{docs-ui → site-ui}/docs/get-started/start-building.md +0 -0
  545. /package/dist/serve/{docs-ui → site-ui}/docs/index.html +0 -0
  546. /package/dist/serve/{docs-ui → site-ui}/docs/observe/resolve-runtime-status.md +0 -0
  547. /package/dist/serve/{docs-ui → site-ui}/docs/observe/see-whats-happening.md +0 -0
  548. /package/dist/serve/{docs-ui → site-ui}/docs/observe/shape-your-data.md +0 -0
  549. /package/dist/serve/{docs-ui → site-ui}/docs/overview.md +0 -0
  550. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-app-reference-api.md +0 -0
  551. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-auth-reference-api.md +0 -0
  552. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-database-reference-api.md +0 -0
  553. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-messaging-reference-api.md +0 -0
  554. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-admin-storage-reference-api.md +0 -0
  555. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ai-reference-api.md +0 -0
  556. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ai-scripting-reference-api.md +0 -0
  557. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-app-reference-api.md +0 -0
  558. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-auth-reference-api.md +0 -0
  559. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-assurance-browser-reference-api.md +0 -0
  560. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-assurance-reference-api.md +0 -0
  561. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-bridge-client-reference-api.md +0 -0
  562. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-bridge-reference-api.md +0 -0
  563. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-conformance-browser-reference-api.md +0 -0
  564. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-conformance-docs-reference-api.md +0 -0
  565. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-conformance-reference-api.md +0 -0
  566. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-credentials-node-reference-api.md +0 -0
  567. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-discover-reference-api.md +0 -0
  568. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-register-reference-api.md +0 -0
  569. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-remote-reference-api.md +0 -0
  570. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-cli-verify-reference-api.md +0 -0
  571. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-messaging-reference-api.md +0 -0
  572. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-messaging-sw-reference-api.md +0 -0
  573. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-database-reference-api.md +0 -0
  574. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-sandbox-firestore-reference-api.md +0 -0
  575. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-agents-reference-api.md +0 -0
  576. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-auth-hooks-reference-api.md +0 -0
  577. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-auth-reference-api.md +0 -0
  578. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-events-hooks-reference-api.md +0 -0
  579. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-events-reference-api.md +0 -0
  580. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-firestore-hooks-reference-api.md +0 -0
  581. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-primitives-reference-api.md +0 -0
  582. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rtdb-reference-api.md +0 -0
  583. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rules-hooks-reference-api.md +0 -0
  584. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-rules-reference-api.md +0 -0
  585. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-storage-hooks-reference-api.md +0 -0
  586. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-traffic-hooks-reference-api.md +0 -0
  587. /package/dist/serve/{docs-ui → site-ui}/docs/pyric-ui-traffic-reference-api.md +0 -0
  588. /package/dist/serve/{docs-ui → site-ui}/docs/secure/audit-your-rules.md +0 -0
  589. /package/dist/serve/{docs-ui → site-ui}/docs/secure/firestore-rules-limits.md +0 -0
  590. /package/dist/serve/{docs-ui → site-ui}/docs/secure/read-a-denial.md +0 -0
  591. /package/dist/serve/{docs-ui → site-ui}/docs/secure/rtdb-rules-in-typescript.md +0 -0
  592. /package/dist/serve/{docs-ui → site-ui}/docs/secure/secure-it-with-rules.md +0 -0
  593. /package/dist/serve/{docs-ui → site-ui}/docs/secure/simulate-and-lint.md +0 -0
  594. /package/dist/serve/{docs-ui → site-ui}/docs/secure/write-a-rules-test-suite.md +0 -0
  595. /package/dist/serve/{docs-ui → site-ui}/docs/ship/ship-to-production.md +0 -0
  596. /package/dist/serve/{docs-ui → site-ui}/docs/ship/test-in-node.md +0 -0
  597. /package/dist/serve/{docs-ui → site-ui}/docs/trust/how-we-know-it-matches-firebase.md +0 -0
  598. /package/dist/serve/{docs-ui → site-ui}/docs/trust/versioning-and-compatibility.md +0 -0
  599. /package/dist/serve/{studio-ui → site-ui}/pyric-logo.svg +0 -0
@@ -17,15 +17,14 @@
17
17
  * deploy hosting` refuses it). `pyric({ swapInBuild })` forces the build
18
18
  * behavior on/off regardless of mode. See `sandbox-marker.ts`.
19
19
  *
20
- * This is a thin adapter over serve's proven machinery. It REUSES, not reimplements:
20
+ * This is the Vite adapter over serve's proven machinery. It reuses:
21
21
  * - the node-builtin shims — `NODE_BUILTIN_SHIMS`;
22
22
  * - the swap targets — `defaultSdkEntries()` (the `serve/entries/*` wrappers,
23
23
  * compiled-dist preferred, src fallback);
24
- * - the `/__pyric/*` namespace`createPyricNamespace` mounted verbatim behind
25
- * a connect-middleware adapter;
26
- * - rules load + prepare — `loadProjectRules` / `prepareRulesSource`;
24
+ * - the host-neutral sandbox session rules, fixtures, stores, live payload,
25
+ * Studio routes, `/__pyric/*` namespace, and owned cleanup;
27
26
  * - the SharedWorker host — `bundleWorker` served at `/__pyric/sdk/worker.js`;
28
- * - durable stores `createStateStore` (persist) / `createCaptureStore`.
27
+ * - the bridge mount shared with `pyric dev --bridge`.
29
28
  *
30
29
  * Scope = M1 (swap + rules) + M2 (SharedWorker multi-tab + persist/capture/seed)
31
30
  * + M3 (the MCP bridge fold — `{ bridge }`). M3 reuses `createBridgeMount` (the
@@ -39,97 +38,18 @@
39
38
  * the same `/__pyric/*` routes. If the worker bundle fails, the plugin falls back
40
39
  * to the in-page sandbox (single-tab, ephemeral).
41
40
  */
42
- import { readFile } from 'node:fs/promises';
43
- import { existsSync, readFileSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';
44
- import path from 'node:path';
45
- import type { IncomingMessage, ServerResponse, Server as HttpServer } from 'node:http';
46
- import type { Plugin, UserConfig, ConfigEnv } from 'vite';
47
- import type { Plugin as EsbuildPlugin } from 'esbuild';
48
- import {
49
- SDK_MODULES,
50
- defaultSdkEntries,
51
- resolveStudioUiDir,
52
- pyricPackageRoot,
53
- NODE_BUILTIN_RE,
54
- NODE_BUILTIN_SHIMS,
55
- } from './bundler.js';
41
+ import type { Plugin, UserConfig } from 'vite';
56
42
  import { createViteWorkerRuntime } from './vite-worker-runtime.js';
43
+ import type { PyricAiOptions } from './vite-ai-config.js';
44
+ import type { PyricRuntimeChipOption } from './runtime/chip-config.js';
57
45
  import {
58
- createEventHub,
59
- createPyricNamespace,
60
- type InitPayload,
61
- } from './namespace.js';
62
- import { formatActivityWarning } from './activity-warning.js';
63
- import { diskWorkspace, diskProjectStore } from './studio/index.js';
64
- import { createBridgeMount } from './bridge-mount.js';
65
- import {
66
- loadProjectDatabaseRules,
67
- loadProjectRules,
68
- loadProjectStorageRules,
69
- prepareRulesSource,
70
- rulesHashOf,
71
- } from './rules.js';
72
- import { createStateStore, STATE_FILE_VERSION, type PyricStateFile } from './state-store.js';
73
- import { createCaptureStore } from './capture-store.js';
74
- import { isAllowedHost } from './server.js';
75
- import { SANDBOX_BUILD_META } from './sandbox-marker.js';
76
- import { readFirebaseJson, readFirebaseRc, type FirebaseJson } from '../cli/firebase-json.js';
77
- import {
78
- discoverFunctionsRtdbProject,
79
- type FunctionsRtdbProject,
80
- } from '../functions-rtdb/project.js';
81
- import {
82
- spawnFunctionsRtdbChild,
83
- type FunctionsRtdbChildHandle,
84
- } from '../functions-rtdb/child.js';
85
- import {
86
- buildChildEnv,
87
- createLinePrefixer,
88
- registerModuleUrl,
89
- } from '../cli/dev-runner.js';
90
- import {
91
- loadViteAiEnv,
92
- resolveViteAiConfig,
93
- viteWorkerEpochSalt,
94
- type PyricAiOptions,
95
- } from './vite-ai-config.js';
96
- import { resolveViteRulesConfig } from './vite-rules-source.js';
97
- import {
98
- PYRIC_RUNTIME_CHIP_META,
99
- runtimeChipMetaValue,
100
- type PyricRuntimeChipOption,
101
- } from './runtime/chip-config.js';
102
-
103
- /**
104
- * Whether a `vite build` should run the firebase→pyric swap (produce a SANDBOX
105
- * build). MODE-based with a plugin-config override:
106
- * - `options.swapInBuild` wins outright when set (force on/off);
107
- * - otherwise swap for any NON-production mode. A plain `vite build` (mode
108
- * `production`) ships real firebase; `vite build --mode development` (or any
109
- * custom non-prod mode) is a sandbox build.
110
- * `vite dev` is handled separately in `apply` (always on).
111
- */
112
- function swapsInBuild(env: ConfigEnv, swapInBuild: boolean | undefined): boolean {
113
- if (swapInBuild !== undefined) return swapInBuild;
114
- return env.mode !== 'production';
115
- }
116
-
117
- /** Any `firebase/<sub>` specifier. */
118
- const FB_ANY = /^firebase\/([a-z-]+(?:\/[a-z-]+)*)$/;
119
-
120
- /** The firebase subpaths with swap entries. */
121
- const SERVED = new Set(SDK_MODULES.map((specifier) => specifier.slice('firebase/'.length)));
122
- const entryKey = (subpath: string): string => subpath.replaceAll('/', '-');
123
- const NODE_SHIM_PREFIX = '\0pyric:node-shim:';
124
-
125
- /** Walk up from a file to the nearest directory containing a package.json. */
126
- function packageRootOf(file: string): string {
127
- let dir = path.dirname(file);
128
- while (dir !== path.dirname(dir) && !existsSync(path.join(dir, 'package.json'))) {
129
- dir = path.dirname(dir);
130
- }
131
- return dir;
132
- }
46
+ createViteSandboxGeneration,
47
+ type ViteSandboxGeneration,
48
+ type ViteSandboxGenerationInput,
49
+ type ViteSandboxGenerationOptions,
50
+ } from './vite-sandbox-generation.js';
51
+ import { createViteModuleContext, createViteModuleSwap } from './vite-module-swap.js';
52
+ import { createVitePageRuntime } from './vite-page-runtime.js';
133
53
 
134
54
  export interface PyricOptions {
135
55
  /** Firestore rules path (relative to `root`). Default discovery prefers an
@@ -161,8 +81,8 @@ export interface PyricOptions {
161
81
  bridge?: boolean | { project?: string; disableAuditLog?: boolean };
162
82
  /** Serve the **Pyric Studio** app at `/__pyric/ui/` on Vite's dev origin (the
163
83
  * `pyric dev --ui` equivalent). Mounts the disk-backed workspace/project
164
- * routes Studio's `local` mode talks to AND serves the built Studio assets
165
- * (vendored in this package at `dist/serve/studio-ui`). **On by default**,
84
+ * routes Studio's `local` mode talks to AND serves the unified Astro site
85
+ * (vendored in this package at `dist/serve/site-ui`). **On by default**,
166
86
  * including under `bridge` (the bridge peer routes through the SharedWorker,
167
87
  * so app, Studio, and agent all observe the one sandbox); pass `ui: false`
168
88
  * to disable. */
@@ -229,6 +149,14 @@ export interface PyricOptions {
229
149
  ai?: PyricAiOptions;
230
150
  }
231
151
 
152
+ function resolveFunctionsOptions(
153
+ options: PyricOptions['functions'],
154
+ ): false | { region?: string; instance?: string; watch?: boolean } {
155
+ if (options === false) return false;
156
+ if (typeof options === 'object') return options;
157
+ return {};
158
+ }
159
+
232
160
  /**
233
161
  * The dev-only Vite plugin. Add to `vite.config`:
234
162
  *
@@ -236,112 +164,24 @@ export interface PyricOptions {
236
164
  * export default defineConfig({ plugins: [pyric()] });
237
165
  */
238
166
  export function pyric(options: PyricOptions = {}): Plugin {
239
- let resolvedAi = resolveViteAiConfig(options.ai, {});
240
- // Resolved once. `defaultSdkEntries()` prefers compiled dist `.js` and falls
241
- // back to source `.ts` in the workspace.
242
- const entries = defaultSdkEntries(); // { app, auth, firestore, init } → abs paths
243
- const pyricRoot = pyricPackageRoot();
244
- // The @pyric/cli package root — covers the served entries AND their siblings
245
- // (`worker/client.js`, the bridge client) that the entries statically import.
246
- const cliRoot = packageRootOf(entries.init);
247
-
248
- // section 8 refinement: a firebase import is "pyric-internal" iff its importer lives
249
- // under the resolved pyric package root — keyed on the root, not a `/pyric/`
250
- // substring (which a user project path could false-positive).
251
- const isPyricImporter = (importer: string | undefined): boolean => {
252
- if (!importer) return false;
253
- const f = importer.split('?')[0];
254
- return f === pyricRoot || f.startsWith(pyricRoot + path.sep);
255
- };
256
- // Node builtins are reached only from OUR code (pyric internals + the served
257
- // entries) — shim those, but NEVER hijack a user app or third-party library's
258
- // own `fs`/`path`/`url` (which Vite, or the user's polyfill plugin, should
259
- // resolve). The firebase branch stays scoped to pyric; this is the wider "ours".
260
- const isOurCode = (importer: string | undefined): boolean => {
261
- if (!importer) return false;
262
- if (isPyricImporter(importer)) return true;
263
- const f = importer.split('?')[0];
264
- return f === cliRoot || f.startsWith(cliRoot + path.sep);
265
- };
266
- const shimFor = (spec: string): string => NODE_BUILTIN_SHIMS[spec.replace(/^node:/, '')]!;
267
-
268
- // The esbuild mirror for Vite's dep optimizer — REQUIRED so a node_modules
269
- // library's `firebase/*` swaps too (the optimizer's esbuild pass bypasses the
270
- // Rollup-pipeline resolveId below and would otherwise pre-bake real firebase).
271
- const esbuildMirror: EsbuildPlugin = {
272
- name: 'pyric-sandbox-optimizer',
273
- setup(build) {
274
- build.onResolve({ filter: FB_ANY }, (args) => {
275
- const sub = FB_ANY.exec(args.path)![1]!;
276
- if (SERVED.has(sub)) return { path: entries[entryKey(sub)]! };
277
- return null; // non-served firebase from a lib → real firebase
278
- });
279
- build.onResolve({ filter: NODE_BUILTIN_RE }, (args) => {
280
- if (!isOurCode(args.importer)) return null; // user/lib node builtins → Vite/their polyfill
281
- return { path: args.path.replace(/^node:/, ''), namespace: 'pyric-node-shim' };
282
- });
283
- build.onLoad({ filter: /.*/, namespace: 'pyric-node-shim' }, (args) => ({
284
- contents: NODE_BUILTIN_SHIMS[args.path]!,
285
- loader: 'js',
286
- }));
287
- },
288
- };
289
-
290
- // Live rules box — the watcher swaps it; the init payload always serves the
291
- // current version.
292
- const live: {
293
- rules: string | null;
294
- rulesHash: string | null;
295
- databaseRules: { rules: Record<string, unknown> } | null;
296
- databaseRulesHash: string | null;
297
- databaseUrl: string | null;
298
- storageRules: string | null;
299
- storageRulesHash: string | null;
300
- } = {
301
- rules: null,
302
- rulesHash: null,
303
- databaseRules: null,
304
- databaseRulesHash: null,
305
- databaseUrl: null,
306
- storageRules: null,
307
- storageRulesHash: null,
308
- };
309
-
310
- // M2: the SharedWorker bundle's content hash (sync) — stamped into the page so
311
- // a still-running OLD worker is detected as stale. The collaborator becomes
312
- // ready once its bundle succeeds; until then (or on bundle failure) the page
313
- // is forced onto the in-page sandbox path. transformIndexHtml reads its tag.
167
+ const moduleContext = createViteModuleContext();
168
+ const moduleSwap = createViteModuleSwap(moduleContext);
169
+ const { entries, cliRoot } = moduleContext;
314
170
  const workerRuntime = createViteWorkerRuntime();
171
+ const studioEnabled = options.ui !== false;
172
+ const pageRuntimeInput = {
173
+ options,
174
+ studioEnabled,
175
+ initEntry: entries.init,
176
+ workerRuntime,
177
+ };
178
+ const pageRuntime = createVitePageRuntime(pageRuntimeInput);
315
179
 
316
- // Set by the `config` hook. When the plugin runs under `vite build` at all it
317
- // is a SANDBOX build (the `apply` gate below only lets build through under the
318
- // sandbox trigger), so `command === 'build'` is sufficient to know we are
319
- // producing marker-stamped, non-production output.
320
- let sandboxBuild = false;
321
- // Sandbox build: the serve init entry (runtime bootstrap + the ServeAuthHelper
322
- // popup picker) is emitted as its OWN chunk and script-tagged into index.html.
323
- // Rollup dedupes the shared runtime module between this chunk and the app
324
- // chunk (both import the same absolute file), so the page runs exactly ONE
325
- // sandbox runtime — unlike serve-time injection of /__pyric/sdk/init.js,
326
- // which is a separately-bundled second runtime copy (the double-init bug:
327
- // two banners, two bridge registrations). `pyric dev` sees the marker and
328
- // skips its injection for these pages (see injectServeTags).
329
- let initChunkRef: string | undefined;
330
- let initChunkFile: string | undefined;
331
-
332
- // M3 bridge fold: normalize `bridge` once (true ⇒ `{}`, falsy ⇒ null). When
333
- // on, the MCP mount is composed into the /__pyric middleware (createBridgeMount,
334
- // shared with `pyric dev --bridge`) AND the page is forced onto the in-page
335
- // sandbox path — the bridge peer is the in-page sandbox, never the SharedWorker,
336
- // so multi-tab is disabled under bridge to keep agent + app on one backend.
180
+ // Normalize the public bridge shorthand once. The active generation owns the
181
+ // bridge/session attachment and routes the peer through the SharedWorker.
337
182
  const bridgeOpts = options.bridge === true ? {} : options.bridge || null;
183
+ let activeGeneration: ViteSandboxGeneration | null = null;
338
184
 
339
- // Plugin-level AI engine, normalized to the JSON-safe wire shape. Travels
340
- // to the worker host via the init payload (→ ctx.aiEngine) AND to the in-page
341
- // fallback via an injected synchronous global (see transformIndexHtml).
342
- // An explicit engine is available immediately (some hook tests call the HTML
343
- // transform directly); Vite's config hook may otherwise select the simple
344
- // PYRIC_AI_MODEL environment path for the active mode/root.
345
185
  return {
346
186
  name: 'pyric:sandbox',
347
187
  // Active for `vite dev` ALWAYS, and for `vite build` only when it is a
@@ -352,655 +192,64 @@ export function pyric(options: PyricOptions = {}): Plugin {
352
192
  // `pyric dev`, never deploy it).
353
193
  apply(config, env) {
354
194
  void config;
355
- if (env.command === 'serve') return true;
356
- return swapsInBuild(env, options.swapInBuild);
195
+ return pageRuntime.applies(env);
357
196
  },
358
197
  enforce: 'pre',
359
198
 
360
199
  config(config, env) {
361
- sandboxBuild = env.command === 'build';
362
- const loadedEnv = loadViteAiEnv(env.mode, config.root, config.envDir);
363
- resolvedAi = resolveViteAiConfig(options.ai, loadedEnv);
364
- // Cast: the `esbuild` package's `Plugin` type skews slightly from Vite's
365
- // bundled esbuild types (benign — the Plugin shape is stable across the
366
- // versions in range).
367
200
  return {
368
- optimizeDeps: {
369
- // Keep firebase out of the optimizer's pre-bake; the resolver swaps it
370
- // per-importer at request time.
371
- exclude: [...SDK_MODULES],
372
- // The excluded SDK is served as ESM straight from dist, so Vite never
373
- // scans it for dependencies. js-md5 / js-sha256 are CJS-only (no ESM
374
- // named exports); without a forced pre-bundle the browser gets the raw
375
- // UMD source and `import { md5 }` throws a SyntaxError. Force-including
376
- // them gives the dist imports the interop-wrapped optimized copies.
377
- include: ['js-md5', 'js-sha256'],
378
- esbuildOptions: { plugins: [esbuildMirror] },
379
- },
380
- // Sandbox build only: the swapped-in runtime chunk uses TOP-LEVEL AWAIT
381
- // (it deploys rules before app code runs — load-bearing, see
382
- // entries/runtime.ts). Vite's default build target predates TLA and the
383
- // esbuild transpile would fail. A sandbox build is a throwaway preview
384
- // served under `pyric dev` (modern browser), so pin an ESNext target
385
- // that keeps TLA. A plain production `vite build` never runs this plugin,
386
- // so the user's own target is untouched there.
387
- ...(sandboxBuild ? { build: { target: 'esnext' } } : {}),
388
- } as unknown as UserConfig;
201
+ ...moduleSwap.config(),
202
+ ...pageRuntime.config(config, env),
203
+ } as UserConfig;
389
204
  },
390
205
 
391
206
  configResolved(resolved) {
392
- // AUGMENT (don't replace) the fs allow-list: pyric dist + the @pyric/cli
393
- // tree live outside the app root, but setting `server.fs.allow` in config()
394
- // would clobber Vite's auto-added root/workspace entries and 403 the app's
395
- // own source. Push the two PACKAGE ROOTS — @pyric/cli' root (not just the
396
- // entries dir) is needed because the served init entry statically imports
397
- // siblings (`worker/client.js`, the bridge client) outside entries/.
398
- const allow = resolved.server?.fs?.allow;
399
- if (allow) {
400
- for (const dir of [pyricRoot, cliRoot]) {
401
- if (!allow.includes(dir)) allow.push(dir);
402
- }
403
- }
207
+ moduleSwap.configResolved(resolved);
404
208
  },
405
209
 
406
210
  resolveId(source, importer) {
407
- const fb = FB_ANY.exec(source);
408
- if (fb) {
409
- const sub = fb[1]!;
410
- if (SERVED.has(sub)) return entries[entryKey(sub)]!; // swap served set for user/lib
411
- return null; // non-served firebase from user → real firebase
412
- }
413
- const node = NODE_BUILTIN_RE.exec(source);
414
- // Shim node builtins ONLY when reached from our own code — never hijack a
415
- // user app or library's own fs/path/url (Vite/their polyfill handles those).
416
- if (node && isOurCode(importer)) return NODE_SHIM_PREFIX + node[2]!;
417
- return null;
211
+ return moduleSwap.resolveId(source, importer);
418
212
  },
419
213
 
420
214
  load(id) {
421
- if (id.startsWith(NODE_SHIM_PREFIX)) return shimFor(id.slice(NODE_SHIM_PREFIX.length));
422
- return null;
215
+ return moduleSwap.load(id);
423
216
  },
424
217
 
425
218
  async configureServer(server) {
426
- const cwd = options.root ?? server.config.root;
427
-
428
- // Reproduce serve's rules prelude: firebase.json (optional) → loadProjectRules.
429
- let fbJson: FirebaseJson | null = null;
430
- try {
431
- fbJson = await readFirebaseJson(cwd);
432
- } catch {
433
- /* optional — serve without a firebase.json */
434
- }
435
- // Convention-first development source: an explicit option wins; otherwise
436
- // an authored 2+modules file wins over firebase.json's generated deployment
437
- // target. Projects without that convention retain the normal Firebase
438
- // discovery path.
439
- const config = resolveViteRulesConfig(cwd, options.rules, fbJson);
440
- const loaded = await loadProjectRules(cwd, config);
441
- const loadedDatabase = await loadProjectDatabaseRules(cwd, config);
442
- const loadedStorage = await loadProjectStorageRules(cwd, config);
443
- live.rules = loaded.rules;
444
- live.rulesHash = loaded.rulesHash;
445
- live.databaseRules = loadedDatabase.rules;
446
- live.databaseRulesHash = loadedDatabase.rulesHash;
447
- live.databaseUrl = loadedDatabase.databaseUrl;
448
- live.storageRules = loadedStorage.rules;
449
- live.storageRulesHash = loadedStorage.rulesHash;
450
-
451
- // ── M2 durable stores (mirrors serve's startServe orchestration) ──────
452
- // Capture (default-on): the worker/page pushes its session fixture to
453
- // /__pyric/capture; the store writes .pyric/last-session.json for `pyric verify`.
454
- const capture = (options.capture ?? true) ? createCaptureStore(cwd) : undefined;
455
- // Persist: createStateStore IS the durable sandbox. Load eagerly so a
456
- // corrupt/mismatched file fails the start (not silently ephemeral).
457
- const state = options.persist ? createStateStore(cwd) : undefined;
458
- if (state && options.fresh) {
459
- for (const p of [state.path, state.backupPath]) if (existsSync(p)) rmSync(p);
460
- server.config.logger.info(' ⓘ [pyric] fresh: discarded the existing state file; re-seeding');
461
- }
462
- // Eager load (mirrors serve.ts:158) — parse the file NOW so a corrupt or
463
- // version-mismatched state file throws StateFileError and FAILS THE START
464
- // with the actionable inspect-or-delete message. Without this the first
465
- // parse is deferred into initPayload() at request time, where it throws
466
- // synchronously AFTER namespace.ts has committed `writeHead(200)`: the
467
- // client gets a 200 with an empty body, the page/worker swallow the JSON
468
- // error, and the sandbox silently runs WITHOUT the persisted data + rules.
469
- // (No-op on first run: load() returns null for a missing file.)
470
- // configureServer is async, so an uncaught throw aborts the dev start.
471
- if (state) state.load();
219
+ const priorGeneration = activeGeneration;
220
+ activeGeneration = null;
221
+ await priorGeneration?.close();
472
222
 
473
- // Seed: a "collection/doc" fields map, OR a `pyric snapshot` state-file
474
- // envelope (detected by its `version` key). Ported from serve.ts.
475
- let seed: Record<string, Record<string, unknown>> | null = null;
476
- let seedState: unknown | null = null;
477
- let seedUsers: Record<string, unknown>[] | null = null;
478
- if (options.seed) {
479
- const seedPath = path.resolve(cwd, options.seed);
480
- let parsed: unknown;
481
- try {
482
- parsed = JSON.parse(readFileSync(seedPath, 'utf8'));
483
- } catch (e) {
484
- throw new Error(`@pyric/cli/vite: failed to read seed ${seedPath}: ${e instanceof Error ? e.message : String(e)}`);
485
- }
486
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
487
- throw new Error('@pyric/cli/vite: seed must be a JSON object of "collection/doc" → fields');
488
- }
489
- const obj = parsed as Record<string, unknown>;
490
- if (obj.version === STATE_FILE_VERSION && ('firestore' in obj || 'auth' in obj)) {
491
- const fixture = obj as unknown as PyricStateFile;
492
- if (state && !state.exists()) {
493
- // persist first run from a fixture: prime the store, then the normal
494
- // persist path restores it like any lived state.
495
- if (fixture.firestore != null) state.writeSection('firestore', fixture.firestore);
496
- if (fixture.auth != null) state.writeSection('auth', fixture.auth);
497
- } else if (!state) {
498
- seedState = fixture.firestore ?? null;
499
- seedUsers = (fixture.auth?.users as Record<string, unknown>[] | undefined) ?? null;
500
- }
501
- // persist + existing state: lived state wins; the fixture is inert.
502
- } else {
503
- seed = parsed as Record<string, Record<string, unknown>>;
504
- }
505
- }
506
-
507
- // ── M2 SharedWorker host: bundle it (cached per version) and serve it at
508
- // /__pyric/sdk/worker.js. This is what flips runtime.ts to the worker path.
509
- // On bundle failure, the collaborator stays unready and its HTML tag
510
- // forces the in-page sandbox.
511
- try {
512
- await workerRuntime.prepare(viteWorkerEpochSalt(cwd, resolvedAi.engineWire));
513
- } catch (e) {
514
- server.config.logger.warn(
515
- ` ⚠ [pyric] SharedWorker bundle failed — using the in-page sandbox (single-tab, ephemeral): ${e instanceof Error ? e.message : String(e)}`,
516
- );
517
- }
518
-
519
- // ── Functions (RTDB triggers) — the `pyric dev` parity fold ───────────
520
- // Discover the one supported Functions codebase from the same resolved
521
- // firebase.json the rules used (project.ts reads it itself). Reuses the
522
- // exact serve module, so absent `functions` → null (silently off) and a
523
- // malformed config throws serve's own error text — which, thrown from an
524
- // async configureServer, fails the dev start the same way serve's
525
- // `return 2` aborts. The Functions child connects to the sandbox over the
526
- // bridge WS, so a discovered codebase forces the bridge mount on (mirrors
527
- // serve's `bridgeEnabledFor(..., functionsProject)`). `functions: false`
528
- // is the off switch: discovery never runs, so neither does the mount.
529
- const functionsOpts = typeof options.functions === 'object' ? options.functions : {};
530
- let functionsProject: FunctionsRtdbProject | null = null;
531
- if (options.functions !== false) {
532
- try {
533
- functionsProject = discoverFunctionsRtdbProject(cwd);
534
- } catch (error) {
535
- // Malformed functions config: fail the start with serve's exact message.
536
- throw error instanceof Error ? error : new Error(String(error));
537
- }
538
- }
539
- const functionsProjectId = functionsProject
540
- ? (process.env.PYRIC_PROJECT ?? (await readFirebaseRc(cwd))?.projects?.default ?? 'demo-project')
541
- : null;
542
-
543
- // ── M3 MCP bridge (mirrors serve.ts:221–274) ─────────────────────────
544
- // The mount is long-lived (one bridge per dev session); its MCP transport
545
- // is rebuilt per request (stateless). Composed into the /__pyric middleware
546
- // below (handler tier) + the server's WS upgrade. middlewareMode has no
547
- // httpServer → HTTP routes still work, no WS peer.
548
- // Guard the WS upgrade with the SAME allow rule Vite's own host check
549
- // uses (host + allowedHosts, where `true` = opted into all hosts). Vite's
550
- // upgrade path bypasses connect middleware, so this is the only guard on it.
551
- const mount = bridgeOpts || functionsProject
552
- ? createBridgeMount({
553
- ...(bridgeOpts ?? {}),
554
- // A functions-only session still needs a labeled bridge; prefer an
555
- // explicit bridge project, else the resolved functions project id.
556
- project: bridgeOpts?.project ?? functionsProjectId ?? undefined,
557
- upgradeGuard: {
558
- boundHost: typeof server.config.server.host === 'string' ? server.config.server.host : 'localhost',
559
- allowedHosts:
560
- server.config.server.allowedHosts === true
561
- ? true
562
- : Array.isArray(server.config.server.allowedHosts)
563
- ? server.config.server.allowedHosts
564
- : [],
565
- },
566
- })
567
- : null;
568
-
569
- // The /__pyric/* namespace, reused VERBATIM (now with the sdk dir + state +
570
- // capture routes live).
571
- const events = createEventHub();
572
- const initPayload = (): InitPayload => ({
573
- rules: live.rules,
574
- rulesHash: live.rulesHash,
575
- databaseRules: live.databaseRules,
576
- databaseRulesHash: live.databaseRulesHash,
577
- databaseUrl: live.databaseUrl,
578
- storageRules: live.storageRules,
579
- storageRulesHash: live.storageRulesHash,
580
- // Project identity: scopes the storage IDB name per served project
581
- // (issue #359). Local-only — a dev path never leaves the machine.
582
- projectKey: cwd,
583
- // The bound port is known only after `listen`; initPayload runs per
584
- // request (after listen), so resolve it lazily here. Absolute ws://host:port
585
- // mirrors serve (the browser reads this as the bridge peer URL).
586
- bridgeUrl: (() => {
587
- if (!mount) return null;
588
- const addr = server.httpServer?.address();
589
- const port = addr && typeof addr === 'object' ? addr.port : 0;
590
- const host = (typeof server.config.server.host === 'string' && server.config.server.host) || 'localhost';
591
- return port > 0 ? mount.wsUrl({ host, port }) : null;
592
- })(),
593
- // Precedence: once a state file exists, lived state is the truth — seed
594
- // applies only on the first (state-less) run.
595
- seed: state?.exists() ? null : seed,
596
- seedState,
597
- persist: Boolean(state),
598
- capture: Boolean(capture),
599
- authUsers: state
600
- ? ((state.readSection('auth') as { users?: Record<string, unknown>[] } | null)?.users ?? null)
601
- : seedUsers,
602
- // Messaging is part of the canonical firebase/* sandbox swap.
603
- messaging: true,
604
- // Plugin-level engine → the worker host's ctx.aiEngine (host-ai.ts),
605
- // which wins over any op-carried engine. Null when unset.
606
- ai: resolvedAi.engineWire ? { engine: resolvedAi.engineWire } : null,
607
- });
608
- // Pyric Studio: mount the disk-backed workspace/project routes that
609
- // Studio's `local` mode talks to + serve the built Studio app at
610
- // /__pyric/ui/. Mirrors `pyric dev --ui`; the studio-ui assets are
611
- // vendored in this package's dist (resolveStudioUiDir).
612
- //
613
- // ON BY DEFAULT, including under `bridge`: the bridge now routes agent
614
- // tool-calls THROUGH the SharedWorker (see `connectBridgePeer`), so the
615
- // app, Studio, and agent all observe the ONE sandbox. Explicit `ui: false`
616
- // still wins.
223
+ const projectDir = options.root ?? server.config.root;
617
224
  const uiEnabled = options.ui ?? true;
618
- const studio = uiEnabled
619
- ? {
620
- workspace: diskWorkspace(cwd),
621
- projects: diskProjectStore(path.join(cwd, '.pyric', 'projects')),
622
- }
623
- : undefined;
624
- let studioUiDir: string | undefined;
625
- if (uiEnabled) {
626
- studioUiDir = resolveStudioUiDir() ?? undefined;
627
- if (!studioUiDir) {
628
- server.config.logger.warn(
629
- '[pyric] ui: built Studio app not found; /__pyric/ui/ will 404 ' +
630
- '(run the full build, or reinstall @pyric/cli).',
631
- );
632
- }
633
- }
634
- const { sdkDir } = workerRuntime.status();
635
- const namespace = createPyricNamespace({
636
- sdkDir,
637
- initPayload,
638
- events,
639
- activity: (incident) => server.config.logger.warn(formatActivityWarning(incident)),
640
- state,
641
- capture,
642
- studio,
643
- studioUiDir,
644
- // `ai.proxyUpstream`: what `/__pyric/ai-proxy` forwards to (beats the
645
- // PYRIC_AI_PROXY_UPSTREAM env var; falls back to the default when unset).
646
- aiProxyUpstream: resolvedAi.proxyUpstream,
647
- // Adapt Vite's logger to the plain info/note shape the namespace's
648
- // diagnostics (denial relay, future hot-reload lines) expect —
649
- // matches the `↻`/`⚠ [pyric]` lines already logged elsewhere in this
650
- // plugin via `server.config.logger` directly.
651
- logger: {
652
- info: (m) => server.config.logger.info(m),
653
- note: (m) => server.config.logger.warn(m),
654
- },
655
- });
656
-
657
- // DNS-rebinding guard for the /__pyric/* surface. Vite has its own host
658
- // check, but a `configureServer` hook that doesn't return a function mounts
659
- // BEFORE it (and the ordering differs across Vite 5/6/7), so guard here too
660
- // — independent of Vite's internals. Reuses serve's `isAllowedHost`.
661
- const srvOpts = server.config.server;
662
- const hostAllowed = (req: IncomingMessage): boolean => {
663
- if (srvOpts.allowedHosts === true) return true; // user opted into all hosts
664
- const boundHost = typeof srvOpts.host === 'string' ? srvOpts.host : 'localhost';
665
- const extra = Array.isArray(srvOpts.allowedHosts) ? srvOpts.allowedHosts : [];
666
- return isAllowedHost(req.headers.host, boundHost, extra);
225
+ const functionsOptions = resolveFunctionsOptions(options.functions);
226
+ const ai = pageRuntime.ai();
227
+ const generationOptions: ViteSandboxGenerationOptions = {
228
+ rules: options.rules,
229
+ seed: options.seed,
230
+ persist: options.persist,
231
+ fresh: options.fresh,
232
+ capture: options.capture,
233
+ bridge: bridgeOpts,
234
+ ui: uiEnabled,
235
+ functions: functionsOptions,
667
236
  };
237
+ const generationInput: ViteSandboxGenerationInput = {
238
+ server,
239
+ projectDir,
240
+ cliRoot,
241
+ workerRuntime,
242
+ options: generationOptions,
243
+ ai,
244
+ };
245
+ const generation = await createViteSandboxGeneration(generationInput);
246
+ activeGeneration = generation;
247
+ },
668
248
 
669
- // Connect-middleware adapter (build `url` from originalUrl; next() when the
670
- // namespace closure returns false; never rewrite route bodies).
671
- server.middlewares.use('/__pyric', (req: IncomingMessage & { originalUrl?: string }, res: ServerResponse, next: () => void) => {
672
- if (!hostAllowed(req)) {
673
- res.statusCode = 403;
674
- res.end(`pyric: refused request for Host '${req.headers.host ?? ''}' (DNS-rebinding guard).`);
675
- return;
676
- }
677
- const url = new URL(req.originalUrl ?? req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
678
- // Bridge first (mirrors serve.ts): /__pyric/mcp + /__pyric/health must be
679
- // handled by the mount, not 404 through the namespace. Falls through to the
680
- // namespace when the mount returns false (every non-bridge route).
681
- Promise.resolve(mount ? mount.handler(req, res, url) : false)
682
- .then((bridged) => (bridged ? true : Promise.resolve(namespace(req, res, url))))
683
- .then((handled) => {
684
- if (!handled) next();
685
- })
686
- .catch((err: unknown) => {
687
- if (!res.headersSent) res.statusCode = 500;
688
- res.end(err instanceof Error ? err.message : String(err));
689
- });
690
- });
691
-
692
- // WS upgrade for the in-page sandbox peer (ws://…/__pyric/sandbox). The
693
- // listener only fires once upgrades arrive (after listen), so adding it in
694
- // configureServer is safe. middlewareMode has no httpServer → HTTP bridge
695
- // routes still work, just no WS peer.
696
- // Cast: Vite types `httpServer` as http.Server | http2.Http2SecureServer;
697
- // attachUpgrade only needs `.on('upgrade')`, present on both. (serve passes
698
- // a plain http.Server, so this widening is plugin-specific.)
699
- if (mount && server.httpServer) mount.attachUpgrade(server.httpServer as unknown as HttpServer);
700
-
701
- // A2 discovery pointer: the stdio `mcp-proxy` (the sanctioned Claude Code
702
- // entrypoint) reads `.pyric/serve.json` to find the bridge without a fixed
703
- // URL -- it takes the PORT and probes BOTH loopback families, defeating the
704
- // IPv6/IPv4 trap that broke the hand-written `.mcp.json`. serve writes this
705
- // pointer; the Vite plugin must too. Written after listen (port known),
706
- // removed on close.
707
- if (mount && server.httpServer) {
708
- const httpServer = server.httpServer;
709
- const pointer = path.join(cwd, '.pyric', 'serve.json');
710
- const host =
711
- (typeof server.config.server.host === 'string' && server.config.server.host) || 'localhost';
712
- const writePointer = (): void => {
713
- const addr = httpServer.address();
714
- const port = addr && typeof addr === 'object' ? addr.port : 0;
715
- if (!port) return;
716
- try {
717
- mkdirSync(path.dirname(pointer), { recursive: true });
718
- writeFileSync(
719
- pointer,
720
- JSON.stringify(
721
- {
722
- url: `http://${host}:${port}`,
723
- mcpUrl: mount.mcpUrl({ host, port }),
724
- port,
725
- pid: process.pid,
726
- instanceId: mount.instanceId,
727
- project: bridgeOpts?.project ?? 'sandbox',
728
- },
729
- null,
730
- 2,
731
- ) + '\n',
732
- );
733
- } catch {
734
- /* best-effort: the proxy falls back to a port scan */
735
- }
736
- };
737
- // Cross-family collision guard: once listening, probe BOTH loopback
738
- // families on our port. If a DIFFERENT sandbox answers on the other
739
- // family, two dev servers are colliding (IPv4 `*:P` + IPv6 `[::1]:P`)
740
- // and the agent/browser can split across them (writes seem to vanish).
741
- // #697's dual-bind can't apply here — Vite owns the single listen — so
742
- // we can only warn, loudly. (Our own family answers with our instanceId
743
- // and is skipped; a dual-stack bind owns both and never trips this.)
744
- const warnOnCollision = async (): Promise<void> => {
745
- const a = httpServer.address();
746
- const p = a && typeof a === 'object' ? a.port : 0;
747
- if (!p) return;
748
- for (const probe of [`http://127.0.0.1:${p}`, `http://[::1]:${p}`]) {
749
- try {
750
- const res = await fetch(`${probe}/__pyric/health`, { signal: AbortSignal.timeout(1000) });
751
- if (res.status !== 200) continue;
752
- const body = (await res.json()) as { mode?: string; instanceId?: string };
753
- if (body.mode === 'sandbox' && body.instanceId && body.instanceId !== mount.instanceId) {
754
- server.config.logger.warn(
755
- `\n⚠ pyric: another sandbox already serves port ${p} on a different loopback ` +
756
- `family (${probe}). Two dev servers are colliding across IPv4/IPv6 — your MCP ` +
757
- `agent and browser can land on DIFFERENT sandboxes (writes seem to vanish). ` +
758
- `Stop the other server, or give this app a unique \`server.port\` so the two ` +
759
- `don't share one (pinning server.host to a family the squatter holds would ` +
760
- `just EADDRINUSE).\n`,
761
- { timestamp: true },
762
- );
763
- return; // one warning is enough
764
- }
765
- } catch {
766
- /* other family silent — no collision */
767
- }
768
- }
769
- };
770
- const announce = (): void => {
771
- writePointer();
772
- void warnOnCollision();
773
- };
774
- if ((httpServer as unknown as { listening?: boolean }).listening) announce();
775
- else httpServer.once('listening', announce);
776
- httpServer.once('close', () => {
777
- try {
778
- rmSync(pointer);
779
- } catch {
780
- /* gone already */
781
- }
782
- });
783
- }
784
-
785
- // ── Functions child lifecycle (mirrors serve's runServe) ─────────────
786
- // The Functions runtime executes in an isolated node child (child.ts),
787
- // exactly as `pyric dev` runs it: the child loads the user's unchanged
788
- // functions module, and `--import @pyric/cli/register` + `PYRIC_SANDBOX=
789
- // remote:<serveUrl>` route its `firebase-admin/app` to a RemoteSandbox that
790
- // dials the bridge WS (`/__pyric/sandbox`). onValueCreated triggers observe
791
- // RTDB writes and write their effects back through that one shared sandbox.
792
- // Started once a sandbox peer (a browser tab / SharedWorker relay) has
793
- // connected — the trigger's baseline needs a live backend — and stopped on
794
- // server close. Vite restarts re-run configureServer, so the child respawns
795
- // with the new server. Unlike `pyric dev` (which does not watch functions
796
- // source), the plugin hot-reloads it via Vite's own watcher — see the
797
- // watch block below; `functions: { watch: false }` restores dev's
798
- // restart-to-reload behavior.
799
- if (functionsProject && functionsProjectId && mount && server.httpServer) {
800
- const httpServer = server.httpServer;
801
- const project = functionsProject;
802
- const projectId = functionsProjectId;
803
- const bridgeMount = mount;
804
- const host =
805
- (typeof server.config.server.host === 'string' && server.config.server.host) || 'localhost';
806
- // Prefer the compiled child (node cannot execute the .ts source when the
807
- // plugin runs from source in tests); fall back to spawnFunctionsRtdbChild's
808
- // own default (correct when the plugin runs from dist in production).
809
- const builtChild = path.join(cliRoot, 'dist/functions-rtdb/child.js');
810
- const childModuleUrl = existsSync(builtChild) ? builtChild : undefined;
811
- let functionsChild: FunctionsRtdbChildHandle | null = null;
812
- let disposed = false;
813
-
814
- const start = async (mode: 'initial' | 'reload' = 'initial'): Promise<void> => {
815
- const addr = httpServer.address();
816
- const port = addr && typeof addr === 'object' ? addr.port : 0;
817
- if (!port || disposed) return;
818
- const serveUrl = `http://${host}:${port}`;
819
-
820
- // Wait (bounded) for a sandbox peer — the SharedWorker relay / browser
821
- // tab that holds the backend. Poll the mount directly (no self-fetch).
822
- // On a hot reload the peer is usually still connected (the loop exits
823
- // immediately); when it dropped mid-session, wait briefly rather than
824
- // the full initial 30s.
825
- const deadline = Date.now() + (mode === 'reload' ? 5_000 : 30_000);
826
- while (!disposed && !bridgeMount.sandboxConnected()) {
827
- if (Date.now() >= deadline) break;
828
- await new Promise((r) => setTimeout(r, 250));
829
- }
830
- if (disposed) return;
831
- if (!bridgeMount.sandboxConnected()) {
832
- server.config.logger.warn(
833
- mode === 'reload'
834
- ? ` ✖ [pyric] functions not restarted — no sandbox peer connected. ` +
835
- `Functions stay down until the next save with ${serveUrl} open.`
836
- : ` ⚠ [pyric] functions not started — no browser tab connected after 30s. ` +
837
- `Open ${serveUrl} and restart the dev server.`,
838
- );
839
- return;
840
- }
841
-
842
- functionsChild = spawnFunctionsRtdbChild({
843
- cwd: project.sourceDir,
844
- entry: project.entry,
845
- env: buildChildEnv(process.env, { serveUrl, registerUrl: registerModuleUrl() }),
846
- // Precedence (per field): plugin option > env var > firebase files
847
- // > default. projectId already folds PYRIC_PROJECT > .firebaserc >
848
- // demo-project.
849
- instance: functionsOpts.instance ?? `${projectId}-default-rtdb`,
850
- location: functionsOpts.region ?? process.env.PYRIC_FUNCTIONS_RTDB_REGION ?? 'us-central1',
851
- ...(childModuleUrl ? { childModuleUrl } : {}),
852
- onEvent(event) {
853
- if (event.type === 'execution') {
854
- const params = Object.entries(event.params)
855
- .map(([name, value]) => `${name}=${value}`)
856
- .join(', ');
857
- const suffix = params ? ` (${params})` : '';
858
- if (event.status === 'fulfilled') {
859
- server.config.logger.info(` ✔ [pyric] function ${event.exportName} ← /${event.ref}${suffix}`);
860
- } else {
861
- server.config.logger.error(
862
- ` ✖ [pyric] function ${event.exportName} ← /${event.ref}${suffix}: ${event.error.message}`,
863
- );
864
- }
865
- } else {
866
- server.config.logger.error(
867
- ` ✖ [pyric] functions delivery for ${event.exportName}: ${event.error.message}`,
868
- );
869
- }
870
- },
871
- });
872
-
873
- const out = createLinePrefixer('[functions] ', (line) => server.config.logger.info(line.replace(/\n$/, '')));
874
- const err = createLinePrefixer('[functions] ', (line) => server.config.logger.warn(line.replace(/\n$/, '')));
875
- functionsChild.child.stdout?.setEncoding('utf8');
876
- functionsChild.child.stderr?.setEncoding('utf8');
877
- functionsChild.child.stdout?.on('data', (chunk: string) => out.push(chunk));
878
- functionsChild.child.stderr?.on('data', (chunk: string) => err.push(chunk));
879
- functionsChild.child.stdout?.once('end', () => out.flush());
880
- functionsChild.child.stderr?.once('end', () => err.flush());
881
-
882
- try {
883
- const ready = await functionsChild.ready;
884
- server.config.logger.info(
885
- mode === 'reload'
886
- ? ` ↻ [pyric] functions reloaded (${ready.triggerCount} trigger${ready.triggerCount === 1 ? '' : 's'})`
887
- : ` ✔ [pyric] functions ${ready.triggerCount} onValueCreated ` +
888
- `trigger${ready.triggerCount === 1 ? '' : 's'} from ${path.relative(cwd, project.entry)}`,
889
- );
890
- for (const unsupported of ready.unsupportedTriggers) {
891
- server.config.logger.warn(
892
- ` ⚠ [pyric] functions export ${unsupported.exportName} uses unsupported trigger ` +
893
- `${unsupported.eventType}; it will not run.`,
894
- );
895
- }
896
- } catch (error) {
897
- const message = error instanceof Error ? error.message : String(error);
898
- server.config.logger.error(
899
- mode === 'reload'
900
- ? // Unlike rules, last-good cannot stay live — the old child is
901
- // already stopped — so a broken save takes functions down.
902
- ` ✖ [pyric] functions failed to reload: ${message}\n` +
903
- ` ✖ [pyric] functions are down until the next good save.`
904
- : ` ✖ [pyric] functions failed to start: ${message}`,
905
- );
906
- await functionsChild.stop().catch(() => undefined);
907
- functionsChild = null;
908
- }
909
- };
910
-
911
- let reloadDebounce: ReturnType<typeof setTimeout> | null = null;
912
- httpServer.once('close', () => {
913
- disposed = true;
914
- if (reloadDebounce) clearTimeout(reloadDebounce);
915
- void functionsChild?.stop().catch(() => undefined);
916
- });
917
- if ((httpServer as unknown as { listening?: boolean }).listening) void start();
918
- else httpServer.once('listening', () => void start());
919
-
920
- // Functions hot-reload from Vite's OWN watcher (mirrors the rules block
921
- // below). Restart = redeploy: stop the old child, respawn via the same
922
- // start path — there is no in-place swap, so in-flight executions in the
923
- // old child may drop and writes landing in the swap gap become the new
924
- // child's baseline (execution.ts consumes each trigger's first observed
925
- // value as baseline; they do not fire). Debounced 300ms — a save fans
926
- // out several fs events and a child respawn is far heavier than a rules
927
- // re-parse. Restarts are serialized: a save landing mid-restart queues
928
- // exactly one follow-up run.
929
- if (functionsOpts.watch !== false) {
930
- const sourceDir = project.sourceDir;
931
- // Usually redundant (Vite watches its root, which contains the
932
- // functions dir in the common layout) but load-bearing when the
933
- // functions source lives outside Vite's root. node_modules stays
934
- // ignored: Vite's watcher ignores `**/node_modules/**` globally, and
935
- // the handler below filters it again for explicitly-added trees.
936
- server.watcher.add(sourceDir);
937
- let restarting = false;
938
- let queued = false;
939
- const restart = async (): Promise<void> => {
940
- if (restarting) {
941
- queued = true;
942
- return;
943
- }
944
- restarting = true;
945
- try {
946
- do {
947
- queued = false;
948
- if (disposed) return;
949
- const old = functionsChild;
950
- functionsChild = null;
951
- if (old) await old.stop().catch(() => undefined);
952
- await start('reload');
953
- } while (queued && !disposed);
954
- } finally {
955
- restarting = false;
956
- }
957
- };
958
- const onFunctionsFsEvent = (file: string): void => {
959
- const resolved = path.resolve(file);
960
- const rel = path.relative(sourceDir, resolved);
961
- if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) return;
962
- if (rel.split(path.sep).includes('node_modules')) return;
963
- if (reloadDebounce) clearTimeout(reloadDebounce);
964
- reloadDebounce = setTimeout(() => void restart(), 300);
965
- };
966
- server.watcher.on('change', onFunctionsFsEvent);
967
- server.watcher.on('add', onFunctionsFsEvent);
968
- server.watcher.on('unlink', onFunctionsFsEvent);
969
- }
970
- }
971
-
972
- // Rules hot-reload from Vite's OWN watcher (no second fs watcher). Reuse
973
- // prepareRulesSource (resolve + lint); last-good stays live on a broken save.
974
- // Debounced (editors emit several change events per save) — matches
975
- // watchProjectRules' 150ms cadence, which we can't reuse here (it opens its
976
- // own fs watcher).
977
- if (loaded.sourcePath) {
978
- const rulesFile = loaded.sourcePath;
979
- let debounce: ReturnType<typeof setTimeout> | null = null;
980
- server.watcher.add(rulesFile);
981
- server.watcher.on('change', (file) => {
982
- if (path.resolve(file) !== path.resolve(rulesFile)) return;
983
- if (debounce) clearTimeout(debounce);
984
- debounce = setTimeout(() => {
985
- void readFile(rulesFile, 'utf8').then(
986
- (raw) => {
987
- try {
988
- const rules = prepareRulesSource(raw, rulesFile);
989
- live.rules = rules;
990
- live.rulesHash = rulesHashOf(rules);
991
- events.broadcast('rules-changed', { rules, rulesHash: live.rulesHash });
992
- server.config.logger.info(` ↻ [pyric] rules reloaded (${live.rulesHash})`);
993
- } catch (e) {
994
- server.config.logger.warn(
995
- ` ⚠ [pyric] rules NOT reloaded (last-good stays live): ${e instanceof Error ? e.message : String(e)}`,
996
- );
997
- }
998
- },
999
- () => {},
1000
- );
1001
- }, 150);
1002
- });
1003
- }
249
+ async closeBundle() {
250
+ const generation = activeGeneration;
251
+ activeGeneration = null;
252
+ await generation?.close();
1004
253
  },
1005
254
 
1006
255
  // Sandbox build only: emit the serve init entry as its own chunk. Emitted in
@@ -1009,68 +258,14 @@ export function pyric(options: PyricOptions = {}): Plugin {
1009
258
  // BEFORE Vite's build-html plugin applies transformIndexHtml — the filename
1010
259
  // is always available when the script tag is injected below.
1011
260
  buildStart() {
1012
- if (sandboxBuild) {
1013
- initChunkRef = this.emitFile({
1014
- type: 'chunk',
1015
- id: entries.init,
1016
- name: 'pyric-sandbox-init',
1017
- });
1018
- }
261
+ pageRuntime.buildStart((chunk) => this.emitFile(chunk));
1019
262
  },
1020
263
  generateBundle() {
1021
- if (initChunkRef) initChunkFile = this.getFileName(initChunkRef);
264
+ pageRuntime.generateBundle((referenceId) => this.getFileName(referenceId));
1022
265
  },
1023
266
 
1024
267
  transformIndexHtml(html) {
1025
- const runtimeChipTag = `<meta name="${PYRIC_RUNTIME_CHIP_META}" content="${runtimeChipMetaValue(options.runtimeChip)}" data-studio="${options.ui === false ? 'off' : 'on'}" data-pyric-sandbox>`;
1026
- // Sandbox BUILD: the app's own `firebase/*` imports were already swapped
1027
- // (resolveId, above) to pyric's in-page adapters and BUNDLED into the app
1028
- // chunk, and the emitted init chunk (script-tagged here) carries the
1029
- // runtime bootstrap + the ServeAuthHelper popup picker — rollup shares
1030
- // ONE runtime module between the two, so the output is fully
1031
- // self-contained. `pyric dev` sees the marker below and skips its own
1032
- // serve-time injection for this page (a second injected runtime would
1033
- // double-init: two banners, two bridge peers). The marker is also the
1034
- // signal that makes `pyric dev` trust this dist (skip the inlined-SDK
1035
- // scan). transformIndexHtml runs BEFORE Vite writes index.html, so both
1036
- // land in the emitted asset.
1037
- if (sandboxBuild) {
1038
- if (html.includes(SANDBOX_BUILD_META)) return html;
1039
- const initTag = initChunkFile
1040
- ? `<script type="module" crossorigin src="/${initChunkFile}" data-pyric-sandbox-init></script>`
1041
- : '';
1042
- const tags = SANDBOX_BUILD_META + runtimeChipTag + initTag;
1043
- return html.includes('</head>')
1044
- ? html.replace('</head>', `${tags}</head>`)
1045
- : tags + html;
1046
- }
1047
- const MARKER = 'data-pyric-sandbox';
1048
- if (html.includes(MARKER)) return html;
1049
- // Worker path (default): stamp the served worker's content hash so the page
1050
- // can WARN when a still-running OLD worker is stale (a SharedWorker can't
1051
- // hot-update). In-page path: force it via the explicit flag before the init
1052
- // module evaluates — a classic inline script runs before the deferred module.
1053
- // The flag (not nulling `window.SharedWorker`) leaves the user's own
1054
- // SharedWorker usage intact. We force in-page ONLY when the worker bundle
1055
- // failed (worker runtime unready) — the ephemeral fallback. `bridge` no longer
1056
- // forces in-page: the bridge peer routes agent tool-calls THROUGH the
1057
- // worker (see `connectBridgePeer`), so the agent shares the one sandbox the
1058
- // app + Studio use.
1059
- const head = workerRuntime.headTag(MARKER);
1060
- // Plugin-level engine for the IN-PAGE path: a classic inline script runs
1061
- // before the deferred init module AND before app code's `getAI`, so the
1062
- // served `getAI` (entries/ai.ts) reads it synchronously — init.json can't
1063
- // be awaited there. Harmless on the worker path (that branch ignores the
1064
- // global; the worker reads ctx.aiEngine from init.json). `<` is escaped so
1065
- // an engine value can never break out of the script tag.
1066
- const aiEngineTag = resolvedAi.engineWire
1067
- ? `<script ${MARKER}>globalThis.__PYRIC_AI_ENGINE__=${JSON.stringify(resolvedAi.engineWire).replace(/</g, '\\u003c')};</script>`
1068
- : '';
1069
- // Boot the sandbox by loading the real init entry as a module (Vite
1070
- // serves + transforms it). The init module's top-level await deploys rules
1071
- // before app code runs. Mirrors serve's injectServeTags.
1072
- const tag = head + aiEngineTag + runtimeChipTag + `<script type="module" src="/@fs/${entries.init}" ${MARKER}></script>`;
1073
- return html.includes('</head>') ? html.replace('</head>', `${tag}</head>`) : tag + html;
268
+ return pageRuntime.transformIndexHtml(html);
1074
269
  },
1075
270
  };
1076
271
  }