@pyric/cli 0.1.0-alpha.16 → 0.1.0-alpha.18

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 (419) hide show
  1. package/README.md +42 -12
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +80 -72
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +80 -72
  5. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  6. package/dist/bridge/server/bridge.d.ts.map +1 -1
  7. package/dist/bridge/server/bridge.js +4 -2
  8. package/dist/bridge/server/bridge.js.map +1 -1
  9. package/dist/bridge/server/peer.d.ts.map +1 -1
  10. package/dist/bridge/server/peer.js +1 -0
  11. package/dist/bridge/server/peer.js.map +1 -1
  12. package/dist/cli/database-rules.d.ts.map +1 -1
  13. package/dist/cli/database-rules.js +6 -4
  14. package/dist/cli/database-rules.js.map +1 -1
  15. package/dist/cli/dev-runner.d.ts +9 -0
  16. package/dist/cli/dev-runner.d.ts.map +1 -1
  17. package/dist/cli/dev-runner.js +18 -0
  18. package/dist/cli/dev-runner.js.map +1 -1
  19. package/dist/cli/serve.d.ts.map +1 -1
  20. package/dist/cli/serve.js +62 -6
  21. package/dist/cli/serve.js.map +1 -1
  22. package/dist/cli/verify.js +2 -2
  23. package/dist/cli/verify.js.map +1 -1
  24. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  25. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  26. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  27. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  28. package/dist/conformance/.generated/can-i-use.js +1 -1
  29. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  30. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
  31. package/dist/conformance/.generated/conformance-docs.js +1 -1
  32. package/dist/conformance/.generated/conformance-docs.js.map +1 -1
  33. package/dist/functions-rtdb/child.d.ts +1 -0
  34. package/dist/functions-rtdb/child.d.ts.map +1 -1
  35. package/dist/functions-rtdb/child.js +11 -1
  36. package/dist/functions-rtdb/child.js.map +1 -1
  37. package/dist/functions-rtdb/development-runtime.d.ts +1 -0
  38. package/dist/functions-rtdb/development-runtime.d.ts.map +1 -1
  39. package/dist/functions-rtdb/development-runtime.js +1 -0
  40. package/dist/functions-rtdb/development-runtime.js.map +1 -1
  41. package/dist/next/client-aliases.d.ts +11 -0
  42. package/dist/next/client-aliases.d.ts.map +1 -0
  43. package/dist/next/client-aliases.js +38 -0
  44. package/dist/next/client-aliases.js.map +1 -0
  45. package/dist/next/dev-rewrites.d.ts +9 -0
  46. package/dist/next/dev-rewrites.d.ts.map +1 -0
  47. package/dist/next/dev-rewrites.js +53 -0
  48. package/dist/next/dev-rewrites.js.map +1 -0
  49. package/dist/next/guard.d.ts +15 -0
  50. package/dist/next/guard.d.ts.map +1 -0
  51. package/dist/next/guard.js +52 -0
  52. package/dist/next/guard.js.map +1 -0
  53. package/dist/next/index.d.ts +12 -0
  54. package/dist/next/index.d.ts.map +1 -0
  55. package/dist/next/index.js +11 -0
  56. package/dist/next/index.js.map +1 -0
  57. package/dist/next/runtime-env.d.ts +7 -0
  58. package/dist/next/runtime-env.d.ts.map +1 -0
  59. package/dist/next/runtime-env.js +13 -0
  60. package/dist/next/runtime-env.js.map +1 -0
  61. package/dist/next/server-external-packages.d.ts +10 -0
  62. package/dist/next/server-external-packages.d.ts.map +1 -0
  63. package/dist/next/server-external-packages.js +34 -0
  64. package/dist/next/server-external-packages.js.map +1 -0
  65. package/dist/next/target-url.d.ts +11 -0
  66. package/dist/next/target-url.d.ts.map +1 -0
  67. package/dist/next/target-url.js +36 -0
  68. package/dist/next/target-url.js.map +1 -0
  69. package/dist/next/turbopack-config.d.ts +9 -0
  70. package/dist/next/turbopack-config.d.ts.map +1 -0
  71. package/dist/next/turbopack-config.js +39 -0
  72. package/dist/next/turbopack-config.js.map +1 -0
  73. package/dist/next/types.d.ts +40 -0
  74. package/dist/next/types.d.ts.map +1 -0
  75. package/dist/next/types.js +5 -0
  76. package/dist/next/types.js.map +1 -0
  77. package/dist/next/webpack-config.d.ts +11 -0
  78. package/dist/next/webpack-config.d.ts.map +1 -0
  79. package/dist/next/webpack-config.js +51 -0
  80. package/dist/next/webpack-config.js.map +1 -0
  81. package/dist/next/with-pyric.d.ts +22 -0
  82. package/dist/next/with-pyric.d.ts.map +1 -0
  83. package/dist/next/with-pyric.js +49 -0
  84. package/dist/next/with-pyric.js.map +1 -0
  85. package/dist/register/app-bridge.d.ts +9 -0
  86. package/dist/register/app-bridge.d.ts.map +1 -0
  87. package/dist/register/app-bridge.js +56 -0
  88. package/dist/register/app-bridge.js.map +1 -0
  89. package/dist/register/hooks.d.ts.map +1 -1
  90. package/dist/register/hooks.js +6 -1
  91. package/dist/register/hooks.js.map +1 -1
  92. package/dist/register/index.js +1 -1
  93. package/dist/register/index.js.map +1 -1
  94. package/dist/register/mapping.d.ts +3 -1
  95. package/dist/register/mapping.d.ts.map +1 -1
  96. package/dist/register/mapping.js +41 -5
  97. package/dist/register/mapping.js.map +1 -1
  98. package/dist/remote/index.d.ts.map +1 -1
  99. package/dist/remote/index.js +5 -3
  100. package/dist/remote/index.js.map +1 -1
  101. package/dist/rtdb/rules-json.d.ts +12 -0
  102. package/dist/rtdb/rules-json.d.ts.map +1 -1
  103. package/dist/rtdb/rules-json.js +98 -0
  104. package/dist/rtdb/rules-json.js.map +1 -1
  105. package/dist/serve/bundler.d.ts.map +1 -1
  106. package/dist/serve/bundler.js +2 -0
  107. package/dist/serve/bundler.js.map +1 -1
  108. package/dist/serve/discovery.d.ts +4 -4
  109. package/dist/serve/discovery.d.ts.map +1 -1
  110. package/dist/serve/discovery.js +59 -38
  111. package/dist/serve/discovery.js.map +1 -1
  112. package/dist/serve/entries/app-ai-passthrough.d.ts +8 -0
  113. package/dist/serve/entries/app-ai-passthrough.d.ts.map +1 -0
  114. package/dist/serve/entries/app-ai-passthrough.js +59 -0
  115. package/dist/serve/entries/app-ai-passthrough.js.map +1 -0
  116. package/dist/serve/entries/auth-helper-core.js +9 -7
  117. package/dist/serve/entries/auth-helper-core.js.map +1 -1
  118. package/dist/serve/entries/auth.d.ts +1 -0
  119. package/dist/serve/entries/auth.d.ts.map +1 -1
  120. package/dist/serve/entries/auth.js +1 -0
  121. package/dist/serve/entries/auth.js.map +1 -1
  122. package/dist/serve/entries/bridge-url.d.ts.map +1 -1
  123. package/dist/serve/entries/bridge-url.js +7 -2
  124. package/dist/serve/entries/bridge-url.js.map +1 -1
  125. package/dist/serve/entries/database.d.ts +1 -0
  126. package/dist/serve/entries/database.d.ts.map +1 -1
  127. package/dist/serve/entries/database.js +1 -0
  128. package/dist/serve/entries/database.js.map +1 -1
  129. package/dist/serve/entries/firestore.d.ts +1 -0
  130. package/dist/serve/entries/firestore.d.ts.map +1 -1
  131. package/dist/serve/entries/firestore.js +1 -0
  132. package/dist/serve/entries/firestore.js.map +1 -1
  133. package/dist/serve/entries/init.d.ts.map +1 -1
  134. package/dist/serve/entries/init.js +4 -2
  135. package/dist/serve/entries/init.js.map +1 -1
  136. package/dist/serve/entries/runtime.js +23 -0
  137. package/dist/serve/entries/runtime.js.map +1 -1
  138. package/dist/serve/entries/storage.d.ts +2 -0
  139. package/dist/serve/entries/storage.d.ts.map +1 -1
  140. package/dist/serve/entries/storage.js +9 -2
  141. package/dist/serve/entries/storage.js.map +1 -1
  142. package/dist/serve/html-injection.d.ts +3 -1
  143. package/dist/serve/html-injection.d.ts.map +1 -1
  144. package/dist/serve/html-injection.js +27 -1
  145. package/dist/serve/html-injection.js.map +1 -1
  146. package/dist/serve/rules.js +2 -2
  147. package/dist/serve/rules.js.map +1 -1
  148. package/dist/serve/runtime/chip-config.d.ts +1 -1
  149. package/dist/serve/runtime/chip-config.d.ts.map +1 -1
  150. package/dist/serve/runtime/chip-config.js +16 -8
  151. package/dist/serve/runtime/chip-config.js.map +1 -1
  152. package/dist/serve/runtime/chip.d.ts.map +1 -1
  153. package/dist/serve/runtime/chip.js +24 -3
  154. package/dist/serve/runtime/chip.js.map +1 -1
  155. package/dist/serve/runtime/status.d.ts +1 -0
  156. package/dist/serve/runtime/status.d.ts.map +1 -1
  157. package/dist/serve/runtime/status.js +71 -13
  158. package/dist/serve/runtime/status.js.map +1 -1
  159. package/dist/serve/sandbox-session.d.ts +1 -0
  160. package/dist/serve/sandbox-session.d.ts.map +1 -1
  161. package/dist/serve/sandbox-session.js +30 -2
  162. package/dist/serve/sandbox-session.js.map +1 -1
  163. package/dist/serve/site-ui/_astro/_slug_.C6QfVOxJ.css +1 -0
  164. package/dist/serve/site-ui/_astro/_studio_.B6b_G1ev.css +1 -0
  165. package/dist/serve/site-ui/_astro/app.B7pBzz5N.js +11 -0
  166. package/dist/serve/site-ui/_astro/app.boex5SnQ.js +1 -0
  167. package/dist/serve/site-ui/_astro/{chess-showcase.CnoxIle5.js → chess-showcase.DDqE-QGe.js} +1 -1
  168. package/dist/serve/site-ui/_astro/{example-runtime.R1d96L6-.js → example-runtime.B0byNQOl.js} +1 -1
  169. package/dist/serve/site-ui/_astro/index.uwPvjH_1.js +1 -0
  170. package/dist/serve/site-ui/_astro/reads.Dh3z0fJy.js +1 -0
  171. package/dist/serve/site-ui/_astro/sandbox-controls.C2IqtoSw.js +1252 -0
  172. package/dist/serve/site-ui/_astro/{seed.EyI3VYEu.js → seed.CCmj00su.js} +1 -1
  173. package/dist/serve/site-ui/auth/index.html +2 -2
  174. package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
  175. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +48 -13
  176. package/dist/serve/site-ui/docs/agent/set-up-your-agent.md +74 -11
  177. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
  178. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
  179. package/dist/serve/site-ui/docs/ai-compat/index.html +85 -85
  180. package/dist/serve/site-ui/docs/ai-compat.md +84 -84
  181. package/dist/serve/site-ui/docs/api-reference/index.html +3 -1
  182. package/dist/serve/site-ui/docs/api-reference.md +2 -0
  183. package/dist/serve/site-ui/docs/app-compat/index.html +28 -28
  184. package/dist/serve/site-ui/docs/app-compat.md +27 -27
  185. package/dist/serve/site-ui/docs/auth-compat/index.html +122 -122
  186. package/dist/serve/site-ui/docs/auth-compat.md +121 -121
  187. package/dist/serve/site-ui/docs/build/ai-logic/index.html +19 -2
  188. package/dist/serve/site-ui/docs/build/ai-logic.md +28 -0
  189. package/dist/serve/site-ui/docs/build/authentication/index.html +1 -1
  190. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +1 -1
  191. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
  192. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +1 -1
  193. package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
  194. package/dist/serve/site-ui/docs/conformance-scores/index.html +25 -10
  195. package/dist/serve/site-ui/docs/conformance-scores.md +23 -8
  196. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +6 -6
  197. package/dist/serve/site-ui/docs/create-pyric-reference-api.md +5 -5
  198. package/dist/serve/site-ui/docs/database-compat/index.html +200 -448
  199. package/dist/serve/site-ui/docs/database-compat.md +198 -461
  200. package/dist/serve/site-ui/docs/examples/chess/index.html +2 -2
  201. package/dist/serve/site-ui/docs/examples/index.html +1 -1
  202. package/dist/serve/site-ui/docs/firestore-compat/index.html +186 -195
  203. package/dist/serve/site-ui/docs/firestore-compat.md +184 -195
  204. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +15 -15
  205. package/dist/serve/site-ui/docs/functions-rtdb-compat.md +14 -14
  206. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  207. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +57 -0
  208. package/dist/serve/site-ui/docs/get-started/nextjs.md +86 -0
  209. package/dist/serve/site-ui/docs/get-started/start-building/index.html +38 -9
  210. package/dist/serve/site-ui/docs/get-started/start-building.md +62 -7
  211. package/dist/serve/site-ui/docs/get-started/vite/index.html +26 -0
  212. package/dist/serve/site-ui/docs/get-started/vite.md +45 -0
  213. package/dist/serve/site-ui/docs/index.json +711 -111
  214. package/dist/serve/site-ui/docs/messaging-compat/index.html +56 -56
  215. package/dist/serve/site-ui/docs/messaging-compat.md +55 -55
  216. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +1 -1
  217. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
  218. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
  219. package/dist/serve/site-ui/docs/overview/index.html +1 -1
  220. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +39 -13
  221. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api.md +28 -2
  222. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  223. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +38 -6
  224. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api.md +43 -0
  225. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +9 -1
  226. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api.md +8 -0
  227. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
  228. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +27 -4
  229. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api.md +23 -0
  230. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
  231. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  232. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
  233. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +1 -1
  234. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  235. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  236. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  237. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  238. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  239. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  240. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  241. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  242. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  243. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +123 -0
  244. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api.md +99 -0
  245. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +127 -0
  246. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api.md +174 -0
  247. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  248. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  249. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +570 -326
  250. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api.md +198 -6
  251. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  252. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +1 -1
  253. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +1 -1
  254. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +2971 -627
  255. package/dist/serve/site-ui/docs/pyric-firestore-reference-api.md +2873 -517
  256. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  257. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  258. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +43 -3
  259. package/dist/serve/site-ui/docs/pyric-rules-reference-api.md +8 -0
  260. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +26 -2
  261. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api.md +24 -0
  262. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  263. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +77 -9
  264. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api.md +28 -13
  265. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +240 -63
  266. package/dist/serve/site-ui/docs/pyric-storage-reference-api.md +164 -5
  267. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  268. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  269. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  270. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  271. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  272. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  273. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  274. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  275. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  276. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  277. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -10
  278. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api.md +0 -9
  279. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  280. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +2 -1
  281. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api.md +1 -0
  282. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  283. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  284. package/dist/serve/site-ui/docs/rules-compat/index.html +87 -79
  285. package/dist/serve/site-ui/docs/rules-compat.md +86 -78
  286. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
  287. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  288. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
  289. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  290. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
  291. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  292. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +1 -1
  293. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  294. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
  295. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
  296. package/dist/serve/site-ui/docs/storage-compat/index.html +119 -125
  297. package/dist/serve/site-ui/docs/storage-compat.md +118 -124
  298. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  299. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
  300. package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +1 -1
  301. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  302. package/dist/serve/site-ui/docs/tutorial/index.html +2 -1
  303. package/dist/serve/site-ui/docs/tutorial.md +2 -0
  304. package/dist/serve/site-ui/examples/chess/index.html +1 -1
  305. package/dist/serve/site-ui/examples/firestore-first-write/index.html +1 -1
  306. package/dist/serve/site-ui/firestore/index.html +2 -2
  307. package/dist/serve/site-ui/index.html +2 -2
  308. package/dist/serve/site-ui/llms.txt +8 -4
  309. package/dist/serve/site-ui/rtdb/index.html +2 -2
  310. package/dist/serve/site-ui/settings/index.html +2 -2
  311. package/dist/serve/site-ui/storage/index.html +2 -2
  312. package/dist/serve/site-ui/traffic/index.html +2 -2
  313. package/dist/serve/vite-ai-config.d.ts +4 -1
  314. package/dist/serve/vite-ai-config.d.ts.map +1 -1
  315. package/dist/serve/vite-ai-config.js +83 -19
  316. package/dist/serve/vite-ai-config.js.map +1 -1
  317. package/dist/serve/vite-functions-development.d.ts.map +1 -1
  318. package/dist/serve/vite-functions-development.js +1 -0
  319. package/dist/serve/vite-functions-development.js.map +1 -1
  320. package/dist/serve/vite-generation-rules-watch.d.ts.map +1 -1
  321. package/dist/serve/vite-generation-rules-watch.js +61 -14
  322. package/dist/serve/vite-generation-rules-watch.js.map +1 -1
  323. package/dist/serve/vite-module-swap.d.ts +4 -1
  324. package/dist/serve/vite-module-swap.d.ts.map +1 -1
  325. package/dist/serve/vite-module-swap.js +106 -21
  326. package/dist/serve/vite-module-swap.js.map +1 -1
  327. package/dist/serve/vite-plugin.d.ts.map +1 -1
  328. package/dist/serve/vite-plugin.js +45 -5
  329. package/dist/serve/vite-plugin.js.map +1 -1
  330. package/dist/serve/vite-sandbox-generation.js +1 -1
  331. package/dist/serve/vite-sandbox-generation.js.map +1 -1
  332. package/dist/serve/worker/client/resumable.d.ts +30 -0
  333. package/dist/serve/worker/client/resumable.d.ts.map +1 -0
  334. package/dist/serve/worker/client/resumable.js +416 -0
  335. package/dist/serve/worker/client/resumable.js.map +1 -0
  336. package/dist/serve/worker/client/rtdb-references.d.ts.map +1 -1
  337. package/dist/serve/worker/client/rtdb-references.js +4 -1
  338. package/dist/serve/worker/client/rtdb-references.js.map +1 -1
  339. package/dist/serve/worker/client/storage.d.ts +16 -2
  340. package/dist/serve/worker/client/storage.d.ts.map +1 -1
  341. package/dist/serve/worker/client/storage.js +57 -6
  342. package/dist/serve/worker/client/storage.js.map +1 -1
  343. package/dist/serve/worker/host/rules.d.ts.map +1 -1
  344. package/dist/serve/worker/host/rules.js +2 -1
  345. package/dist/serve/worker/host/rules.js.map +1 -1
  346. package/dist/serve/worker/index.d.ts +1 -1
  347. package/dist/serve/worker/index.d.ts.map +1 -1
  348. package/dist/serve/worker/index.js +1 -1
  349. package/dist/serve/worker/index.js.map +1 -1
  350. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  351. package/dist/serve/worker/serve-init.js +31 -0
  352. package/dist/serve/worker/serve-init.js.map +1 -1
  353. package/package.json +15 -4
  354. package/src/assurance/.generated/conformance-verdicts.ts +80 -72
  355. package/src/bridge/server/bridge.ts +5 -2
  356. package/src/bridge/server/peer.ts +2 -1
  357. package/src/cli/cli.test.ts +14 -0
  358. package/src/cli/database-rules.ts +6 -4
  359. package/src/cli/dev-runner.ts +21 -0
  360. package/src/cli/serve.ts +63 -5
  361. package/src/cli/verify.ts +2 -2
  362. package/src/conformance/.generated/can-i-use-browser.ts +1 -1
  363. package/src/conformance/.generated/can-i-use.ts +1 -1
  364. package/src/conformance/.generated/conformance-docs.ts +1 -1
  365. package/src/functions-rtdb/child.ts +12 -1
  366. package/src/functions-rtdb/development-runtime.ts +2 -0
  367. package/src/next/client-aliases.ts +39 -0
  368. package/src/next/dev-rewrites.ts +77 -0
  369. package/src/next/guard.ts +61 -0
  370. package/src/next/index.ts +16 -0
  371. package/src/next/runtime-env.ts +18 -0
  372. package/src/next/server-external-packages.ts +43 -0
  373. package/src/next/target-url.ts +46 -0
  374. package/src/next/turbopack-config.ts +54 -0
  375. package/src/next/types.ts +47 -0
  376. package/src/next/webpack-config.ts +71 -0
  377. package/src/next/with-pyric.ts +58 -0
  378. package/src/register/app-bridge.ts +79 -0
  379. package/src/register/hooks.ts +6 -1
  380. package/src/register/index.ts +1 -1
  381. package/src/register/mapping.ts +50 -4
  382. package/src/remote/index.ts +7 -5
  383. package/src/rtdb/rules-json.ts +110 -0
  384. package/src/serve/bundler.ts +2 -0
  385. package/src/serve/discovery.ts +65 -44
  386. package/src/serve/entries/app-ai-passthrough.ts +83 -0
  387. package/src/serve/entries/auth-helper-core.ts +9 -7
  388. package/src/serve/entries/auth.ts +1 -0
  389. package/src/serve/entries/bridge-url.ts +9 -2
  390. package/src/serve/entries/database.ts +1 -0
  391. package/src/serve/entries/firestore.ts +1 -0
  392. package/src/serve/entries/init.ts +5 -2
  393. package/src/serve/entries/runtime.ts +25 -0
  394. package/src/serve/entries/storage.ts +12 -1
  395. package/src/serve/html-injection.ts +26 -1
  396. package/src/serve/rules.ts +2 -2
  397. package/src/serve/runtime/chip-config.ts +19 -6
  398. package/src/serve/runtime/chip.ts +24 -3
  399. package/src/serve/runtime/status.ts +76 -13
  400. package/src/serve/sandbox-session.ts +31 -2
  401. package/src/serve/vite-ai-config.ts +86 -19
  402. package/src/serve/vite-functions-development.ts +1 -0
  403. package/src/serve/vite-generation-rules-watch.ts +67 -15
  404. package/src/serve/vite-module-swap.ts +121 -21
  405. package/src/serve/vite-plugin.ts +44 -6
  406. package/src/serve/vite-sandbox-generation.ts +1 -1
  407. package/src/serve/worker/client/resumable.ts +506 -0
  408. package/src/serve/worker/client/rtdb-references.ts +4 -1
  409. package/src/serve/worker/client/storage.ts +77 -7
  410. package/src/serve/worker/host/rules.ts +2 -1
  411. package/src/serve/worker/index.ts +4 -0
  412. package/src/serve/worker/serve-init.ts +30 -0
  413. package/dist/serve/site-ui/_astro/_slug_.BoKXYrnu.css +0 -1
  414. package/dist/serve/site-ui/_astro/_studio_.BtYpqe1A.css +0 -1
  415. package/dist/serve/site-ui/_astro/app.4HeLP_FA.js +0 -109
  416. package/dist/serve/site-ui/_astro/app.BgSnCR5G.js +0 -1
  417. package/dist/serve/site-ui/_astro/index.BJiOemMX.js +0 -1
  418. package/dist/serve/site-ui/_astro/reads.BrKNdKAa.js +0 -1
  419. package/dist/serve/site-ui/_astro/sandbox-controls.BTb3EbQp.js +0 -1153
@@ -17,14 +17,27 @@ interface RuntimeChipDocument {
17
17
  querySelector(selector: string): { getAttribute(name: string): string | null } | null;
18
18
  }
19
19
 
20
- /** Read only plugin-authored values; absent/unknown metadata keeps the UI off. */
20
+ function hasBundlerRuntimeChipConfig(): boolean {
21
+ return typeof process !== 'undefined' && typeof process.env !== 'undefined' && typeof process.env.PYRIC_RUNTIME_CHIP === 'string';
22
+ }
23
+
24
+ /** Read plugin-authored values from DOM metadata or bundler environment variables, defaulting to collapsed UI when omitted. */
21
25
  export function readPyricRuntimeChipConfig(
22
26
  documentLike: RuntimeChipDocument,
23
27
  ): PyricRuntimeChipConfig | null {
24
28
  const meta = documentLike.querySelector(`meta[name="${PYRIC_RUNTIME_CHIP_META}"]`);
25
- const value = meta?.getAttribute('content');
26
- const studioEnabled = meta?.getAttribute('data-studio') !== 'off';
27
- if (value === 'collapsed') return { initiallyOpen: false, studioEnabled };
28
- if (value === 'expanded') return { initiallyOpen: true, studioEnabled };
29
- return null;
29
+ const hasMetaTag = meta !== null;
30
+ let value = hasMetaTag ? meta.getAttribute('content') : null;
31
+
32
+ const shouldFallbackToEnv = !hasMetaTag && hasBundlerRuntimeChipConfig();
33
+ if (shouldFallbackToEnv) {
34
+ value = process.env.PYRIC_RUNTIME_CHIP as string;
35
+ }
36
+ if (value === 'off') {
37
+ return null;
38
+ }
39
+
40
+ const studioEnabled = !hasMetaTag || meta.getAttribute('data-studio') !== 'off';
41
+ const initiallyOpen = value === 'expanded';
42
+ return { initiallyOpen, studioEnabled };
30
43
  }
@@ -94,9 +94,12 @@ const styles = `
94
94
  .errors { background: var(--pyric-content); border-bottom: 1px solid var(--pyric-border-soft); border-top: 1px solid var(--pyric-border-soft); max-height: 184px; min-height: 58px; overflow-y: auto; }
95
95
  .errors::-webkit-scrollbar { width: 8px; }
96
96
  .errors::-webkit-scrollbar-thumb { background: #33333f; border-radius: 4px; }
97
- .error-row { align-items: flex-start; border-bottom: 1px solid rgba(42,42,53,.7); display: grid; gap: 8px; grid-template-columns: 18px minmax(0,1fr) 28px; padding: 10px 8px 10px 12px; }
97
+ .error-row { align-items: flex-start; border-bottom: 1px solid rgba(42,42,53,.7); display: grid; gap: 8px; grid-template-columns: 18px minmax(0,1fr) 28px 28px; padding: 10px 8px 10px 12px; }
98
98
  .error-row:last-child { border-bottom: 0; }
99
99
  .error-number { color: var(--pyric-error); font: 10px/20px ui-monospace, monospace; }
100
+ .panel-controls { align-items: center; display: inline-flex; gap: 4px; }
101
+ .clear-button { background: transparent; border: 0; color: var(--pyric-muted); cursor: pointer; font-size: 11px; margin-left: 8px; padding: 2px 6px; }
102
+ .clear-button:hover { color: var(--pyric-text); }
100
103
  .error-body { min-width: 0; }
101
104
  .error-body code { color: #d7d7df; display: block; font-size: 11px; line-height: 1.55; overflow-wrap: anywhere; white-space: pre-wrap; }
102
105
  .error-meta { color: var(--pyric-muted); font: 9px/1.4 ui-monospace, monospace; margin-top: 4px; overflow-wrap: anywhere; }
@@ -122,6 +125,7 @@ const styles = `
122
125
 
123
126
  const icons = {
124
127
  close: '<svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="m6 6 12 12M18 6 6 18"/></svg>',
128
+ minimize: '<svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M5 12h14"/></svg>',
125
129
  copy: '<svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="8" y="8" width="11" height="11" rx="1"/><path d="M16 8V5H5v11h3"/></svg>',
126
130
  chevron: '<svg class="chevron" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="m6 15 6-6 6 6"/></svg>',
127
131
  external: '<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M14 5h5v5M19 5l-8 8"/><path d="M19 13v6H5V5h6"/></svg>',
@@ -148,6 +152,7 @@ function renderErrors(snapshot: PyricRuntimeSnapshot, canCopy: boolean): string
148
152
  <span class="error-number">${String(index + 1).padStart(2, '0')}</span>
149
153
  <div class="error-body"><code></code><div class="error-meta"></div></div>
150
154
  <button class="icon-button" type="button" data-copy-error="${escapeAttribute(error.id)}" aria-label="${canCopy ? `Copy error ${index + 1}` : 'Copy unavailable'}" title="${canCopy ? 'Copy error' : 'Clipboard unavailable'}" ${canCopy ? '' : 'disabled'}>${icons.copy}</button>
155
+ <button class="icon-button" type="button" data-dismiss-error="${escapeAttribute(error.id)}" aria-label="Dismiss error ${index + 1}" title="Dismiss error">${icons.close}</button>
151
156
  </div>
152
157
  `).join('');
153
158
  }
@@ -202,8 +207,11 @@ export function mountPyricRuntimeChip(options: PyricRuntimeChipOptions): PyricRu
202
207
  view.innerHTML = `${open ? `
203
208
  <section class="panel" role="dialog" aria-label="Pyric runtime">
204
209
  <header class="panel-header">
205
- <div class="panel-title"><span class="brand-mark">&gt;_</span><strong>Pyric runtime</strong>${errorCount > 0 ? `<span class="count">${errorCount} ${errorCount === 1 ? 'error' : 'errors'}</span>` : ''}</div>
206
- <button class="icon-button" type="button" data-collapse aria-label="Collapse Pyric runtime">${icons.close}</button>
210
+ <div class="panel-title"><span class="brand-mark">&gt;_</span><strong>Pyric runtime</strong>${errorCount > 0 ? `<span class="count">${errorCount} ${errorCount === 1 ? 'error' : 'errors'}</span><button class="clear-button" type="button" data-clear-errors aria-label="Clear all errors">Clear</button>` : ''}</div>
211
+ <div class="panel-controls">
212
+ <button class="icon-button" type="button" data-collapse aria-label="Minimize Pyric runtime">${icons.minimize}</button>
213
+ <button class="icon-button" type="button" data-dismiss-chip aria-label="Dismiss Pyric runtime from page">${icons.close}</button>
214
+ </div>
207
215
  </header>
208
216
  <div class="worker-state"><span class="state-label${snapshot.updateAvailable ? ' available' : ''}"><span class="mini-dot"></span>${workerLabel}</span><span class="epochs">${epochs}</span></div>
209
217
  <div class="errors" data-error-viewport>${renderErrors(snapshot, Boolean(clipboard))}</div>
@@ -247,6 +255,12 @@ export function mountPyricRuntimeChip(options: PyricRuntimeChipOptions): PyricRu
247
255
  render();
248
256
  root.querySelector<HTMLButtonElement>('[data-expand]')?.focus();
249
257
  });
258
+ root.querySelector('[data-clear-errors]')?.addEventListener('click', () => {
259
+ options.runtime.clearErrors();
260
+ });
261
+ root.querySelector('[data-dismiss-chip]')?.addEventListener('click', () => {
262
+ host.style.display = 'none';
263
+ });
250
264
  root.querySelector('[data-update-worker]')?.addEventListener('click', () => {
251
265
  if (!snapshot.updateAvailable || snapshot.updatingWorker) return;
252
266
  void options.runtime.updateWorker().catch(() => { /* status records and renders the failure */ });
@@ -262,6 +276,13 @@ export function mountPyricRuntimeChip(options: PyricRuntimeChipOptions): PyricRu
262
276
  });
263
277
  });
264
278
  }
279
+ for (const button of root.querySelectorAll<HTMLButtonElement>('[data-dismiss-error]')) {
280
+ button.addEventListener('click', () => {
281
+ if (button.dataset.dismissError) {
282
+ options.runtime.dismissError(button.dataset.dismissError);
283
+ }
284
+ });
285
+ }
265
286
  if (focusToken) {
266
287
  const candidates = root.querySelectorAll<HTMLElement>(`[${focusToken.attribute}]`);
267
288
  const replacement = [...candidates].find((candidate) =>
@@ -36,6 +36,7 @@ export interface PyricRuntimeStatus {
36
36
  reportError(error: unknown, source: PyricRuntimeErrorSource): void;
37
37
  recordSandboxEvents(events: readonly SandboxEvent[]): void;
38
38
  clearErrors(): void;
39
+ dismissError(id: string): void;
39
40
  }
40
41
 
41
42
  let nextErrorId = 0;
@@ -77,41 +78,95 @@ export function normalizePyricRuntimeError(
77
78
  return { id, source, at, message: String(value) };
78
79
  }
79
80
 
81
+ function isOperationOrRequestEvent(event: SandboxEvent): boolean {
82
+ const isOperationKind = event.kind === 'operation';
83
+ const isRequestKind = event.kind === 'request';
84
+ return isOperationKind || isRequestKind;
85
+ }
86
+
87
+ function isDeniedOperationEvent(event: SandboxEvent): boolean {
88
+ const isTargetEventKind = isOperationOrRequestEvent(event);
89
+ const hasResultProperty = 'result' in event;
90
+ const isDeniedResult = hasResultProperty && event.result === 'deny';
91
+ return isTargetEventKind && isDeniedResult;
92
+ }
93
+
94
+ function isRuntimeErrorEvent(event: SandboxEvent): boolean {
95
+ return event.kind === 'runtime_error';
96
+ }
97
+
98
+ function isListenerErroredEvent(event: SandboxEvent): boolean {
99
+ const isListenerErroredKind = event.kind === 'listener_errored';
100
+ const hasErrorPayload = 'error' in event && Boolean(event.error);
101
+ return isListenerErroredKind && hasErrorPayload;
102
+ }
103
+
104
+ function isListenerPhaseErroredEvent(event: SandboxEvent): boolean {
105
+ const isListenerKind = event.kind === 'listener';
106
+ const isErroredPhase = 'phase' in event && event.phase === 'errored';
107
+ const hasErrorPayload = 'error' in event && Boolean(event.error);
108
+ return isListenerKind && isErroredPhase && hasErrorPayload;
109
+ }
110
+
80
111
  function sandboxError(event: SandboxEvent): PyricRuntimeError | null {
81
- if (event.kind === 'runtime_error') {
112
+ if (isRuntimeErrorEvent(event)) {
113
+ const hasPathProperty = 'path' in event && typeof event.path === 'string';
114
+ const targetPath = hasPathProperty ? event.path : undefined;
115
+ const hasMethodProperty = 'method' in event && typeof event.method === 'string';
116
+ const targetMethod = hasMethodProperty ? event.method : 'unknown';
117
+ const hasErrorPayload = 'error' in event && Boolean(event.error);
118
+ const errorPayload = hasErrorPayload ? (event as { error: { code?: string; message: string } }).error : undefined;
82
119
  return {
83
120
  id: event.id,
84
121
  source: 'sandbox',
85
122
  at: event.at,
86
123
  service: event.service,
87
- method: event.method,
88
- ...(event.path ? { path: event.path } : {}),
89
- ...(event.error.code ? { code: event.error.code } : {}),
90
- message: event.error.message,
124
+ method: targetMethod,
125
+ ...(targetPath ? { path: targetPath } : {}),
126
+ ...(errorPayload?.code ? { code: errorPayload.code } : {}),
127
+ message: errorPayload?.message ? errorPayload.message : 'Sandbox runtime error',
91
128
  };
92
129
  }
93
- if (event.kind === 'listener_errored' && event.error) {
130
+ if (isListenerErroredEvent(event)) {
131
+ const errorPayload = (event as { error: { code?: string; message: string } }).error;
94
132
  return {
95
133
  id: event.id,
96
134
  source: 'sandbox',
97
135
  at: event.at,
98
136
  service: 'firestore',
99
137
  method: 'listener',
100
- ...('path' in event.target ? { path: event.target.path } : {}),
101
- code: event.error.code,
102
- message: event.error.message,
138
+ ...('target' in event && event.target && 'path' in event.target ? { path: event.target.path } : {}),
139
+ code: errorPayload.code,
140
+ message: errorPayload.message,
103
141
  };
104
142
  }
105
- if (event.kind === 'listener' && event.phase === 'errored' && event.error) {
143
+ if (isListenerPhaseErroredEvent(event)) {
144
+ const errorPayload = (event as { error: { code?: string; message: string } }).error;
106
145
  return {
107
146
  id: event.id,
108
147
  source: 'sandbox',
109
148
  at: event.at,
110
149
  service: event.service,
111
150
  method: 'listener',
112
- ...(event.target.path ? { path: event.target.path } : {}),
113
- ...(event.error.code ? { code: event.error.code } : {}),
114
- message: event.error.message,
151
+ ...('target' in event && event.target && 'path' in event.target ? { path: event.target.path } : {}),
152
+ ...(errorPayload.code ? { code: errorPayload.code } : {}),
153
+ message: errorPayload.message,
154
+ };
155
+ }
156
+ if (isDeniedOperationEvent(event)) {
157
+ const hasPathProperty = 'path' in event && typeof event.path === 'string';
158
+ const targetPath = hasPathProperty ? event.path : '(service)';
159
+ const hasMethodProperty = 'method' in event && typeof event.method === 'string';
160
+ const targetMethod = hasMethodProperty ? event.method : 'operation';
161
+ return {
162
+ id: event.id,
163
+ source: 'sandbox',
164
+ at: event.at,
165
+ service: event.service,
166
+ method: targetMethod,
167
+ path: targetPath,
168
+ code: 'PERMISSION_DENIED',
169
+ message: `PERMISSION_DENIED: ${targetMethod} on ${targetPath} denied by rules`,
115
170
  };
116
171
  }
117
172
  return null;
@@ -201,6 +256,14 @@ export function createPyricRuntimeStatus(
201
256
  errorIds.clear();
202
257
  publish({ ...snapshot, errors: [] });
203
258
  },
259
+ dismissError(id) {
260
+ if (!errorIds.has(id)) return;
261
+ errorIds.delete(id);
262
+ publish({
263
+ ...snapshot,
264
+ errors: snapshot.errors.filter((err) => err.id !== id),
265
+ });
266
+ },
204
267
  };
205
268
  }
206
269
 
@@ -63,6 +63,7 @@ export interface SandboxSession {
63
63
  payload(): InitPayload;
64
64
  handle(req: IncomingMessage, res: ServerResponse, url: URL): boolean | Promise<boolean>;
65
65
  reloadFirestoreRules(): Promise<RulesReloadResult>;
66
+ reloadDatabaseRules(): Promise<RulesReloadResult>;
66
67
  close(): Promise<void>;
67
68
  }
68
69
 
@@ -93,6 +94,8 @@ export async function createSandboxSession(
93
94
  const live = {
94
95
  rules: firestore.rules,
95
96
  rulesHash: firestore.rulesHash,
97
+ databaseRules: database.rules,
98
+ databaseRulesHash: database.rulesHash,
96
99
  };
97
100
  const events = createEventHub();
98
101
  const capture: CaptureStore | undefined = (options.capture ?? true)
@@ -145,8 +148,8 @@ export async function createSandboxSession(
145
148
  const payload = (): InitPayload => ({
146
149
  rules: live.rules,
147
150
  rulesHash: live.rulesHash,
148
- databaseRules: database.rules,
149
- databaseRulesHash: database.rulesHash,
151
+ databaseRules: live.databaseRules,
152
+ databaseRulesHash: live.databaseRulesHash,
150
153
  databaseUrl: database.databaseUrl,
151
154
  storageRules: storage.rules,
152
155
  storageRulesHash: storage.rulesHash,
@@ -217,6 +220,31 @@ export async function createSandboxSession(
217
220
  return { kind: 'rejected', error: error instanceof Error ? error : new Error(String(error)) };
218
221
  }
219
222
  };
223
+ const reloadDatabaseRules = async (): Promise<RulesReloadResult> => {
224
+ const isMissingDatabaseRules = database.sourcePath === null;
225
+ if (isMissingDatabaseRules) {
226
+ return { kind: 'not-configured' };
227
+ }
228
+ try {
229
+ const updated = await loadProjectDatabaseRules(options.projectDir, options.firebaseConfig);
230
+ const isMissingUpdatedRules = updated.rules === null || updated.rulesHash === null;
231
+ if (isMissingUpdatedRules) {
232
+ return { kind: 'not-configured' };
233
+ }
234
+ live.databaseRules = updated.rules;
235
+ live.databaseRulesHash = updated.rulesHash;
236
+ events.broadcast('rtdb-rules-update', { rules: updated.rules, rulesHash: updated.rulesHash });
237
+ return { kind: 'reloaded', rulesHash: updated.rulesHash as string, clients: events.clientCount() };
238
+ } catch (error) {
239
+ const isErrorInstance = error instanceof Error;
240
+ let errorResult: Error = new Error(String(error));
241
+ if (isErrorInstance) {
242
+ errorResult = error as Error;
243
+ }
244
+ return { kind: 'rejected', error: errorResult };
245
+ }
246
+ };
247
+
220
248
  let closePromise: Promise<void> | null = null;
221
249
  const close = (): Promise<void> => {
222
250
  closePromise ??= Promise.resolve().then(() => events.close());
@@ -228,6 +256,7 @@ export async function createSandboxSession(
228
256
  payload,
229
257
  handle: namespace,
230
258
  reloadFirestoreRules,
259
+ reloadDatabaseRules,
231
260
  close,
232
261
  };
233
262
  }
@@ -9,6 +9,8 @@ const AI_PROXY_PATH = '/__pyric/ai-proxy';
9
9
  export type PyricAiEngineConfig = Extract<NonNullable<AIOptions['engine']>, { kind: string }>;
10
10
 
11
11
  export interface PyricAiOptions {
12
+ /** Mode for AI Logic: 'sandbox' (local mirrors) or 'production' (pass-through to Google AI / Vertex AI). */
13
+ mode?: 'sandbox' | 'production';
12
14
  /** Simple OpenAI-compatible model selection through Pyric's same-origin proxy. */
13
15
  model?: string;
14
16
  /** Advanced declarative engine configuration. */
@@ -18,6 +20,7 @@ export interface PyricAiOptions {
18
20
  }
19
21
 
20
22
  export interface ResolvedViteAiConfig {
23
+ mode: 'sandbox' | 'production';
21
24
  engineWire: AiEngineConfigWire | undefined;
22
25
  proxyUpstream: string | undefined;
23
26
  }
@@ -26,8 +29,9 @@ export interface ResolvedViteAiConfig {
26
29
  export function viteWorkerEpochSalt(
27
30
  projectKey: string,
28
31
  engineWire: AiEngineConfigWire | undefined,
32
+ mode: 'sandbox' | 'production' = 'sandbox',
29
33
  ): string {
30
- return JSON.stringify({ projectKey, aiEngine: engineWire ?? null });
34
+ return JSON.stringify({ projectKey, aiEngine: engineWire ?? null, aiMode: mode });
31
35
  }
32
36
 
33
37
  /** Load env using Vite's `envDir`-relative-to-root convention. */
@@ -45,20 +49,30 @@ export function loadViteAiEnv(
45
49
 
46
50
  /** Convert a public declarative engine into the JSON-safe worker wire shape. */
47
51
  export function engineConfigToWire(engine: PyricAiEngineConfig): AiEngineConfigWire {
48
- if (engine.kind === 'openai') {
49
- return {
52
+ const isOpenAiEngine = engine.kind === 'openai';
53
+ if (isOpenAiEngine) {
54
+ const result: Record<string, unknown> = {
50
55
  kind: 'openai',
51
- baseUrl: engine.baseUrl ?? AI_PROXY_PATH,
52
- ...(engine.model !== undefined ? { model: engine.model } : {}),
53
- ...(engine.modelMap !== undefined ? { modelMap: engine.modelMap } : {}),
56
+ baseUrl: engine.baseUrl !== undefined && engine.baseUrl !== null ? engine.baseUrl : AI_PROXY_PATH,
54
57
  };
58
+ const hasModel = engine.model !== undefined;
59
+ if (hasModel) {
60
+ result.model = engine.model;
61
+ }
62
+ const hasModelMap = engine.modelMap !== undefined;
63
+ if (hasModelMap) {
64
+ result.modelMap = engine.modelMap;
65
+ }
66
+ return result as AiEngineConfigWire;
55
67
  }
56
- return {
68
+ const result: Record<string, unknown> = {
57
69
  kind: 'scripted',
58
- ...(engine.script !== undefined
59
- ? { script: engine.script as unknown as Array<Record<string, unknown>> }
60
- : {}),
61
70
  };
71
+ const hasScript = engine.script !== undefined;
72
+ if (hasScript) {
73
+ result.script = engine.script as unknown as Array<Record<string, unknown>>;
74
+ }
75
+ return result as AiEngineConfigWire;
62
76
  }
63
77
 
64
78
  /** Resolve the plugin's explicit-options-over-Vite-env AI convention. */
@@ -66,20 +80,73 @@ export function resolveViteAiConfig(
66
80
  options: PyricAiOptions | undefined,
67
81
  env: Record<string, string | undefined>,
68
82
  ): ResolvedViteAiConfig {
69
- if (options?.model !== undefined && options.engine !== undefined) {
83
+ const explicitModel = options?.model;
84
+ const explicitEngine = options?.engine;
85
+ const hasModelOption = explicitModel !== undefined;
86
+ const hasEngineOption = explicitEngine !== undefined;
87
+ const hasBothModelAndEngine = hasModelOption && hasEngineOption;
88
+ if (hasBothModelAndEngine) {
70
89
  throw new Error('@pyric/cli/vite: Choose either ai.model or ai.engine, not both.');
71
90
  }
72
91
 
73
- const model = options?.model?.trim() || env.PYRIC_AI_MODEL?.trim();
74
- const engineWire = options?.engine
75
- ? engineConfigToWire(options.engine)
76
- : model
77
- ? engineConfigToWire({ kind: 'openai', baseUrl: AI_PROXY_PATH, model })
78
- : undefined;
92
+ let mode: 'sandbox' | 'production' = 'sandbox';
93
+ const explicitMode = options?.mode;
94
+ const hasExplicitMode = explicitMode !== undefined;
95
+ if (hasExplicitMode) {
96
+ mode = explicitMode;
97
+ } else {
98
+ const isEnvProductionMode = env.PYRIC_AI_MODE === 'production';
99
+ const isEnvPassthroughFlag = env.PYRIC_AI_PASSTHROUGH === '1';
100
+ const isProductionEnv = isEnvProductionMode || isEnvPassthroughFlag;
101
+ if (isProductionEnv) {
102
+ mode = 'production';
103
+ }
104
+ }
105
+
106
+ const isProductionMode = mode === 'production';
107
+ const hasAnyEngineConfig = hasModelOption || hasEngineOption;
108
+ const isInvalidProductionConfig = isProductionMode && hasAnyEngineConfig;
109
+ if (isInvalidProductionConfig) {
110
+ throw new Error('@pyric/cli/vite: Cannot configure ai.model or ai.engine when ai.mode is set to "production".');
111
+ }
112
+
113
+ let model: string | undefined = undefined;
114
+ const envModel = env.PYRIC_AI_MODEL;
115
+ if (explicitModel !== undefined) {
116
+ model = explicitModel.trim();
117
+ } else if (envModel !== undefined) {
118
+ model = envModel.trim();
119
+ }
120
+ const hasNonEmptyModel = model !== undefined && model !== '';
121
+ if (!hasNonEmptyModel) {
122
+ model = undefined;
123
+ }
124
+
125
+ let engineWire: AiEngineConfigWire | undefined = undefined;
126
+ if (!isProductionMode) {
127
+ if (explicitEngine !== undefined) {
128
+ engineWire = engineConfigToWire(explicitEngine);
129
+ } else if (model !== undefined) {
130
+ engineWire = engineConfigToWire({ kind: 'openai', baseUrl: AI_PROXY_PATH, model });
131
+ }
132
+ }
133
+
134
+ let proxyUpstream: string | undefined = undefined;
135
+ const explicitProxyUpstream = options?.proxyUpstream;
136
+ const envProxyUpstream = env.PYRIC_AI_PROXY_UPSTREAM;
137
+ if (explicitProxyUpstream !== undefined) {
138
+ proxyUpstream = explicitProxyUpstream.trim();
139
+ } else if (envProxyUpstream !== undefined) {
140
+ proxyUpstream = envProxyUpstream.trim();
141
+ }
142
+ const hasNonEmptyProxyUpstream = proxyUpstream !== undefined && proxyUpstream !== '';
143
+ if (!hasNonEmptyProxyUpstream) {
144
+ proxyUpstream = undefined;
145
+ }
79
146
 
80
147
  return {
148
+ mode,
81
149
  engineWire,
82
- proxyUpstream:
83
- options?.proxyUpstream?.trim() || env.PYRIC_AI_PROXY_UPSTREAM?.trim() || undefined,
150
+ proxyUpstream,
84
151
  };
85
152
  }
@@ -144,6 +144,7 @@ export function attachViteFunctionsDevelopment(
144
144
  registerUrl: options.registerUrl,
145
145
  instance: options.instance ?? `${options.projectId}-default-rtdb`,
146
146
  location: options.region ?? options.baseEnv.PYRIC_FUNCTIONS_RTDB_REGION ?? 'us-central1',
147
+ projectId: options.projectId,
147
148
  readiness: createInProcessFunctionsPeerReadiness(bridge.sandboxConnected),
148
149
  onEvent: (event) => reportEvent(options.logger, event),
149
150
  ...(options.childModuleUrl === undefined ? {} : { childModuleUrl: options.childModuleUrl }),
@@ -8,30 +8,82 @@ export function watchViteGenerationRules(input: {
8
8
  session: SandboxSession;
9
9
  }): (() => void) | null {
10
10
  const { server, session } = input;
11
- const rulesFile = session.summary.rules.firestore.sourcePath;
12
- if (!rulesFile) return null;
11
+ const firestoreFile = session.summary.rules.firestore.sourcePath;
12
+ const databaseFile = session.summary.rules.database.sourcePath;
13
+ const hasFirestoreFile = firestoreFile !== null;
14
+ const hasDatabaseFile = databaseFile !== null;
15
+ const hasNeitherFile = !hasFirestoreFile && !hasDatabaseFile;
16
+ if (hasNeitherFile) {
17
+ return null;
18
+ }
13
19
 
14
20
  let debounce: ReturnType<typeof setTimeout> | null = null;
15
21
  const onRulesChange = (file: string): void => {
16
- if (path.resolve(file) !== path.resolve(rulesFile)) return;
17
- if (debounce) clearTimeout(debounce);
22
+ const resolvedFile = path.resolve(file);
23
+ let isFirestoreMatch = false;
24
+ if (hasFirestoreFile) {
25
+ const firestoreResolved = path.resolve(firestoreFile);
26
+ isFirestoreMatch = resolvedFile === firestoreResolved;
27
+ }
28
+ let isDatabaseMatch = false;
29
+ if (hasDatabaseFile) {
30
+ const databaseResolved = path.resolve(databaseFile);
31
+ isDatabaseMatch = resolvedFile === databaseResolved;
32
+ }
33
+ const isNeitherMatch = !isFirestoreMatch && !isDatabaseMatch;
34
+ if (isNeitherMatch) {
35
+ return;
36
+ }
37
+ const hasDebounce = debounce !== null;
38
+ if (hasDebounce) {
39
+ clearTimeout(debounce as ReturnType<typeof setTimeout>);
40
+ }
18
41
  debounce = setTimeout(() => {
19
- void session.reloadFirestoreRules().then((result) => {
20
- if (result.kind === 'reloaded') {
21
- server.config.logger.info(` ↻ [pyric] rules reloaded (${result.rulesHash})`);
22
- } else if (result.kind === 'rejected') {
23
- server.config.logger.warn(
24
- ` ⚠ [pyric] rules NOT reloaded (last-good stays live): ${result.error.message}`,
25
- );
26
- }
27
- });
42
+ if (isFirestoreMatch) {
43
+ void session.reloadFirestoreRules().then((result) => {
44
+ const isReloaded = result.kind === 'reloaded';
45
+ if (isReloaded) {
46
+ server.config.logger.info(` ↻ [pyric] rules reloaded (${result.rulesHash})`);
47
+ } else {
48
+ const isRejected = result.kind === 'rejected';
49
+ if (isRejected) {
50
+ server.config.logger.warn(
51
+ ` ⚠ [pyric] rules NOT reloaded (last-good stays live): ${result.error.message}`,
52
+ );
53
+ }
54
+ }
55
+ });
56
+ }
57
+ if (isDatabaseMatch) {
58
+ void session.reloadDatabaseRules().then((result) => {
59
+ const isReloaded = result.kind === 'reloaded';
60
+ if (isReloaded) {
61
+ server.config.logger.info(` ↻ [pyric] rtdb rules reloaded (${result.rulesHash})`);
62
+ } else {
63
+ const isRejected = result.kind === 'rejected';
64
+ if (isRejected) {
65
+ server.config.logger.warn(
66
+ ` ⚠ [pyric] rtdb rules NOT reloaded (last-good stays live): ${result.error.message}`,
67
+ );
68
+ }
69
+ }
70
+ });
71
+ }
28
72
  }, 150);
29
73
  };
30
74
 
31
- server.watcher.add(rulesFile);
75
+ if (hasFirestoreFile) {
76
+ server.watcher.add(firestoreFile);
77
+ }
78
+ if (hasDatabaseFile) {
79
+ server.watcher.add(databaseFile);
80
+ }
32
81
  server.watcher.on('change', onRulesChange);
33
82
  return () => {
34
- if (debounce) clearTimeout(debounce);
83
+ const hasDebounce = debounce !== null;
84
+ if (hasDebounce) {
85
+ clearTimeout(debounce as ReturnType<typeof setTimeout>);
86
+ }
35
87
  server.watcher.off('change', onRulesChange);
36
88
  };
37
89
  }