@pyric/cli 0.1.0-alpha.20 → 0.1.0-alpha.21

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 (491) hide show
  1. package/README.md +64 -89
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +68 -1
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +68 -1
  5. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  6. package/dist/bridge/client/dispatch.d.ts +25 -19
  7. package/dist/bridge/client/dispatch.d.ts.map +1 -1
  8. package/dist/bridge/client/dispatch.js +41 -48
  9. package/dist/bridge/client/dispatch.js.map +1 -1
  10. package/dist/bridge/client/tool-family-factories.d.ts +26 -0
  11. package/dist/bridge/client/tool-family-factories.d.ts.map +1 -0
  12. package/dist/bridge/client/tool-family-factories.js +10 -0
  13. package/dist/bridge/client/tool-family-factories.js.map +1 -0
  14. package/dist/bridge/server/mcp-contract.d.ts +7 -6
  15. package/dist/bridge/server/mcp-contract.d.ts.map +1 -1
  16. package/dist/bridge/server/mcp-contract.js +9 -48
  17. package/dist/bridge/server/mcp-contract.js.map +1 -1
  18. package/dist/bridge/server/peer.d.ts +11 -1
  19. package/dist/bridge/server/peer.d.ts.map +1 -1
  20. package/dist/bridge/server/peer.js +22 -1
  21. package/dist/bridge/server/peer.js.map +1 -1
  22. package/dist/bridge/server/tool-family-factories.d.ts +30 -0
  23. package/dist/bridge/server/tool-family-factories.d.ts.map +1 -0
  24. package/dist/bridge/server/tool-family-factories.js +22 -0
  25. package/dist/bridge/server/tool-family-factories.js.map +1 -0
  26. package/dist/bridge/server/tool-metadata.d.ts +17 -18
  27. package/dist/bridge/server/tool-metadata.d.ts.map +1 -1
  28. package/dist/bridge/server/tool-metadata.js +24 -59
  29. package/dist/bridge/server/tool-metadata.js.map +1 -1
  30. package/dist/bridge/tool-families.d.ts +48 -0
  31. package/dist/bridge/tool-families.d.ts.map +1 -0
  32. package/dist/bridge/tool-families.generated.d.ts +32 -0
  33. package/dist/bridge/tool-families.generated.d.ts.map +1 -0
  34. package/dist/bridge/tool-families.generated.js +15 -0
  35. package/dist/bridge/tool-families.generated.js.map +1 -0
  36. package/dist/bridge/tool-families.js +51 -0
  37. package/dist/bridge/tool-families.js.map +1 -0
  38. package/dist/bridge/tool-family-records/conformance.d.ts +7 -0
  39. package/dist/bridge/tool-family-records/conformance.d.ts.map +1 -0
  40. package/dist/bridge/tool-family-records/conformance.js +6 -0
  41. package/dist/bridge/tool-family-records/conformance.js.map +1 -0
  42. package/dist/bridge/tool-family-records/firestore-data.d.ts +7 -0
  43. package/dist/bridge/tool-family-records/firestore-data.d.ts.map +1 -0
  44. package/dist/bridge/tool-family-records/firestore-data.js +15 -0
  45. package/dist/bridge/tool-family-records/firestore-data.js.map +1 -0
  46. package/dist/bridge/tool-family-records/firestore-inspect.d.ts +7 -0
  47. package/dist/bridge/tool-family-records/firestore-inspect.d.ts.map +1 -0
  48. package/dist/bridge/tool-family-records/firestore-inspect.js +6 -0
  49. package/dist/bridge/tool-family-records/firestore-inspect.js.map +1 -0
  50. package/dist/bridge/tool-family-records/firestore-rules.d.ts +7 -0
  51. package/dist/bridge/tool-family-records/firestore-rules.d.ts.map +1 -0
  52. package/dist/bridge/tool-family-records/firestore-rules.js +15 -0
  53. package/dist/bridge/tool-family-records/firestore-rules.js.map +1 -0
  54. package/dist/bridge/tool-family-records/firestore-simulator.d.ts +7 -0
  55. package/dist/bridge/tool-family-records/firestore-simulator.d.ts.map +1 -0
  56. package/dist/bridge/tool-family-records/firestore-simulator.js +16 -0
  57. package/dist/bridge/tool-family-records/firestore-simulator.js.map +1 -0
  58. package/dist/bridge/tool-family-records/rtdb-inspection.d.ts +7 -0
  59. package/dist/bridge/tool-family-records/rtdb-inspection.d.ts.map +1 -0
  60. package/dist/bridge/tool-family-records/rtdb-inspection.js +6 -0
  61. package/dist/bridge/tool-family-records/rtdb-inspection.js.map +1 -0
  62. package/dist/bundler/externals.d.ts +37 -0
  63. package/dist/bundler/externals.d.ts.map +1 -0
  64. package/dist/bundler/externals.js +52 -0
  65. package/dist/bundler/externals.js.map +1 -0
  66. package/dist/bundler/index.d.ts +17 -0
  67. package/dist/bundler/index.d.ts.map +1 -0
  68. package/dist/bundler/index.js +17 -0
  69. package/dist/bundler/index.js.map +1 -0
  70. package/dist/cli/inlined-sdk-scanner.d.ts +6 -0
  71. package/dist/cli/inlined-sdk-scanner.d.ts.map +1 -0
  72. package/dist/cli/inlined-sdk-scanner.js +82 -0
  73. package/dist/cli/inlined-sdk-scanner.js.map +1 -0
  74. package/dist/cli/sandbox-interlock.d.ts +97 -0
  75. package/dist/cli/sandbox-interlock.d.ts.map +1 -0
  76. package/dist/cli/sandbox-interlock.js +112 -0
  77. package/dist/cli/sandbox-interlock.js.map +1 -0
  78. package/dist/cli/sandbox-runner.d.ts +20 -12
  79. package/dist/cli/sandbox-runner.d.ts.map +1 -1
  80. package/dist/cli/sandbox-runner.js +24 -21
  81. package/dist/cli/sandbox-runner.js.map +1 -1
  82. package/dist/cli/serve.d.ts +6 -10
  83. package/dist/cli/serve.d.ts.map +1 -1
  84. package/dist/cli/serve.js +57 -77
  85. package/dist/cli/serve.js.map +1 -1
  86. package/dist/cli/unsupported-runtime.d.ts +27 -0
  87. package/dist/cli/unsupported-runtime.d.ts.map +1 -0
  88. package/dist/cli/unsupported-runtime.js +63 -0
  89. package/dist/cli/unsupported-runtime.js.map +1 -0
  90. package/dist/conformance/.generated/can-i-use-browser.d.ts +1 -1
  91. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  92. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  93. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  94. package/dist/conformance/.generated/can-i-use.d.ts +1 -1
  95. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  96. package/dist/conformance/.generated/can-i-use.js +1 -1
  97. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  98. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
  99. package/dist/conformance/.generated/conformance-docs.js +1 -1
  100. package/dist/conformance/.generated/conformance-docs.js.map +1 -1
  101. package/dist/functions-rtdb/child.d.ts +37 -0
  102. package/dist/functions-rtdb/child.d.ts.map +1 -1
  103. package/dist/functions-rtdb/child.js +90 -21
  104. package/dist/functions-rtdb/child.js.map +1 -1
  105. package/dist/functions-rtdb/development-runtime.d.ts +3 -0
  106. package/dist/functions-rtdb/development-runtime.d.ts.map +1 -1
  107. package/dist/functions-rtdb/development-runtime.js +1 -0
  108. package/dist/functions-rtdb/development-runtime.js.map +1 -1
  109. package/dist/google-endpoints.d.ts +67 -0
  110. package/dist/google-endpoints.d.ts.map +1 -0
  111. package/dist/google-endpoints.js +119 -0
  112. package/dist/google-endpoints.js.map +1 -0
  113. package/dist/next/runtime-env.d.ts.map +1 -1
  114. package/dist/next/runtime-env.js +5 -0
  115. package/dist/next/runtime-env.js.map +1 -1
  116. package/dist/next/with-pyric.d.ts +1 -1
  117. package/dist/next/with-pyric.js +1 -1
  118. package/dist/register/beacon.d.ts +69 -0
  119. package/dist/register/beacon.d.ts.map +1 -0
  120. package/dist/register/beacon.js +199 -0
  121. package/dist/register/beacon.js.map +1 -0
  122. package/dist/register/index.d.ts.map +1 -1
  123. package/dist/register/index.js +65 -6
  124. package/dist/register/index.js.map +1 -1
  125. package/dist/register/net-guard.d.ts +110 -0
  126. package/dist/register/net-guard.d.ts.map +1 -0
  127. package/dist/register/net-guard.js +462 -0
  128. package/dist/register/net-guard.js.map +1 -0
  129. package/dist/serve/ai-diagnostics-relay.d.ts +63 -0
  130. package/dist/serve/ai-diagnostics-relay.d.ts.map +1 -0
  131. package/dist/serve/ai-diagnostics-relay.js +125 -0
  132. package/dist/serve/ai-diagnostics-relay.js.map +1 -0
  133. package/dist/serve/ai-proxy.d.ts +92 -0
  134. package/dist/serve/ai-proxy.d.ts.map +1 -0
  135. package/dist/serve/ai-proxy.js +269 -0
  136. package/dist/serve/ai-proxy.js.map +1 -0
  137. package/dist/serve/ai-status.d.ts +44 -0
  138. package/dist/serve/ai-status.d.ts.map +1 -0
  139. package/dist/serve/ai-status.js +77 -0
  140. package/dist/serve/ai-status.js.map +1 -0
  141. package/dist/serve/ai-terminal-blocks.d.ts +97 -0
  142. package/dist/serve/ai-terminal-blocks.d.ts.map +1 -0
  143. package/dist/serve/ai-terminal-blocks.js +128 -0
  144. package/dist/serve/ai-terminal-blocks.js.map +1 -0
  145. package/dist/serve/ai-terminal-text.d.ts +36 -0
  146. package/dist/serve/ai-terminal-text.d.ts.map +1 -0
  147. package/dist/serve/ai-terminal-text.js +48 -0
  148. package/dist/serve/ai-terminal-text.js.map +1 -0
  149. package/dist/serve/beacon-route.d.ts +53 -0
  150. package/dist/serve/beacon-route.d.ts.map +1 -0
  151. package/dist/serve/beacon-route.js +101 -0
  152. package/dist/serve/beacon-route.js.map +1 -0
  153. package/dist/serve/entries/active-auth-registry.d.ts +16 -0
  154. package/dist/serve/entries/active-auth-registry.d.ts.map +1 -0
  155. package/dist/serve/entries/active-auth-registry.js +48 -0
  156. package/dist/serve/entries/active-auth-registry.js.map +1 -0
  157. package/dist/serve/entries/active-auth.d.ts +18 -0
  158. package/dist/serve/entries/active-auth.d.ts.map +1 -0
  159. package/dist/serve/entries/active-auth.js +84 -0
  160. package/dist/serve/entries/active-auth.js.map +1 -0
  161. package/dist/serve/entries/auth-helper-core.d.ts +1 -0
  162. package/dist/serve/entries/auth-helper-core.d.ts.map +1 -1
  163. package/dist/serve/entries/auth-helper-core.js +4 -0
  164. package/dist/serve/entries/auth-helper-core.js.map +1 -1
  165. package/dist/serve/entries/auth-helper-dom.d.ts.map +1 -1
  166. package/dist/serve/entries/auth-helper-dom.js +28 -2
  167. package/dist/serve/entries/auth-helper-dom.js.map +1 -1
  168. package/dist/serve/entries/auth.d.ts.map +1 -1
  169. package/dist/serve/entries/auth.js +8 -0
  170. package/dist/serve/entries/auth.js.map +1 -1
  171. package/dist/serve/entries/bridge-url.d.ts +1 -1
  172. package/dist/serve/entries/bridge-url.js +1 -1
  173. package/dist/serve/entries/init.d.ts.map +1 -1
  174. package/dist/serve/entries/init.js +70 -4
  175. package/dist/serve/entries/init.js.map +1 -1
  176. package/dist/serve/entries/runtime.d.ts.map +1 -1
  177. package/dist/serve/entries/runtime.js +9 -0
  178. package/dist/serve/entries/runtime.js.map +1 -1
  179. package/dist/serve/namespace.d.ts +14 -5
  180. package/dist/serve/namespace.d.ts.map +1 -1
  181. package/dist/serve/namespace.js +57 -124
  182. package/dist/serve/namespace.js.map +1 -1
  183. package/dist/serve/runtime/chip-config.d.ts.map +1 -1
  184. package/dist/serve/runtime/chip-config.js +16 -2
  185. package/dist/serve/runtime/chip-config.js.map +1 -1
  186. package/dist/serve/runtime/chip-dialog.d.ts +18 -0
  187. package/dist/serve/runtime/chip-dialog.d.ts.map +1 -0
  188. package/dist/serve/runtime/chip-dialog.js +315 -0
  189. package/dist/serve/runtime/chip-dialog.js.map +1 -0
  190. package/dist/serve/runtime/chip-install.d.ts +2 -0
  191. package/dist/serve/runtime/chip-install.d.ts.map +1 -1
  192. package/dist/serve/runtime/chip-install.js +9 -4
  193. package/dist/serve/runtime/chip-install.js.map +1 -1
  194. package/dist/serve/runtime/chip-user-search.d.ts +16 -0
  195. package/dist/serve/runtime/chip-user-search.d.ts.map +1 -0
  196. package/dist/serve/runtime/chip-user-search.js +354 -0
  197. package/dist/serve/runtime/chip-user-search.js.map +1 -0
  198. package/dist/serve/runtime/chip.d.ts +10 -0
  199. package/dist/serve/runtime/chip.d.ts.map +1 -1
  200. package/dist/serve/runtime/chip.js +118 -15
  201. package/dist/serve/runtime/chip.js.map +1 -1
  202. package/dist/serve/runtime/identity.d.ts +17 -0
  203. package/dist/serve/runtime/identity.d.ts.map +1 -0
  204. package/dist/serve/runtime/identity.js +10 -0
  205. package/dist/serve/runtime/identity.js.map +1 -0
  206. package/dist/serve/sandbox-session.d.ts +7 -0
  207. package/dist/serve/sandbox-session.d.ts.map +1 -1
  208. package/dist/serve/sandbox-session.js +2 -0
  209. package/dist/serve/sandbox-session.js.map +1 -1
  210. package/dist/serve/site-ui/_astro/{RulesCodeEditor.XtDmHOlN.js → RulesCodeEditor.DsTAsKIa.js} +1 -1
  211. package/dist/serve/site-ui/_astro/app.BOr2kwae.js +115 -0
  212. package/dist/serve/site-ui/_astro/app.DhAcImFD.js +1 -0
  213. package/dist/serve/site-ui/_astro/{chess-showcase.B72XYeoh.js → chess-showcase.Bn_pP6UJ.js} +2 -2
  214. package/dist/serve/site-ui/_astro/{example-runtime.C25_lx6Z.js → example-runtime.CXopTGv7.js} +1 -1
  215. package/dist/serve/site-ui/_astro/sandbox-controls.rOuZTOUG.js +510 -0
  216. package/dist/serve/site-ui/_astro/{seed.Co0yUJY5.js → seed.03a08f9t.js} +2 -2
  217. package/dist/serve/site-ui/_astro/writes.BsPBG3dp.js +653 -0
  218. package/dist/serve/site-ui/auth/index.html +1 -1
  219. package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
  220. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +1 -1
  221. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
  222. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
  223. package/dist/serve/site-ui/docs/ai-compat/index.html +1 -1
  224. package/dist/serve/site-ui/docs/api-reference/index.html +8 -1
  225. package/dist/serve/site-ui/docs/api-reference.md +7 -0
  226. package/dist/serve/site-ui/docs/app-compat/index.html +1 -1
  227. package/dist/serve/site-ui/docs/auth-compat/index.html +3 -3
  228. package/dist/serve/site-ui/docs/auth-compat.md +2 -2
  229. package/dist/serve/site-ui/docs/build/ai-logic/index.html +6 -1
  230. package/dist/serve/site-ui/docs/build/ai-logic.md +6 -0
  231. package/dist/serve/site-ui/docs/build/authentication/index.html +1 -1
  232. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +1 -1
  233. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
  234. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +1 -1
  235. package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
  236. package/dist/serve/site-ui/docs/conformance-scores/index.html +6 -2
  237. package/dist/serve/site-ui/docs/conformance-scores.md +5 -1
  238. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +1 -1
  239. package/dist/serve/site-ui/docs/database-compat/index.html +44 -44
  240. package/dist/serve/site-ui/docs/database-compat.md +43 -43
  241. package/dist/serve/site-ui/docs/examples/chess/index.html +1 -1
  242. package/dist/serve/site-ui/docs/examples/index.html +1 -1
  243. package/dist/serve/site-ui/docs/firestore-compat/index.html +4 -4
  244. package/dist/serve/site-ui/docs/firestore-compat.md +3 -3
  245. package/dist/serve/site-ui/docs/firestore-flutter-compat/index.html +319 -0
  246. package/dist/serve/site-ui/docs/firestore-flutter-compat.md +344 -0
  247. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +1 -1
  248. package/dist/serve/site-ui/docs/get-started/backend-bundlers/index.html +105 -0
  249. package/dist/serve/site-ui/docs/get-started/backend-bundlers.md +165 -0
  250. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  251. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +1 -1
  252. package/dist/serve/site-ui/docs/get-started/start-building/index.html +1 -1
  253. package/dist/serve/site-ui/docs/get-started/vite/index.html +1 -1
  254. package/dist/serve/site-ui/docs/index.json +2967 -1482
  255. package/dist/serve/site-ui/docs/messaging-compat/index.html +1 -1
  256. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +1 -1
  257. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
  258. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
  259. package/dist/serve/site-ui/docs/overview/index.html +1 -1
  260. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  261. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  262. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  263. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  264. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
  265. package/dist/serve/site-ui/docs/pyric-admin-reference-api/index.html +1 -1
  266. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  267. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
  268. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  269. package/dist/serve/site-ui/docs/pyric-analytics-reference-api/index.html +124 -0
  270. package/dist/serve/site-ui/docs/pyric-analytics-reference-api.md +287 -0
  271. package/dist/serve/site-ui/docs/pyric-app-check-reference-api/index.html +87 -0
  272. package/dist/serve/site-ui/docs/pyric-app-check-reference-api.md +199 -0
  273. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
  274. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +6 -2
  275. package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +2 -1
  276. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  277. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  278. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +2 -2
  279. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api.md +1 -1
  280. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  281. package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api/index.html +56 -0
  282. package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api.md +72 -0
  283. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +2 -1
  284. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api.md +1 -0
  285. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  286. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +2 -1
  287. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api.md +1 -0
  288. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  289. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  290. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +2 -2
  291. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api.md +1 -1
  292. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +1 -1
  293. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  294. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +34 -9
  295. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api.md +16 -8
  296. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +133 -93
  297. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api.md +61 -1
  298. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +2 -2
  299. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api.md +1 -1
  300. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +2 -2
  301. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api.md +2 -2
  302. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +2 -2
  303. package/dist/serve/site-ui/docs/pyric-database-reference-api.md +1 -1
  304. package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api/index.html +559 -0
  305. package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api.md +1240 -0
  306. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +40 -11
  307. package/dist/serve/site-ui/docs/pyric-firestore-reference-api.md +18 -8
  308. package/dist/serve/site-ui/docs/pyric-functions-reference-api/index.html +67 -0
  309. package/dist/serve/site-ui/docs/pyric-functions-reference-api.md +149 -0
  310. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  311. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  312. package/dist/serve/site-ui/docs/pyric-performance-reference-api/index.html +35 -0
  313. package/dist/serve/site-ui/docs/pyric-performance-reference-api.md +69 -0
  314. package/dist/serve/site-ui/docs/pyric-remote-config-reference-api/index.html +132 -0
  315. package/dist/serve/site-ui/docs/pyric-remote-config-reference-api.md +307 -0
  316. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +1 -1
  317. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +52 -17
  318. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api.md +48 -9
  319. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  320. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +239 -49
  321. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api.md +148 -31
  322. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +22 -4
  323. package/dist/serve/site-ui/docs/pyric-storage-reference-api.md +24 -2
  324. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +26 -96
  325. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api.md +20 -51
  326. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  327. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +2 -2
  328. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api.md +1 -1
  329. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  330. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  331. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  332. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +2 -2
  333. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api.md +1 -1
  334. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +124 -26
  335. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api.md +58 -5
  336. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  337. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  338. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  339. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  340. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +4 -5
  341. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api.md +3 -4
  342. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  343. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  344. package/dist/serve/site-ui/docs/reference/cli/index.html +6 -3
  345. package/dist/serve/site-ui/docs/reference/cli.md +8 -2
  346. package/dist/serve/site-ui/docs/rules-compat/index.html +10 -2
  347. package/dist/serve/site-ui/docs/rules-compat.md +9 -1
  348. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
  349. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  350. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
  351. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  352. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
  353. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  354. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +1 -1
  355. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  356. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
  357. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
  358. package/dist/serve/site-ui/docs/storage-compat/index.html +13 -13
  359. package/dist/serve/site-ui/docs/storage-compat.md +12 -12
  360. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  361. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
  362. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  363. package/dist/serve/site-ui/docs/tutorial/index.html +1 -1
  364. package/dist/serve/site-ui/examples/chess/index.html +1 -1
  365. package/dist/serve/site-ui/firestore/index.html +1 -1
  366. package/dist/serve/site-ui/llms.txt +9 -0
  367. package/dist/serve/site-ui/rtdb/index.html +1 -1
  368. package/dist/serve/site-ui/settings/index.html +1 -1
  369. package/dist/serve/site-ui/storage/index.html +1 -1
  370. package/dist/serve/site-ui/studio/index.html +1 -1
  371. package/dist/serve/site-ui/traffic/index.html +1 -1
  372. package/dist/serve/studio/disk-workspace.d.ts.map +1 -1
  373. package/dist/serve/studio/disk-workspace.js +64 -2
  374. package/dist/serve/studio/disk-workspace.js.map +1 -1
  375. package/dist/serve/vite-plugin.d.ts +7 -7
  376. package/dist/serve/vite-plugin.js +1 -1
  377. package/dist/serve/vite-plugin.js.map +1 -1
  378. package/dist/serve/vite-sandbox-generation.d.ts.map +1 -1
  379. package/dist/serve/vite-sandbox-generation.js +12 -0
  380. package/dist/serve/vite-sandbox-generation.js.map +1 -1
  381. package/dist/serve/worker/client/auth.js +1 -2
  382. package/dist/serve/worker/client/auth.js.map +1 -1
  383. package/dist/serve/worker/client/core.d.ts +21 -1
  384. package/dist/serve/worker/client/core.d.ts.map +1 -1
  385. package/dist/serve/worker/client/core.js +79 -3
  386. package/dist/serve/worker/client/core.js.map +1 -1
  387. package/dist/serve/worker/client.d.ts +1 -1
  388. package/dist/serve/worker/client.d.ts.map +1 -1
  389. package/dist/serve/worker/client.js +1 -1
  390. package/dist/serve/worker/client.js.map +1 -1
  391. package/dist/serve/worker/context-resolver.d.ts +30 -0
  392. package/dist/serve/worker/context-resolver.d.ts.map +1 -0
  393. package/dist/serve/worker/context-resolver.js +44 -0
  394. package/dist/serve/worker/context-resolver.js.map +1 -0
  395. package/dist/serve/worker/entry.js +23 -19
  396. package/dist/serve/worker/entry.js.map +1 -1
  397. package/dist/serve/worker/host/core.d.ts +1 -0
  398. package/dist/serve/worker/host/core.d.ts.map +1 -1
  399. package/dist/serve/worker/host/core.js +12 -6
  400. package/dist/serve/worker/host/core.js.map +1 -1
  401. package/dist/serve/worker/host/storage.js +2 -2
  402. package/dist/serve/worker/host-auth.js +1 -2
  403. package/dist/serve/worker/host-auth.js.map +1 -1
  404. package/dist/serve/worker/index.d.ts +1 -1
  405. package/dist/serve/worker/index.d.ts.map +1 -1
  406. package/dist/serve/worker/index.js +2 -2
  407. package/dist/serve/worker/index.js.map +1 -1
  408. package/dist/serve/worker/port-lifecycle.d.ts +18 -0
  409. package/dist/serve/worker/port-lifecycle.d.ts.map +1 -0
  410. package/dist/serve/worker/port-lifecycle.js +28 -0
  411. package/dist/serve/worker/port-lifecycle.js.map +1 -0
  412. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  413. package/dist/serve/worker/serve-init.js +8 -2
  414. package/dist/serve/worker/serve-init.js.map +1 -1
  415. package/dist/verify/fixture.d.ts +1 -1
  416. package/package.json +16 -5
  417. package/src/assurance/.generated/conformance-verdicts.ts +68 -1
  418. package/src/bridge/client/dispatch.ts +52 -56
  419. package/src/bridge/client/tool-family-factories.ts +34 -0
  420. package/src/bridge/server/mcp-contract.ts +15 -59
  421. package/src/bridge/server/peer.ts +24 -1
  422. package/src/bridge/server/tool-family-factories.ts +40 -0
  423. package/src/bridge/server/tool-metadata.ts +29 -61
  424. package/src/bridge/tool-families.generated.ts +17 -0
  425. package/src/bridge/tool-families.ts +87 -0
  426. package/src/bridge/tool-family-records/conformance.ts +6 -0
  427. package/src/bridge/tool-family-records/firestore-data.ts +15 -0
  428. package/src/bridge/tool-family-records/firestore-inspect.ts +6 -0
  429. package/src/bridge/tool-family-records/firestore-rules.ts +15 -0
  430. package/src/bridge/tool-family-records/firestore-simulator.ts +16 -0
  431. package/src/bridge/tool-family-records/rtdb-inspection.ts +6 -0
  432. package/src/bundler/externals.ts +55 -0
  433. package/src/bundler/index.ts +21 -0
  434. package/src/cli/cli.test.ts +0 -44
  435. package/src/cli/inlined-sdk-scanner.ts +77 -0
  436. package/src/cli/sandbox-interlock.ts +167 -0
  437. package/src/cli/sandbox-runner.ts +37 -26
  438. package/src/cli/serve.ts +68 -69
  439. package/src/cli/unsupported-runtime.ts +68 -0
  440. package/src/conformance/.generated/can-i-use-browser.ts +2 -2
  441. package/src/conformance/.generated/can-i-use.ts +2 -2
  442. package/src/conformance/.generated/conformance-docs.ts +1 -1
  443. package/src/functions-rtdb/child.ts +115 -21
  444. package/src/functions-rtdb/development-runtime.ts +4 -0
  445. package/src/google-endpoints.ts +155 -0
  446. package/src/next/runtime-env.ts +5 -0
  447. package/src/next/with-pyric.ts +1 -1
  448. package/src/register/beacon.ts +232 -0
  449. package/src/register/index.ts +68 -6
  450. package/src/register/net-guard.ts +567 -0
  451. package/src/serve/ai-diagnostics-relay.ts +243 -0
  452. package/src/serve/ai-proxy.ts +327 -0
  453. package/src/serve/ai-status.ts +109 -0
  454. package/src/serve/ai-terminal-blocks.ts +210 -0
  455. package/src/serve/ai-terminal-text.ts +52 -0
  456. package/src/serve/beacon-route.ts +141 -0
  457. package/src/serve/entries/active-auth-registry.ts +56 -0
  458. package/src/serve/entries/active-auth.ts +100 -0
  459. package/src/serve/entries/auth-helper-core.ts +5 -0
  460. package/src/serve/entries/auth-helper-dom.ts +26 -2
  461. package/src/serve/entries/auth.ts +8 -0
  462. package/src/serve/entries/bridge-url.ts +1 -1
  463. package/src/serve/entries/init.ts +78 -3
  464. package/src/serve/entries/runtime.ts +10 -0
  465. package/src/serve/namespace.ts +73 -140
  466. package/src/serve/runtime/chip-config.ts +16 -2
  467. package/src/serve/runtime/chip-dialog.ts +366 -0
  468. package/src/serve/runtime/chip-install.ts +10 -4
  469. package/src/serve/runtime/chip-user-search.ts +391 -0
  470. package/src/serve/runtime/chip.ts +140 -15
  471. package/src/serve/runtime/identity.ts +26 -0
  472. package/src/serve/sandbox-session.ts +9 -0
  473. package/src/serve/studio/disk-workspace.ts +76 -2
  474. package/src/serve/vite-plugin.ts +8 -8
  475. package/src/serve/vite-sandbox-generation.ts +15 -0
  476. package/src/serve/worker/client/auth.ts +1 -1
  477. package/src/serve/worker/client/core.ts +80 -3
  478. package/src/serve/worker/client.ts +1 -1
  479. package/src/serve/worker/context-resolver.ts +60 -0
  480. package/src/serve/worker/entry.ts +22 -18
  481. package/src/serve/worker/host/core.ts +9 -7
  482. package/src/serve/worker/host/storage.ts +2 -2
  483. package/src/serve/worker/host-auth.ts +1 -1
  484. package/src/serve/worker/index.ts +4 -1
  485. package/src/serve/worker/port-lifecycle.ts +45 -0
  486. package/src/serve/worker/serve-init.ts +9 -2
  487. package/src/verify/fixture.ts +1 -1
  488. package/dist/serve/site-ui/_astro/app.B52xr-DK.js +0 -1
  489. package/dist/serve/site-ui/_astro/app.DWBraPUw.js +0 -12
  490. package/dist/serve/site-ui/_astro/sandbox-controls.DEpnKg-O.js +0 -1169
  491. package/dist/serve/site-ui/_astro/writes.rpjrFzmu.js +0 -102
@@ -0,0 +1,26 @@
1
+ import type { AuthUserRecord } from 'pyric/auth';
2
+
3
+ export interface RuntimeIdentity {
4
+ uid: string;
5
+ email?: string | null;
6
+ displayName?: string | null;
7
+ }
8
+
9
+ /** The chip's complete identity integration seam, passed intact through mounting. */
10
+ export interface RuntimeIdentityBindings {
11
+ listUsers(): Promise<AuthUserRecord[]> | AuthUserRecord[];
12
+ switchUser(uid: string): Promise<void> | void;
13
+ signOut(): Promise<void> | void;
14
+ openCreateUser(): void;
15
+ getCurrentUser(): RuntimeIdentity | null;
16
+ subscribeAuth(listener: (user: RuntimeIdentity | null) => void): () => void;
17
+ }
18
+
19
+ export function projectRuntimeIdentity(user: RuntimeIdentity | null | undefined): RuntimeIdentity | null {
20
+ if (!user) return null;
21
+ return {
22
+ uid: user.uid,
23
+ email: user.email,
24
+ displayName: user.displayName,
25
+ };
26
+ }
@@ -14,6 +14,7 @@ import {
14
14
  rulesHashOf,
15
15
  } from './rules.js';
16
16
  import { createEventHub, createPyricNamespace } from './namespace.js';
17
+ import type { BeaconReport } from '../register/beacon.js';
17
18
  import { diskProjectStore, diskWorkspace } from './studio/index.js';
18
19
  import type { ServeLogger } from './server.js';
19
20
  import {
@@ -38,6 +39,12 @@ export interface SandboxSessionOptions {
38
39
  permissive?: boolean;
39
40
  logger?: ServeLogger;
40
41
  activity?: (incident: ActivityIncident) => void;
42
+ /** Receives one handshake beacon per pyric-launched child, the dev
43
+ * server's only positive proof that the register module reached it. */
44
+ beacon?: (report: BeaconReport) => void;
45
+ /** The per-launch secret a beacon must present, also placed in the child's
46
+ * `PYRIC_BEACON_TOKEN`. */
47
+ beaconToken?: string;
41
48
  }
42
49
 
43
50
  export interface SandboxSessionSummary {
@@ -212,6 +219,8 @@ export async function createSandboxSession(
212
219
  workerVersion: options.sdk.workerVersion,
213
220
  aiProxyUpstream: options.aiProxyUpstream,
214
221
  activity: options.activity,
222
+ beacon: options.beacon,
223
+ beaconToken: options.beaconToken,
215
224
  logger: options.logger,
216
225
  });
217
226
 
@@ -17,8 +17,16 @@ import {
17
17
  stat,
18
18
  writeFile,
19
19
  } from 'node:fs/promises';
20
- import { existsSync, mkdirSync, watch as fsWatch, type FSWatcher } from 'node:fs';
21
- import { dirname, join, posix, relative, resolve, sep } from 'node:path';
20
+ import {
21
+ existsSync,
22
+ lstatSync,
23
+ mkdirSync,
24
+ readlinkSync,
25
+ realpathSync,
26
+ watch as fsWatch,
27
+ type FSWatcher,
28
+ } from 'node:fs';
29
+ import { basename, dirname, join, posix, relative, resolve, sep } from 'node:path';
22
30
 
23
31
  import type {
24
32
  WorkspaceChange,
@@ -34,6 +42,54 @@ export class WorkspacePathError extends Error {
34
42
  }
35
43
  }
36
44
 
45
+ /**
46
+ * Resolves the canonical realpath of a path, handling symlinks and non-existent
47
+ * terminal segments by resolving the nearest existing ancestor.
48
+ */
49
+ function getCanonicalPath(targetPath: string, seen = new Set<string>()): string {
50
+ const abs = resolve(targetPath);
51
+ if (seen.has(abs)) {
52
+ throw new WorkspacePathError(targetPath);
53
+ }
54
+ seen.add(abs);
55
+
56
+ try {
57
+ return realpathSync(abs);
58
+ } catch (err: any) {
59
+ if (err?.code === 'ELOOP') {
60
+ throw new WorkspacePathError(targetPath);
61
+ }
62
+ if (err?.code !== 'ENOENT' && err?.code !== 'ENOTDIR') {
63
+ throw err;
64
+ }
65
+ }
66
+
67
+ try {
68
+ const st = lstatSync(abs);
69
+ if (st.isSymbolicLink()) {
70
+ const linkTarget = readlinkSync(abs);
71
+ const nextTarget = resolve(dirname(abs), linkTarget);
72
+ return getCanonicalPath(nextTarget, seen);
73
+ }
74
+ } catch {
75
+ // abs does not exist as a directory entry
76
+ }
77
+
78
+ const parent = dirname(abs);
79
+ if (parent === abs) {
80
+ return abs;
81
+ }
82
+ const canonicalParent = getCanonicalPath(parent, seen);
83
+ return join(canonicalParent, basename(abs));
84
+ }
85
+
86
+ /** Check whether canonical target is contained within canonical root. */
87
+ function isContained(root: string, target: string): boolean {
88
+ if (target === root) return true;
89
+ const prefix = root.endsWith(sep) ? root : root + sep;
90
+ return target.startsWith(prefix);
91
+ }
92
+
37
93
  /**
38
94
  * Resolve a project-relative POSIX path to an absolute OS path inside `root`,
39
95
  * or throw {@link WorkspacePathError} if it would escape. Leading slashes are
@@ -52,6 +108,24 @@ export function resolveWorkspacePath(root: string, rel: string): string {
52
108
  if (abs !== root && !abs.startsWith(root + sep)) {
53
109
  throw new WorkspacePathError(rel);
54
110
  }
111
+
112
+ // Canonical realpath containment check:
113
+ // Reject symlinks that escape the workspace root.
114
+ const canonicalRoot = getCanonicalPath(root);
115
+ let canonicalTarget: string;
116
+ try {
117
+ canonicalTarget = getCanonicalPath(abs);
118
+ } catch (err) {
119
+ if (err instanceof WorkspacePathError) {
120
+ throw new WorkspacePathError(rel);
121
+ }
122
+ throw err;
123
+ }
124
+
125
+ if (!isContained(canonicalRoot, canonicalTarget)) {
126
+ throw new WorkspacePathError(rel);
127
+ }
128
+
55
129
  return abs;
56
130
  }
57
131
 
@@ -1,18 +1,18 @@
1
1
  /**
2
2
  * `@pyric/cli/vite` — the firebase→pyric-sandbox swap as a Vite plugin.
3
3
  *
4
- * The serve analog for SOURCE-driven apps: instead of `vite build && pyric dev
4
+ * The serve analog for SOURCE-driven apps: instead of `vite build && pyric sandbox
5
5
  * dist`, a team keeps `vite dev` (HMR, source maps) with the in-process sandbox
6
6
  * standing in for Firebase. The app's `firebase/*` imports are UNCHANGED — the
7
7
  * plugin swaps them at the module-resolution layer (`resolveId`), the same way
8
- * `pyric dev` swaps via a runtime import map. (Design: `plans/pyric-vite-plugin.md`.)
8
+ * `pyric sandbox` swaps via a runtime import map. (Design: `plans/pyric-vite-plugin.md`.)
9
9
  *
10
10
  * Two flavors, one `apply` function. Under `vite dev` the swap is ALWAYS on.
11
11
  * For `vite build` the swap is MODE-gated: a plain `vite build` (mode
12
12
  * `production`) ships the real `firebase` package — the swap never reaches the
13
13
  * prod artifact — while `vite build --mode development` (any NON-production
14
14
  * mode) produces a SANDBOX build that bundles pyric's in-page adapters instead
15
- * of the real SDK: self-contained, meant to be previewed under `pyric dev`, and
15
+ * of the real SDK: self-contained, meant to be previewed under `pyric sandbox`, and
16
16
  * stamped with the sandbox-build marker so it can never be deployed (`pyric
17
17
  * deploy hosting` refuses it). `pyric({ swapInBuild })` forces the build
18
18
  * behavior on/off regardless of mode. See `sandbox-marker.ts`.
@@ -24,11 +24,11 @@
24
24
  * - the host-neutral sandbox session — rules, fixtures, stores, live payload,
25
25
  * Studio routes, `/__pyric/*` namespace, and owned cleanup;
26
26
  * - the SharedWorker host — `bundleWorker` served at `/__pyric/sdk/worker.js`;
27
- * - the bridge mount shared with `pyric dev --bridge`.
27
+ * - the bridge mount shared with `pyric sandbox --bridge`.
28
28
  *
29
29
  * Scope = M1 (swap + rules) + M2 (SharedWorker multi-tab + persist/capture/seed)
30
30
  * + M3 (the MCP bridge fold — `{ bridge }`). M3 reuses `createBridgeMount` (the
31
- * proven serve-flavored bridge behind `pyric dev --bridge`), composing it into
31
+ * proven serve-flavored bridge behind `pyric sandbox --bridge`), composing it into
32
32
  * the same `/__pyric` middleware; on the worker path the bridge peer routes
33
33
  * agent tool-calls THROUGH the SharedWorker (`connectBridgePeer`), so the agent
34
34
  * and the app share one backend without forcing the page in-page.
@@ -82,7 +82,7 @@ export interface PyricOptions {
82
82
  * only when the worker bundle itself fails, bridge or not. */
83
83
  bridge?: boolean | { project?: string; disableAuditLog?: boolean };
84
84
  /** Serve the **Pyric Studio** app at `/__pyric/ui/` on Vite's dev origin (the
85
- * `pyric dev --ui` equivalent). Mounts the disk-backed workspace/project
85
+ * `pyric sandbox --ui` equivalent). Mounts the disk-backed workspace/project
86
86
  * routes Studio's `local` mode talks to AND serves the unified Astro site
87
87
  * (vendored in this package at `dist/serve/site-ui`). **On by default**,
88
88
  * including under `bridge` (the bridge peer routes through the SharedWorker,
@@ -93,7 +93,7 @@ export interface PyricOptions {
93
93
  * dev/builds. On by default. Pass `false` to hide it, or
94
94
  * `{ initiallyOpen: true }` when actively debugging runtime errors. */
95
95
  runtimeChip?: PyricRuntimeChipOption;
96
- /** RTDB-triggered Cloud Functions under this dev server (the `pyric dev`
96
+ /** RTDB-triggered Cloud Functions under this dev server (the `pyric sandbox`
97
97
  * parity fold). By default a `functions` block in `firebase.json` is
98
98
  * discovered automatically: its `onValueCreated` triggers run in an isolated
99
99
  * node child against the shared sandbox (other trigger kinds warn and are
@@ -216,7 +216,7 @@ export function pyric(options: PyricOptions = {}): Plugin {
216
216
  // `vite build` keeps the real firebase package — the swap never reaches
217
217
  // production output. A sandbox build applies the same swap so the output
218
218
  // bundles pyric's in-page adapters (self-contained; preview it under
219
- // `pyric dev`, never deploy it).
219
+ // `pyric sandbox`, never deploy it).
220
220
  apply(config, env) {
221
221
  void config;
222
222
  return pageRuntime.applies(env);
@@ -7,6 +7,7 @@ import {
7
7
  type FunctionsRtdbProject,
8
8
  } from '../functions-rtdb/project.js';
9
9
  import { formatActivityWarning } from './activity-warning.js';
10
+ import { formatAiStatusNote } from './ai-status.js';
10
11
  import {
11
12
  createBridgeMount,
12
13
  type BridgeHostAttachment,
@@ -217,6 +218,20 @@ export async function createViteSandboxGeneration(
217
218
  server.config.logger.info(' ⓘ [pyric] fresh: discarded the existing state file; re-seeding');
218
219
  }
219
220
 
221
+ // Say what AI resolved to. This is the one front door where the engine and
222
+ // its model binding ARE known at boot (`ai.engine` / `ai.model` reduced to
223
+ // the wire shape above); the broker itself is still built lazily, in the
224
+ // page or the worker, on the first `ai.*` op. Every generation prints it,
225
+ // so a Vite restart on an `.env`/config edit re-announces the new binding
226
+ // through the same formatter instead of swapping engines in silence.
227
+ server.config.logger.info(
228
+ formatAiStatusNote({
229
+ engine: ai.engineWire,
230
+ mode: ai.mode,
231
+ proxyUpstream: ai.proxyUpstream,
232
+ }),
233
+ );
234
+
220
235
  const middlewareInput = { server, bridge, session };
221
236
  const disposeMiddleware = attachViteGenerationMiddleware(middlewareInput);
222
237
  listenerDisposers.push(disposeMiddleware);
@@ -312,7 +312,7 @@ export async function restorePortSession(
312
312
  t: 'op', id: nextId(), method: 'auth.restorePortSession', uid,
313
313
  })) as SerializedUser | null;
314
314
  const user = toClientUser(auth.port, raw);
315
- if (user) auth.currentUser = user;
315
+ auth.currentUser = user;
316
316
  return user;
317
317
  }
318
318
 
@@ -259,26 +259,103 @@ export function wirePort(port: ClientPort): void {
259
259
  // ops (`auth.*`) and `getVersion` are NEVER lensed — they operate the worker's
260
260
  // session, not data — so the lens is stamped only on the data-op path.
261
261
 
262
+ export const AUTH_LENS_STORAGE_KEY = 'pyric:auth-lens';
263
+
264
+ type PersistedAuthLens =
265
+ | Extract<AuthLens, { mode: 'admin' }>
266
+ | Extract<AuthLens, { mode: 'as' }>;
267
+
268
+ export function isPersistedAuthLens(value: unknown): value is PersistedAuthLens {
269
+ if (!value || typeof value !== 'object') return false;
270
+ const candidate = value as { mode?: unknown; uid?: unknown };
271
+ if (candidate.mode === 'admin') return true;
272
+ return candidate.mode === 'as' && typeof candidate.uid === 'string';
273
+ }
274
+
275
+ function normalizePersistedAuthLens(value: unknown): PersistedAuthLens | undefined {
276
+ if (isPersistedAuthLens(value)) return value;
277
+ return undefined;
278
+ }
279
+
280
+ /** Read persisted auth lens from sessionStorage safely. */
281
+ export function hydrateLensFromStorage(): AuthLens | undefined {
282
+ if (typeof sessionStorage === 'undefined') return undefined;
283
+ try {
284
+ const raw = sessionStorage.getItem(AUTH_LENS_STORAGE_KEY);
285
+ if (!raw) return undefined;
286
+ const parsed: unknown = JSON.parse(raw);
287
+ const persistedLens = normalizePersistedAuthLens(parsed);
288
+ if (persistedLens) return persistedLens;
289
+ sessionStorage.removeItem(AUTH_LENS_STORAGE_KEY);
290
+ return undefined;
291
+ } catch {
292
+ try {
293
+ sessionStorage.removeItem(AUTH_LENS_STORAGE_KEY);
294
+ } catch {
295
+ // Ignore storage restrictions
296
+ }
297
+ return undefined;
298
+ }
299
+ }
300
+
262
301
  /** Module-level default lens. `undefined` ⇒ the worker treats the op as the
263
302
  * app's session (the additive default — existing senders omit `actAs`).
264
303
  *
265
304
  * Exported as a LIVE binding: family modules read it to stamp the lens onto
266
305
  * subscriptions (`onSnapshot`, `rtdbOnValue`), and see `setLens(...)` updates
267
306
  * through this one singleton. */
268
- export let _defaultLens: AuthLens | undefined;
307
+ export let _defaultLens: AuthLens | undefined = hydrateLensFromStorage();
308
+
309
+ const lensListeners = new Set<(lens: AuthLens | undefined) => void>();
310
+
311
+ /**
312
+ * Register a listener for auth lens mutations.
313
+ * Returns an unsubscribe function that removes the listener.
314
+ */
315
+ export function subscribeLens(listener: (lens: AuthLens | undefined) => void): () => void {
316
+ lensListeners.add(listener);
317
+ return () => {
318
+ lensListeners.delete(listener);
319
+ };
320
+ }
269
321
 
270
322
  /**
271
323
  * Set the default auth lens applied to subsequent Firestore DATA ops from this
272
- * client (Pyric Studio). Pass `{ mode: 'as', uid }` to read/write AS a user
324
+ * client (Pyric Studio & Runtime Chip). Pass `{ mode: 'as', uid }` to read/write AS a user
273
325
  * (rules apply), `{ mode: 'admin' }` for the admin lens, or
274
326
  * `{ mode: 'app-session' }` / `undefined` to revert to the app's own session.
275
327
  *
276
328
  * The lens is process-wide for this client module (one served page = one
277
329
  * worker port), mirroring how Studio drives a single active identity at a time.
278
330
  * Auth ops are unaffected — they always operate the real session.
331
+ *
332
+ * Persists active admin and impersonation lenses to sessionStorage under
333
+ * AUTH_LENS_STORAGE_KEY, and removes the key when cleared or reverted to the
334
+ * app session.
335
+ * Notifies all registered subscribeLens listeners.
279
336
  */
280
337
  export function setLens(lens: AuthLens | undefined): void {
281
- _defaultLens = lens && lens.mode === 'app-session' ? undefined : lens;
338
+ _defaultLens = normalizePersistedAuthLens(lens);
339
+
340
+ if (typeof sessionStorage !== 'undefined') {
341
+ try {
342
+ if (_defaultLens) {
343
+ sessionStorage.setItem(AUTH_LENS_STORAGE_KEY, JSON.stringify(_defaultLens));
344
+ } else {
345
+ sessionStorage.removeItem(AUTH_LENS_STORAGE_KEY);
346
+ }
347
+ } catch {
348
+ // Ignore quota or disabled storage restrictions
349
+ }
350
+ }
351
+
352
+ for (const listener of [...lensListeners]) {
353
+ try {
354
+ listener(_defaultLens);
355
+ } catch (err) {
356
+ console.error('Error in subscribeLens listener:', err);
357
+ }
358
+ }
282
359
  }
283
360
 
284
361
  /** The active default lens (read-only view), for Studio UI to reflect state. */
@@ -26,7 +26,7 @@
26
26
  */
27
27
 
28
28
  // Shared core: lens/issuer controls + the handle and snapshot types.
29
- export { setLens, getLens, setOpIssuer } from './client/core.js';
29
+ export { setLens, getLens, subscribeLens, AUTH_LENS_STORAGE_KEY, hydrateLensFromStorage, setOpIssuer } from './client/core.js';
30
30
  export type {
31
31
  ClientDb,
32
32
  ClientRtdb,
@@ -0,0 +1,60 @@
1
+ /**
2
+ * SharedWorker context resolver.
3
+ *
4
+ * Coordinates asynchronous initialization of a singleton resource across
5
+ * concurrent inbound connection requests or burst messages.
6
+ *
7
+ * Invariants:
8
+ * 1. Single In-Flight Attempt: When multiple callers request the context
9
+ * concurrently while initialization is in flight, all callers share the
10
+ * single in-flight promise rather than starting parallel initializations.
11
+ * 2. Unpoisoned on Rejection: If initialization rejects, the memoized promise
12
+ * is cleared immediately, allowing subsequent requests to retry initialization
13
+ * rather than permanently caching the rejection.
14
+ * 3. Synchronous Retrieval: Once successfully resolved, the resource is
15
+ * available synchronously for shutdown and cleanup handlers.
16
+ */
17
+
18
+ export interface ContextResolver<T> {
19
+ /**
20
+ * Return the resolved resource or the in-flight initialization promise.
21
+ * If a previous attempt rejected, starts a new attempt.
22
+ */
23
+ get(): Promise<T>;
24
+
25
+ /**
26
+ * Return the successfully resolved resource, or null if not yet resolved
27
+ * or currently in-flight.
28
+ */
29
+ current(): T | null;
30
+ }
31
+
32
+ export function createContextResolver<T>(factory: () => Promise<T>): ContextResolver<T> {
33
+ let value: T | null = null;
34
+ let inFlight: Promise<T> | null = null;
35
+
36
+ return {
37
+ async get(): Promise<T> {
38
+ if (value !== null) {
39
+ return value;
40
+ }
41
+ if (inFlight === null) {
42
+ inFlight = factory()
43
+ .then((resolved) => {
44
+ value = resolved;
45
+ return resolved;
46
+ })
47
+ .catch((error: unknown) => {
48
+ inFlight = null;
49
+ value = null;
50
+ throw error;
51
+ });
52
+ }
53
+ return inFlight;
54
+ },
55
+
56
+ current(): T | null {
57
+ return value;
58
+ },
59
+ };
60
+ }
@@ -67,36 +67,33 @@ import {
67
67
  } from './service-worker-channel.js';
68
68
  import { createServiceWorkerRelay } from './service-worker-relay.js';
69
69
  import { createWorkerRetirement } from './retirement.js';
70
+ import { createContextResolver } from './context-resolver.js';
71
+ import { createPortLifecycleManager } from './port-lifecycle.js';
70
72
 
71
73
  declare const __PYRIC_WORKER_VERSION__: string;
72
74
  const workerEpoch = typeof __PYRIC_WORKER_VERSION__ !== 'undefined'
73
75
  ? __PYRIC_WORKER_VERSION__
74
76
  : 'dev';
75
77
  const workerScope = self as unknown as SharedWorkerGlobalScope;
78
+ const contextResolver = createContextResolver(buildCtx);
79
+ const portLifecycle = createPortLifecycleManager();
76
80
  const retirement = createWorkerRetirement({
77
81
  closeWorker: () => workerScope.close(),
78
- beforeAnnounce: async () => { await _ctx?.captureFlush?.(); },
82
+ beforeAnnounce: async () => { await contextResolver.current()?.captureFlush?.(); },
79
83
  });
80
84
 
81
85
  // ─── Singleton context ────────────────────────────────────────────────────
82
86
 
83
- // `_ctx` is the RESOLVED context, kept for the synchronous `close` handler.
84
- // The build is memoized as a PROMISE (`_ctxPromise`) — NOT as the resolved
85
- // value — because init is async (it awaits `/__pyric/init.json` + persistence
86
- // restore). The first messages arrive in a BURST (the authState sub, the first
87
- // firestore sub, an op — possibly across two tabs at once); if each re-checked
88
- // only the resolved `_ctx` they would every one start a fresh init and build a
89
- // SEPARATE sandbox, so a listener and a write could bind to different
90
- // instances and never see each other. The promise memo guarantees ONE init.
91
- let _ctx: HostCtx | null = null;
92
- let _ctxPromise: Promise<HostCtx> | null = null;
93
-
94
87
  /**
95
88
  * Return the shared context, memoizing the in-flight init promise so
96
- * concurrent first messages await ONE build (see `_ctxPromise` above).
89
+ * concurrent first messages await ONE build. If initialization rejects,
90
+ * the rejection is cleared so subsequent connection attempts can retry.
91
+ * Any ports that closed while initialization was in flight are drained immediately.
97
92
  */
98
- function getCtx(): Promise<HostCtx> {
99
- return (_ctxPromise ??= buildCtx());
93
+ async function getCtx(): Promise<HostCtx> {
94
+ const ctx = await contextResolver.get();
95
+ portLifecycle.drainClosedPorts(ctx);
96
+ return ctx;
100
97
  }
101
98
 
102
99
  /**
@@ -125,7 +122,6 @@ async function buildCtx(): Promise<HostCtx> {
125
122
  ? (url) => new EventSource(url) as unknown as EventSourceLike
126
123
  : null,
127
124
  });
128
- _ctx = ctx; // publish the resolved ctx for the synchronous close handler
129
125
  return ctx;
130
126
  }
131
127
 
@@ -141,6 +137,7 @@ workerScope.onconnect = (e: MessageEvent) => {
141
137
  const port = e.ports[0];
142
138
  port.start();
143
139
  retirement.connect(port);
140
+ void getCtx().catch(() => undefined);
144
141
 
145
142
  let messageQueue = Promise.resolve();
146
143
  port.onmessage = (ev: MessageEvent<InboundMessage>) => {
@@ -172,9 +169,16 @@ workerScope.onconnect = (e: MessageEvent) => {
172
169
  // cannot overtake an already-posted mutation, and later frames see the
173
170
  // disconnected-port tombstone instead of touching the shared backend.
174
171
  messageQueue = messageQueue.then(async () => {
172
+ const portLike = port as unknown as PortLike;
173
+ if (portLifecycle.isPortClosed(portLike)) {
174
+ return;
175
+ }
175
176
  try {
176
177
  const ctx = await getCtx();
177
- await handleMessage(ctx, port as unknown as PortLike, ev.data);
178
+ if (portLifecycle.isPortClosed(portLike)) {
179
+ return;
180
+ }
181
+ await handleMessage(ctx, portLike, ev.data);
178
182
  } catch (e) {
179
183
  // eslint-disable-next-line no-console
180
184
  console.error('[pyric worker] message handler error:', (e as Error)?.stack ?? e, 'msg:', ev.data);
@@ -188,7 +192,7 @@ workerScope.onconnect = (e: MessageEvent) => {
188
192
  // best-effort; subscriptions also GC when the worker itself dies.
189
193
  port.addEventListener('close', () => {
190
194
  retirement.disconnect(port);
191
- if (_ctx) void cleanupPortWithDisconnect(_ctx, port as unknown as PortLike).catch(() => undefined);
195
+ portLifecycle.onPortClosed(port as unknown as PortLike, contextResolver.current());
192
196
  });
193
197
  };
194
198
 
@@ -220,16 +220,18 @@ export function lensDb(ctx: HostCtx, actAs?: AuthLens): Firestore {
220
220
  return handle;
221
221
  }
222
222
 
223
- export function authStateForLens(actAs: Extract<AuthLens, { mode: 'as' }>): { uid: string; token?: Record<string, unknown> } {
224
- return actAs.token === undefined
225
- ? { uid: actAs.uid }
226
- : { uid: actAs.uid, token: actAs.token };
223
+ export function authStateForLens(actAs: Extract<AuthLens, { mode: 'as' }>): { uid: string; token?: Record<string, unknown>; tenant?: string } {
224
+ const state: { uid: string; token?: Record<string, unknown>; tenant?: string } = { uid: actAs.uid };
225
+ if (actAs.token !== undefined) state.token = actAs.token;
226
+ if (actAs.tenant !== undefined) state.tenant = actAs.tenant;
227
+ return state;
227
228
  }
228
229
 
229
230
  export function lensCacheKey(actAs: Extract<AuthLens, { mode: 'as' }>): string {
230
- return actAs.token === undefined
231
- ? actAs.uid
232
- : `${actAs.uid}:${JSON.stringify(actAs.token)}`;
231
+ const parts = [actAs.uid];
232
+ if (actAs.tenant !== undefined) parts.push(`tenant:${actAs.tenant}`);
233
+ if (actAs.token !== undefined) parts.push(JSON.stringify(actAs.token));
234
+ return parts.join(':');
233
235
  }
234
236
 
235
237
  /** Cache key for a real port session; claims are part of authorization identity. */
@@ -68,8 +68,8 @@ function ensureStorage(ctx: HostCtx): FirebaseStorage {
68
68
  * `applyServeInit` (`serve-init.ts`), which opens the storage service
69
69
  * with `payload.storageRules` BEFORE any op can reach `ensureStorage`/
70
70
  * `lensStorage`, so every lens on a served worker enforces the
71
- * project's storage.rules (or runs open when the project has none,
72
- * matching Firestore/RTDB's no-rules posture). The lens split still
71
+ * project's storage.rules (or fails closed when the project has none,
72
+ * matching Firebase production's no-rules posture). The lens split still
73
73
  * matters for embedding/test hosts that open the service directly.
74
74
  * - `{ mode: 'admin' }` → the rules-BYPASS handle from
75
75
  * `pyric/storage/internal`'s admin plane — same per-sandbox store +
@@ -213,7 +213,7 @@ export async function handleAuthOp(ctx: HostCtx, port: PortLike, msg: OpMessage)
213
213
  } catch {
214
214
  session = null;
215
215
  }
216
- if (session) setPortSession(ctx, port, session);
216
+ setPortSession(ctx, port, session);
217
217
  ok(port, msg.id, session ? serializeUser(session.user) : null);
218
218
  } catch (e) { fail(port, msg.id, e); }
219
219
  break;
@@ -155,9 +155,12 @@ export {
155
155
  inMemoryPersistence,
156
156
  browserSessionPersistence,
157
157
  browserLocalPersistence,
158
- // Auth lens (Pyric Studio — admin / impersonation / app-session)
158
+ // Auth lens (Pyric Studio & Runtime Chip — admin / impersonation / app-session)
159
159
  setLens,
160
160
  getLens,
161
+ subscribeLens,
162
+ AUTH_LENS_STORAGE_KEY,
163
+ hydrateLensFromStorage,
161
164
  // Storage (Pyric Studio data browse): worker-backed FirebaseStorage mirror
162
165
  getStorage,
163
166
  ref,
@@ -0,0 +1,45 @@
1
+ import { cleanupPortWithDisconnect, type HostCtx, type PortLike } from './host.js';
2
+
3
+ /**
4
+ * SharedWorker port lifecycle manager.
5
+ *
6
+ * Tracks ports that close before asynchronous worker context initialization
7
+ * finishes, preventing dead-port leaks and ensuring that port cleanup / disconnect
8
+ * operations are drained as soon as the context becomes available.
9
+ */
10
+ export interface PortLifecycleManager {
11
+ /** Record port closure. Cleans up immediately if context is ready, or defers until resolution. */
12
+ onPortClosed(port: PortLike, currentCtx: HostCtx | null): void;
13
+ /** Drain all deferred closed ports against the newly resolved context. */
14
+ drainClosedPorts(ctx: HostCtx): void;
15
+ /** Check whether a port has already closed before processing queued messages. */
16
+ isPortClosed(port: PortLike): boolean;
17
+ }
18
+
19
+ export function createPortLifecycleManager(): PortLifecycleManager {
20
+ const closedPorts = new WeakSet<PortLike>();
21
+ const pendingClosedPorts = new Set<PortLike>();
22
+
23
+ return {
24
+ onPortClosed(port: PortLike, currentCtx: HostCtx | null): void {
25
+ closedPorts.add(port);
26
+ if (currentCtx !== null) {
27
+ void cleanupPortWithDisconnect(currentCtx, port).catch(() => undefined);
28
+ } else {
29
+ pendingClosedPorts.add(port);
30
+ }
31
+ },
32
+
33
+ drainClosedPorts(ctx: HostCtx): void {
34
+ if (pendingClosedPorts.size === 0) return;
35
+ for (const port of pendingClosedPorts) {
36
+ void cleanupPortWithDisconnect(ctx, port).catch(() => undefined);
37
+ }
38
+ pendingClosedPorts.clear();
39
+ },
40
+
41
+ isPortClosed(port: PortLike): boolean {
42
+ return closedPorts.has(port);
43
+ },
44
+ };
45
+ }
@@ -39,6 +39,7 @@ import {
39
39
  } from 'pyric/sandbox/internal';
40
40
  import type { InitPayload } from '../namespace.js';
41
41
  import { setupFirebaseActivityGuard } from './activity-bootstrap.js';
42
+ import { setupAiDiagnosticsRelay } from '../ai-diagnostics-relay.js';
42
43
  import { createWorkerDurableBackend, setupServerAuthFlush } from './durable-persistence.js';
43
44
  import { ensureAuth, getOrCreateInstanceId, type HostCtx } from './host.js';
44
45
  import { buildVerifyFixture, type PyricVerifyFixture } from '../../verify/fixture.js';
@@ -245,8 +246,7 @@ export function applyServeInit(
245
246
  // always open storage with no `rules` option, so whichever call opens
246
247
  // the service first wins — making this the sanctioned place to
247
248
  // configure it. `payload.storageRules` is null when the project has no
248
- // storage.rules, matching the same open-by-default posture as no
249
- // firestore.rules / no database.rules.
249
+ // storage.rules, so the storage sandbox retains its fail-closed default.
250
250
  // The open ALSO claims the project-scoped IDB name
251
251
  // (`pyric-storage:<projectKey>`, issue #359) — which is why it now runs
252
252
  // unconditionally: a lazy first open from `ensureStorage`/`lensStorage`
@@ -604,6 +604,13 @@ export async function buildWorkerCtx(bootEnv: WorkerBootEnv): Promise<HostCtx> {
604
604
  // populate a report without replaying an old warning into a fresh terminal.
605
605
  setupFirebaseActivityGuard(ctx, env, payload?.activityToken);
606
606
 
607
+ // Same seam, AI's diagnostics: relay every broker `request_rejected`,
608
+ // `response_blocked`, and `model_substituted` event to the dev server's
609
+ // denial relay so a headless developer sees why the broker said no, why an
610
+ // answer came back empty, or which model actually answered. Live events
611
+ // only, so it is safe on either side of hydration.
612
+ setupAiDiagnosticsRelay({ subscribe: (listener) => ctx.sandbox.onEvent(listener) }, env.fetch);
613
+
607
614
  // Apply rules / seed / authUsers / capture BEFORE any port op runs (so
608
615
  // seeded users exist and project rules govern the first write), then mirror
609
616
  // auth to the committable server file (`--persist` only).