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

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 (502) hide show
  1. package/README.md +64 -89
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +238 -1
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +238 -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.CMmTxyhL.js +1 -0
  212. package/dist/serve/site-ui/_astro/app.DhALsVii.js +115 -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.lywYbXZ0.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 +2 -2
  232. package/dist/serve/site-ui/docs/build/authentication.md +1 -1
  233. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +4 -2
  234. package/dist/serve/site-ui/docs/build/cloud-firestore.md +4 -0
  235. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
  236. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +1 -1
  237. package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
  238. package/dist/serve/site-ui/docs/conformance-scores/index.html +14 -2
  239. package/dist/serve/site-ui/docs/conformance-scores.md +13 -1
  240. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +1 -1
  241. package/dist/serve/site-ui/docs/database-compat/index.html +44 -44
  242. package/dist/serve/site-ui/docs/database-compat.md +43 -43
  243. package/dist/serve/site-ui/docs/examples/chess/index.html +1 -1
  244. package/dist/serve/site-ui/docs/examples/index.html +1 -1
  245. package/dist/serve/site-ui/docs/firestore-compat/index.html +4 -4
  246. package/dist/serve/site-ui/docs/firestore-compat.md +3 -3
  247. package/dist/serve/site-ui/docs/firestore-flutter-compat/index.html +319 -0
  248. package/dist/serve/site-ui/docs/firestore-flutter-compat.md +344 -0
  249. package/dist/serve/site-ui/docs/firestore-kotlin-compat/index.html +319 -0
  250. package/dist/serve/site-ui/docs/firestore-kotlin-compat.md +344 -0
  251. package/dist/serve/site-ui/docs/firestore-swift-compat/index.html +490 -0
  252. package/dist/serve/site-ui/docs/firestore-swift-compat.md +517 -0
  253. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +1 -1
  254. package/dist/serve/site-ui/docs/get-started/backend-bundlers/index.html +105 -0
  255. package/dist/serve/site-ui/docs/get-started/backend-bundlers.md +165 -0
  256. package/dist/serve/site-ui/docs/get-started/flutter/index.html +98 -0
  257. package/dist/serve/site-ui/docs/get-started/flutter.md +105 -0
  258. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  259. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +1 -1
  260. package/dist/serve/site-ui/docs/get-started/start-building/index.html +1 -1
  261. package/dist/serve/site-ui/docs/get-started/vite/index.html +1 -1
  262. package/dist/serve/site-ui/docs/index.json +3211 -1471
  263. package/dist/serve/site-ui/docs/messaging-compat/index.html +1 -1
  264. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +4 -3
  265. package/dist/serve/site-ui/docs/observe/resolve-runtime-status.md +3 -1
  266. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
  267. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
  268. package/dist/serve/site-ui/docs/observe/switch-and-impersonate-identities/index.html +110 -0
  269. package/dist/serve/site-ui/docs/observe/switch-and-impersonate-identities.md +134 -0
  270. package/dist/serve/site-ui/docs/overview/index.html +1 -1
  271. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  272. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  273. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  274. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  275. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
  276. package/dist/serve/site-ui/docs/pyric-admin-reference-api/index.html +1 -1
  277. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  278. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
  279. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  280. package/dist/serve/site-ui/docs/pyric-analytics-reference-api/index.html +124 -0
  281. package/dist/serve/site-ui/docs/pyric-analytics-reference-api.md +287 -0
  282. package/dist/serve/site-ui/docs/pyric-app-check-reference-api/index.html +87 -0
  283. package/dist/serve/site-ui/docs/pyric-app-check-reference-api.md +199 -0
  284. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
  285. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +6 -2
  286. package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +2 -1
  287. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  288. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  289. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +2 -2
  290. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api.md +1 -1
  291. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  292. package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api/index.html +56 -0
  293. package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api.md +72 -0
  294. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +4 -1
  295. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api.md +3 -0
  296. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  297. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +4 -1
  298. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api.md +3 -0
  299. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  300. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  301. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +2 -2
  302. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api.md +1 -1
  303. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +1 -1
  304. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  305. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +34 -9
  306. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api.md +16 -8
  307. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +133 -93
  308. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api.md +61 -1
  309. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +2 -2
  310. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api.md +1 -1
  311. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +2 -2
  312. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api.md +2 -2
  313. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +2 -2
  314. package/dist/serve/site-ui/docs/pyric-database-reference-api.md +1 -1
  315. package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api/index.html +559 -0
  316. package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api.md +1240 -0
  317. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +40 -11
  318. package/dist/serve/site-ui/docs/pyric-firestore-reference-api.md +18 -8
  319. package/dist/serve/site-ui/docs/pyric-functions-reference-api/index.html +67 -0
  320. package/dist/serve/site-ui/docs/pyric-functions-reference-api.md +149 -0
  321. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  322. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  323. package/dist/serve/site-ui/docs/pyric-performance-reference-api/index.html +35 -0
  324. package/dist/serve/site-ui/docs/pyric-performance-reference-api.md +69 -0
  325. package/dist/serve/site-ui/docs/pyric-remote-config-reference-api/index.html +132 -0
  326. package/dist/serve/site-ui/docs/pyric-remote-config-reference-api.md +307 -0
  327. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +1 -1
  328. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +52 -17
  329. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api.md +48 -9
  330. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  331. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +239 -49
  332. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api.md +148 -31
  333. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +22 -4
  334. package/dist/serve/site-ui/docs/pyric-storage-reference-api.md +25 -3
  335. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +26 -96
  336. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api.md +20 -51
  337. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  338. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +2 -2
  339. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api.md +1 -1
  340. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  341. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  342. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  343. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +2 -2
  344. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api.md +1 -1
  345. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +124 -26
  346. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api.md +58 -5
  347. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  348. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  349. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  350. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  351. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +4 -5
  352. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api.md +3 -4
  353. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  354. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  355. package/dist/serve/site-ui/docs/reference/cli/index.html +6 -3
  356. package/dist/serve/site-ui/docs/reference/cli.md +8 -2
  357. package/dist/serve/site-ui/docs/rules-compat/index.html +10 -2
  358. package/dist/serve/site-ui/docs/rules-compat.md +9 -1
  359. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
  360. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  361. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
  362. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  363. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
  364. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  365. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +1 -1
  366. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  367. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
  368. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
  369. package/dist/serve/site-ui/docs/storage-compat/index.html +13 -13
  370. package/dist/serve/site-ui/docs/storage-compat.md +12 -12
  371. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  372. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
  373. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  374. package/dist/serve/site-ui/docs/tutorial/index.html +1 -1
  375. package/dist/serve/site-ui/examples/chess/index.html +1 -1
  376. package/dist/serve/site-ui/firestore/index.html +1 -1
  377. package/dist/serve/site-ui/llms.txt +13 -0
  378. package/dist/serve/site-ui/rtdb/index.html +1 -1
  379. package/dist/serve/site-ui/settings/index.html +1 -1
  380. package/dist/serve/site-ui/storage/index.html +1 -1
  381. package/dist/serve/site-ui/studio/index.html +1 -1
  382. package/dist/serve/site-ui/traffic/index.html +1 -1
  383. package/dist/serve/studio/disk-workspace.d.ts.map +1 -1
  384. package/dist/serve/studio/disk-workspace.js +64 -2
  385. package/dist/serve/studio/disk-workspace.js.map +1 -1
  386. package/dist/serve/vite-plugin.d.ts +7 -7
  387. package/dist/serve/vite-plugin.js +1 -1
  388. package/dist/serve/vite-plugin.js.map +1 -1
  389. package/dist/serve/vite-sandbox-generation.d.ts.map +1 -1
  390. package/dist/serve/vite-sandbox-generation.js +12 -0
  391. package/dist/serve/vite-sandbox-generation.js.map +1 -1
  392. package/dist/serve/worker/client/auth.js +1 -2
  393. package/dist/serve/worker/client/auth.js.map +1 -1
  394. package/dist/serve/worker/client/core.d.ts +21 -1
  395. package/dist/serve/worker/client/core.d.ts.map +1 -1
  396. package/dist/serve/worker/client/core.js +79 -3
  397. package/dist/serve/worker/client/core.js.map +1 -1
  398. package/dist/serve/worker/client.d.ts +1 -1
  399. package/dist/serve/worker/client.d.ts.map +1 -1
  400. package/dist/serve/worker/client.js +1 -1
  401. package/dist/serve/worker/client.js.map +1 -1
  402. package/dist/serve/worker/context-resolver.d.ts +30 -0
  403. package/dist/serve/worker/context-resolver.d.ts.map +1 -0
  404. package/dist/serve/worker/context-resolver.js +44 -0
  405. package/dist/serve/worker/context-resolver.js.map +1 -0
  406. package/dist/serve/worker/entry.js +23 -19
  407. package/dist/serve/worker/entry.js.map +1 -1
  408. package/dist/serve/worker/host/core.d.ts +1 -0
  409. package/dist/serve/worker/host/core.d.ts.map +1 -1
  410. package/dist/serve/worker/host/core.js +12 -6
  411. package/dist/serve/worker/host/core.js.map +1 -1
  412. package/dist/serve/worker/host/storage.js +2 -2
  413. package/dist/serve/worker/host-auth.js +1 -2
  414. package/dist/serve/worker/host-auth.js.map +1 -1
  415. package/dist/serve/worker/index.d.ts +1 -1
  416. package/dist/serve/worker/index.d.ts.map +1 -1
  417. package/dist/serve/worker/index.js +2 -2
  418. package/dist/serve/worker/index.js.map +1 -1
  419. package/dist/serve/worker/port-lifecycle.d.ts +18 -0
  420. package/dist/serve/worker/port-lifecycle.d.ts.map +1 -0
  421. package/dist/serve/worker/port-lifecycle.js +28 -0
  422. package/dist/serve/worker/port-lifecycle.js.map +1 -0
  423. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  424. package/dist/serve/worker/serve-init.js +8 -2
  425. package/dist/serve/worker/serve-init.js.map +1 -1
  426. package/dist/verify/fixture.d.ts +1 -1
  427. package/package.json +16 -5
  428. package/src/assurance/.generated/conformance-verdicts.ts +238 -1
  429. package/src/bridge/client/dispatch.ts +52 -56
  430. package/src/bridge/client/tool-family-factories.ts +34 -0
  431. package/src/bridge/server/mcp-contract.ts +15 -59
  432. package/src/bridge/server/peer.ts +24 -1
  433. package/src/bridge/server/tool-family-factories.ts +40 -0
  434. package/src/bridge/server/tool-metadata.ts +29 -61
  435. package/src/bridge/tool-families.generated.ts +17 -0
  436. package/src/bridge/tool-families.ts +87 -0
  437. package/src/bridge/tool-family-records/conformance.ts +6 -0
  438. package/src/bridge/tool-family-records/firestore-data.ts +15 -0
  439. package/src/bridge/tool-family-records/firestore-inspect.ts +6 -0
  440. package/src/bridge/tool-family-records/firestore-rules.ts +15 -0
  441. package/src/bridge/tool-family-records/firestore-simulator.ts +16 -0
  442. package/src/bridge/tool-family-records/rtdb-inspection.ts +6 -0
  443. package/src/bundler/externals.ts +55 -0
  444. package/src/bundler/index.ts +21 -0
  445. package/src/cli/cli.test.ts +0 -44
  446. package/src/cli/inlined-sdk-scanner.ts +77 -0
  447. package/src/cli/sandbox-interlock.ts +167 -0
  448. package/src/cli/sandbox-runner.ts +37 -26
  449. package/src/cli/serve.ts +68 -69
  450. package/src/cli/unsupported-runtime.ts +68 -0
  451. package/src/conformance/.generated/can-i-use-browser.ts +2 -2
  452. package/src/conformance/.generated/can-i-use.ts +2 -2
  453. package/src/conformance/.generated/conformance-docs.ts +1 -1
  454. package/src/functions-rtdb/child.ts +115 -21
  455. package/src/functions-rtdb/development-runtime.ts +4 -0
  456. package/src/google-endpoints.ts +155 -0
  457. package/src/next/runtime-env.ts +5 -0
  458. package/src/next/with-pyric.ts +1 -1
  459. package/src/register/beacon.ts +232 -0
  460. package/src/register/index.ts +68 -6
  461. package/src/register/net-guard.ts +567 -0
  462. package/src/serve/ai-diagnostics-relay.ts +243 -0
  463. package/src/serve/ai-proxy.ts +327 -0
  464. package/src/serve/ai-status.ts +109 -0
  465. package/src/serve/ai-terminal-blocks.ts +210 -0
  466. package/src/serve/ai-terminal-text.ts +52 -0
  467. package/src/serve/beacon-route.ts +141 -0
  468. package/src/serve/entries/active-auth-registry.ts +56 -0
  469. package/src/serve/entries/active-auth.ts +100 -0
  470. package/src/serve/entries/auth-helper-core.ts +5 -0
  471. package/src/serve/entries/auth-helper-dom.ts +26 -2
  472. package/src/serve/entries/auth.ts +8 -0
  473. package/src/serve/entries/bridge-url.ts +1 -1
  474. package/src/serve/entries/init.ts +78 -3
  475. package/src/serve/entries/runtime.ts +10 -0
  476. package/src/serve/namespace.ts +73 -140
  477. package/src/serve/runtime/chip-config.ts +16 -2
  478. package/src/serve/runtime/chip-dialog.ts +366 -0
  479. package/src/serve/runtime/chip-install.ts +10 -4
  480. package/src/serve/runtime/chip-user-search.ts +391 -0
  481. package/src/serve/runtime/chip.ts +140 -15
  482. package/src/serve/runtime/identity.ts +26 -0
  483. package/src/serve/sandbox-session.ts +9 -0
  484. package/src/serve/studio/disk-workspace.ts +76 -2
  485. package/src/serve/vite-plugin.ts +8 -8
  486. package/src/serve/vite-sandbox-generation.ts +15 -0
  487. package/src/serve/worker/client/auth.ts +1 -1
  488. package/src/serve/worker/client/core.ts +80 -3
  489. package/src/serve/worker/client.ts +1 -1
  490. package/src/serve/worker/context-resolver.ts +60 -0
  491. package/src/serve/worker/entry.ts +22 -18
  492. package/src/serve/worker/host/core.ts +9 -7
  493. package/src/serve/worker/host/storage.ts +2 -2
  494. package/src/serve/worker/host-auth.ts +1 -1
  495. package/src/serve/worker/index.ts +4 -1
  496. package/src/serve/worker/port-lifecycle.ts +45 -0
  497. package/src/serve/worker/serve-init.ts +9 -2
  498. package/src/verify/fixture.ts +1 -1
  499. package/dist/serve/site-ui/_astro/app.B52xr-DK.js +0 -1
  500. package/dist/serve/site-ui/_astro/app.DWBraPUw.js +0 -12
  501. package/dist/serve/site-ui/_astro/sandbox-controls.DEpnKg-O.js +0 -1169
  502. package/dist/serve/site-ui/_astro/writes.rpjrFzmu.js +0 -102
@@ -0,0 +1,462 @@
1
+ /**
2
+ * The runtime network guard: the enforcement half of the production-leak
3
+ * invariant.
4
+ *
5
+ * A sandboxed app's Firebase traffic all routes to the local `/__pyric/*`
6
+ * namespace. So a pyric-launched process that opens a connection to a real
7
+ * Google/Firebase endpoint has escaped the sandbox: it is reading or writing
8
+ * live production data with the developer believing otherwise. This module
9
+ * detects that egress and, depending on one knob, warns about it or fails it.
10
+ *
11
+ * Where it hooks, and why exactly there
12
+ * -------------------------------------
13
+ * 1. `Symbol.for('undici.globalDispatcher.1')`, the undici global dispatcher.
14
+ * Measured against Next 15.5 / Node 24 / undici 7, this one seam covers
15
+ * Node route handlers, edge route handlers and middleware, under both the
16
+ * webpack and turbopack dev servers. Patching `globalThis.fetch` does not:
17
+ * the edge sandbox bundles its own undici, and that copy's
18
+ * `getGlobalDispatcher()` reads the host realm's symbol, which is precisely
19
+ * why hooking the dispatcher reaches it and hooking `fetch` does not.
20
+ *
21
+ * Three mechanics the seam depends on:
22
+ * - undici installs the property `configurable: false, writable: true`, so
23
+ * we install by plain assignment. A `defineProperty` with
24
+ * `configurable: true` throws a TypeError and takes the dev server down
25
+ * with it. Accessor traps are useless anyway, because
26
+ * `setGlobalDispatcher` uses `defineProperty`, which bypasses setters.
27
+ * - The property does not exist until undici is first touched, and undici
28
+ * only installs a default agent when it finds the slot empty. So we
29
+ * materialize it first with `new Headers()` (loads undici, zero
30
+ * network) and wrap whatever real Agent that produces.
31
+ * - The `handler` argument of `dispatch(opts, handler)` must pass through
32
+ * opaque and by identity. Edge hands a v6-shaped handler to the host's
33
+ * v7 Agent and that cross-version handoff only survives untouched. We
34
+ * read `opts.origin` and nothing else.
35
+ *
36
+ * 2. `net.connect` / `net.createConnection` / `tls.connect`, plus the
37
+ * `createConnection` on the `http.Agent` and `https.Agent` prototypes: the
38
+ * backstop for traffic that never goes through undici, such as
39
+ * `http.request`, gRPC, database drivers, anything holding a raw socket.
40
+ * Same catalog, same policy. (undici itself connects through `net.connect`,
41
+ * so a warn-mode fetch would report twice; the once-per-host dedupe below
42
+ * collapses that.)
43
+ *
44
+ * The Agent prototypes need their own patch because
45
+ * `http.Agent.prototype.createConnection` is a copied reference to
46
+ * `net.createConnection`, taken when `_http_agent` first loaded. If anything
47
+ * loaded `node:http` before this module ran, that copy is the unpatched
48
+ * function and every plain `http.request` would sail past the backstop,
49
+ * including a request to the metadata server. It is also why the socket
50
+ * patches are installed BEFORE the dispatcher is materialized: materializing
51
+ * loads undici, which loads `_http_agent`.
52
+ *
53
+ * Policy
54
+ * ------
55
+ * One knob, `PYRIC_GUARD=warn|block|off`, default `warn`:
56
+ * warn report the egress, let it through
57
+ * block report it and fail the request
58
+ * off no hooks at all, one notice line at install time
59
+ * The GCE metadata IP (`169.254.169.254`, `alwaysBlock` in the catalog) is
60
+ * refused in warn mode and cannot be allowlisted, since its only use from a
61
+ * dev process is credential theft. `off` is genuinely off, metadata IP
62
+ * included; the off notice says so out loud.
63
+ *
64
+ * A blocked fetch surfaces to app code as a bare `TypeError: fetch failed`
65
+ * (the reason is buried on `error.cause`), so the guard must log its own
66
+ * denial: the app's error will never explain itself.
67
+ *
68
+ * The allowlist seam
69
+ * ------------------
70
+ * `PYRIC_GUARD_ALLOW` is a comma/whitespace separated list of hosts or URLs,
71
+ * matched on label boundaries, permitting an otherwise-flagged catalog host
72
+ * (an allowlisted hit is still reported once). Env is the seam by design:
73
+ * - the AI engine baseUrls live in the user's Vite config
74
+ * (`PyricAiOptions.engine.baseUrl`, `serve/vite-ai-config.ts`), which is
75
+ * read by the Vite plugin inside the serve host, a different process from
76
+ * the one this module loads into, and not parsed by the CLI at all;
77
+ * - `pyric.json` is read asynchronously by `runServe` (`cli/pyric-config.ts`)
78
+ * and this module runs on the `--import` hot path of every child, where a
79
+ * synchronous config-file read has no business being.
80
+ * `cli/sandbox-runner.ts:buildChildEnv` spreads the parent env into the child,
81
+ * so anything the pyric process exports reaches every descendant for free
82
+ * (`NODE_OPTIONS` already propagates the register import the same way). To
83
+ * wire a `pyric.json` `guardAllow` through, the whole change is: add the field
84
+ * to `PyricConfig`, and have `buildChildEnv` set `PYRIC_GUARD_ALLOW` from it
85
+ * at the `cli/serve.ts` call site, where `pyricConfig` is already in scope.
86
+ *
87
+ * Bun and Deno are out of scope: neither evaluates Node loader hooks (the
88
+ * register module never loads there) and neither routes `fetch` through
89
+ * undici's global dispatcher. `installNetGuard` degrades to the socket
90
+ * backstop instead of throwing.
91
+ */
92
+ import { createRequire } from 'node:module';
93
+ import { lookupGoogleEndpoint, matchesHostSuffix, normalizeHostname, } from '../google-endpoints.js';
94
+ /** undici's global-dispatcher slot. Version-suffixed by undici itself. */
95
+ const UNDICI_GLOBAL_DISPATCHER = Symbol.for('undici.globalDispatcher.1');
96
+ /** Marks a rejection as the guard's, so callers can tell it from a DNS/TLS
97
+ * failure. A blocked `fetch` only exposes it as `error.cause.code`. */
98
+ export const GUARD_BLOCKED_CODE = 'PYRIC_GUARD_BLOCKED';
99
+ const LOG_PREFIX = '@pyric/cli/register: net-guard';
100
+ /** How often to check that nobody replaced the global dispatcher under us. */
101
+ const REASSERT_INTERVAL_MS = 5_000;
102
+ /** `PYRIC_GUARD` → mode. Unset, empty or unrecognised all mean the safe
103
+ * default: report, do not break the developer's app. */
104
+ export function parseGuardMode(raw) {
105
+ const value = (raw ?? '').trim().toLowerCase();
106
+ if (value === 'block')
107
+ return 'block';
108
+ if (value === 'off')
109
+ return 'off';
110
+ return 'warn';
111
+ }
112
+ /** `PYRIC_GUARD_ALLOW` → hostnames. Accepts bare hosts and full URLs, because
113
+ * the values it carries are configured as URLs (AI engine baseUrls). */
114
+ export function parseAllowHosts(raw) {
115
+ if (!raw)
116
+ return [];
117
+ const out = [];
118
+ for (const token of raw.split(/[\s,]+/)) {
119
+ const entry = token.trim();
120
+ if (entry.length === 0)
121
+ continue;
122
+ out.push(hostnameOf(entry));
123
+ }
124
+ return out;
125
+ }
126
+ /** Only a trailing `:port` is stripped; a bare IPv6 address is left alone. */
127
+ const HOST_WITH_PORT = /^(.+):\d+$/;
128
+ /**
129
+ * Best-effort hostname from a host, `host:port`, or full URL. Normalization
130
+ * and suffix matching are the catalog's, so the guard and the catalog can
131
+ * never disagree about what a hostname is.
132
+ */
133
+ function hostnameOf(value) {
134
+ const trimmed = value.trim();
135
+ if (trimmed.includes('://')) {
136
+ try {
137
+ return normalizeHostname(new URL(trimmed).hostname).replace(/^\[|\]$/g, '');
138
+ }
139
+ catch {
140
+ // Not a parseable URL: fall through to the textual forms.
141
+ }
142
+ }
143
+ const withoutPath = trimmed.split('/')[0] ?? trimmed;
144
+ const portMatch = HOST_WITH_PORT.exec(withoutPath);
145
+ let hostPart;
146
+ if (portMatch === null) {
147
+ hostPart = withoutPath;
148
+ }
149
+ else {
150
+ hostPart = portMatch[1];
151
+ }
152
+ return normalizeHostname(hostPart);
153
+ }
154
+ /**
155
+ * The whole verdict, pure: catalog lookup, then `alwaysBlock`, then the
156
+ * allowlist, then the mode. `null` means nothing to say: either not a
157
+ * production endpoint, or the guard is off.
158
+ */
159
+ export function evaluateEgress(hostname, policy) {
160
+ if (policy.mode === 'off')
161
+ return null;
162
+ const host = hostnameOf(hostname);
163
+ if (host.length === 0)
164
+ return null;
165
+ const entry = lookupGoogleEndpoint(host);
166
+ if (entry === undefined)
167
+ return null;
168
+ // `alwaysBlock` outranks both the mode and the allowlist: the metadata
169
+ // server is never a legitimate destination for a sandboxed dev process, so
170
+ // there is no configuration that should be able to permit it.
171
+ if (entry.alwaysBlock === true) {
172
+ return {
173
+ verdict: 'block',
174
+ permitted: false,
175
+ host,
176
+ endpoint: entry.host,
177
+ service: entry.service,
178
+ alwaysBlock: true,
179
+ };
180
+ }
181
+ if (policy.allow.some((allowed) => matchesHostSuffix(host, allowed))) {
182
+ return { verdict: 'allow', permitted: true, host, endpoint: entry.host, service: entry.service };
183
+ }
184
+ if (policy.mode === 'block') {
185
+ return {
186
+ verdict: 'block',
187
+ permitted: false,
188
+ host,
189
+ endpoint: entry.host,
190
+ service: entry.service,
191
+ };
192
+ }
193
+ return { verdict: 'warn', permitted: true, host, endpoint: entry.host, service: entry.service };
194
+ }
195
+ /** One stderr line per verdict: structured (fixed leading fields, so it is
196
+ * greppable) and attributable (service + transport + initiating command).
197
+ * The request PATH is deliberately never logged: it carries ids and tokens. */
198
+ export function formatGuardLine(verdict, transport, context) {
199
+ let where = `via ${transport}`;
200
+ if (context !== undefined && context.length > 0)
201
+ where = `${where} from ${context}`;
202
+ const head = `${LOG_PREFIX} ${verdict.verdict.toUpperCase()} ${verdict.host} (${verdict.service}) ${where}:`;
203
+ const tail = 'Further attempts to this host are not logged.';
204
+ if (verdict.verdict === 'allow') {
205
+ return `${head} live production egress permitted by PYRIC_GUARD_ALLOW. ${tail}\n`;
206
+ }
207
+ if (verdict.verdict === 'warn') {
208
+ return (`${head} LIVE production egress. A sandboxed app routes Firebase traffic to /__pyric/*, ` +
209
+ `so this is reaching real data. Set PYRIC_GUARD=block to fail these requests instead. ${tail}\n`);
210
+ }
211
+ let why;
212
+ if (verdict.alwaysBlock === true) {
213
+ why = 'the credential metadata server is refused in every mode except PYRIC_GUARD=off';
214
+ }
215
+ else {
216
+ why = 'live production egress refused (PYRIC_GUARD=block)';
217
+ }
218
+ // What the app actually observes differs by seam: undici swallows our throw
219
+ // into the opaque `TypeError: fetch failed`, while a raw socket caller gets
220
+ // the error itself. Say which, or the developer cannot connect the two.
221
+ let surfaces;
222
+ if (transport === 'fetch') {
223
+ surfaces = `the caller sees \`TypeError: fetch failed\` with cause ${GUARD_BLOCKED_CODE}`;
224
+ }
225
+ else {
226
+ surfaces = `the caller sees an error with code ${GUARD_BLOCKED_CODE}`;
227
+ }
228
+ return `${head} ${why}; ${surfaces}. ${tail}\n`;
229
+ }
230
+ function blockedError(verdict, transport) {
231
+ return Object.assign(new Error(`pyric net-guard blocked ${transport} egress to ${verdict.host} (${verdict.service}): ` +
232
+ `this is LIVE production, not the pyric sandbox. ` +
233
+ `Set PYRIC_GUARD=warn to allow it, or PYRIC_GUARD_ALLOW to permit this host.`), { code: GUARD_BLOCKED_CODE, host: verdict.host, service: verdict.service });
234
+ }
235
+ function createReporter(options) {
236
+ const write = options.write ?? ((line) => void process.stderr.write(line));
237
+ const policy = { mode: options.mode, allow: options.allow };
238
+ const reported = options.reported ?? new Set();
239
+ return {
240
+ check(hostname, transport) {
241
+ if (hostname === undefined)
242
+ return;
243
+ const verdict = evaluateEgress(hostname, policy);
244
+ if (verdict === null)
245
+ return;
246
+ // A dev server retries relentlessly; one line per host is the signal,
247
+ // and it also collapses the undici-over-net.connect double report.
248
+ const key = `${verdict.verdict}:${verdict.host}`;
249
+ if (!reported.has(key)) {
250
+ reported.add(key);
251
+ write(formatGuardLine(verdict, transport, options.context));
252
+ }
253
+ if (!verdict.permitted)
254
+ throw blockedError(verdict, transport);
255
+ },
256
+ };
257
+ }
258
+ /** `opts.origin` is a URL or an origin string; anything else means "no idea",
259
+ * and an unrecognisable origin is passed through rather than guessed at. */
260
+ function originHost(opts) {
261
+ const origin = opts?.origin;
262
+ if (origin === undefined || origin === null)
263
+ return undefined;
264
+ if (typeof origin === 'object' && 'hostname' in origin) {
265
+ const hostname = origin.hostname;
266
+ return typeof hostname === 'string' ? hostname.toLowerCase() : undefined;
267
+ }
268
+ if (typeof origin !== 'string')
269
+ return undefined;
270
+ try {
271
+ return new URL(origin).hostname.toLowerCase();
272
+ }
273
+ catch {
274
+ return undefined;
275
+ }
276
+ }
277
+ /**
278
+ * Wrap a dispatcher so `dispatch` is guarded and every other member still
279
+ * belongs to the real instance.
280
+ *
281
+ * A `Proxy` rather than a subclass or a copy: undici's Agent keeps state in
282
+ * private fields and internal symbols, and every forwarded call must run with
283
+ * `this` bound to the REAL instance (hence `Reflect.get(target, prop, target)`
284
+ * and the bind) or those fields are not there. `instanceof` keeps working.
285
+ */
286
+ export function wrapDispatcher(real, options) {
287
+ const reporter = createReporter(options);
288
+ const guardedDispatch = (opts, handler) => {
289
+ reporter.check(originHost(opts), 'fetch');
290
+ // Both arguments cross UNTOUCHED. Edge hands a v6 handler to the host's
291
+ // v7 Agent, and that handoff only survives by identity.
292
+ return real.dispatch(opts, handler);
293
+ };
294
+ return new Proxy(real, {
295
+ get(target, prop) {
296
+ if (prop === 'dispatch')
297
+ return guardedDispatch;
298
+ const value = Reflect.get(target, prop, target);
299
+ return typeof value === 'function' ? value.bind(target) : value;
300
+ },
301
+ });
302
+ }
303
+ /** `basename(argv[1])`, the cheapest honest attribution available. */
304
+ function contextFrom(argv) {
305
+ const entry = argv?.[1];
306
+ if (typeof entry !== 'string' || entry.length === 0)
307
+ return undefined;
308
+ const parts = entry.split(/[\\/]/);
309
+ return parts[parts.length - 1] || undefined;
310
+ }
311
+ /**
312
+ * Materialize undici's lazy global dispatcher without touching the network.
313
+ * `new Headers()` loads Node's undici, whose module body installs a default
314
+ * Agent into the symbol only if the slot is still empty, so this must run
315
+ * before we put anything there. It also loads `_http_agent`, which is why the
316
+ * socket patches go in first.
317
+ */
318
+ function materializeGlobalDispatcher() {
319
+ try {
320
+ new Headers();
321
+ }
322
+ catch {
323
+ // No WHATWG Headers, or a runtime that never had undici. The socket
324
+ // backstop still applies.
325
+ }
326
+ }
327
+ /**
328
+ * The `http.Agent` and `https.Agent` prototypes, or an empty list on a runtime
329
+ * without them. Each carries its own `createConnection`: `http`'s is a copied
330
+ * reference to `net.createConnection` snapshotted at `_http_agent` load time,
331
+ * so patching `net` alone leaves it unguarded whenever `node:http` loaded
332
+ * first.
333
+ */
334
+ function nodeAgentPrototypes() {
335
+ const require = createRequire(import.meta.url);
336
+ const prototypes = [];
337
+ for (const id of ['node:http', 'node:https']) {
338
+ try {
339
+ const mod = require(id);
340
+ const prototype = mod.Agent?.prototype;
341
+ if (typeof prototype === 'object' && prototype !== null) {
342
+ prototypes.push(prototype);
343
+ }
344
+ }
345
+ catch {
346
+ // Runtime without that module: the other seams still apply.
347
+ }
348
+ }
349
+ return prototypes;
350
+ }
351
+ /**
352
+ * Install the guard. Gated on `PYRIC_SANDBOX` exactly like the rest of the
353
+ * register module: without the activator this is a no-op, so the module stays
354
+ * safe to import anywhere. Returns `null` when nothing was installed.
355
+ */
356
+ export function installNetGuard(hooks = {}) {
357
+ const env = hooks.env ?? process.env;
358
+ if (!env.PYRIC_SANDBOX)
359
+ return null;
360
+ const write = hooks.write ?? ((line) => void process.stderr.write(line));
361
+ const mode = parseGuardMode(env.PYRIC_GUARD);
362
+ if (mode === 'off') {
363
+ write(`${LOG_PREFIX} disabled (PYRIC_GUARD=off): egress from this process to live ` +
364
+ `Google/Firebase endpoints is neither reported nor blocked, not even the GCE ` +
365
+ `metadata server (169.254.169.254).\n`);
366
+ return null;
367
+ }
368
+ const allow = parseAllowHosts(env.PYRIC_GUARD_ALLOW);
369
+ const context = contextFrom(hooks.argv ?? process.argv);
370
+ const reporterOptions = { mode, allow, write, context, reported: new Set() };
371
+ const scope = hooks.scope ?? globalThis;
372
+ // ── socket backstop: http.request, gRPC, DB drivers, raw sockets ──
373
+ //
374
+ // This runs FIRST, before the dispatcher is materialized. Materializing
375
+ // loads undici, which loads `_http_agent`, which snapshots
376
+ // `net.createConnection` onto `http.Agent.prototype.createConnection`. With
377
+ // the order reversed, that snapshot is the unpatched function and every
378
+ // plain `http.request` escapes the guard, the metadata server included.
379
+ const require = createRequire(import.meta.url);
380
+ const netModule = hooks.net ?? require('node:net');
381
+ const tlsModule = hooks.tls ?? require('node:tls');
382
+ const reporter = createReporter(reporterOptions);
383
+ const guardConnect = (target, name) => {
384
+ const original = target[name];
385
+ if (typeof original !== 'function')
386
+ return;
387
+ const wrapped = function (...args) {
388
+ reporter.check(connectHost(args), 'socket');
389
+ return original.apply(this, args);
390
+ };
391
+ target[name] = wrapped;
392
+ };
393
+ guardConnect(netModule, 'connect');
394
+ guardConnect(netModule, 'createConnection');
395
+ guardConnect(tlsModule, 'connect');
396
+ // And the Agent prototypes, so a `node:http` that loaded before this module
397
+ // is still covered. `https.Agent` also reaches the patched `tls.connect`, so
398
+ // its own patch is a second check on the same egress; the once-per-host
399
+ // dedupe keeps that from printing twice.
400
+ for (const prototype of hooks.agentPrototypes ?? nodeAgentPrototypes()) {
401
+ guardConnect(prototype, 'createConnection');
402
+ }
403
+ let installed;
404
+ const wrapGlobalDispatcher = () => {
405
+ const current = scope[UNDICI_GLOBAL_DISPATCHER];
406
+ if (current === undefined || current === null)
407
+ return;
408
+ if (current === installed)
409
+ return;
410
+ if (typeof current.dispatch !== 'function')
411
+ return;
412
+ // PLAIN ASSIGNMENT. undici's own property is
413
+ // `configurable: false, writable: true`; a `defineProperty` that tries to
414
+ // make it configurable throws and takes the process down.
415
+ installed = wrapDispatcher(current, reporterOptions);
416
+ scope[UNDICI_GLOBAL_DISPATCHER] = installed;
417
+ };
418
+ if (hooks.scope === undefined)
419
+ materializeGlobalDispatcher();
420
+ wrapGlobalDispatcher();
421
+ let timer;
422
+ if (hooks.scope === undefined) {
423
+ timer = setInterval(wrapGlobalDispatcher, REASSERT_INTERVAL_MS);
424
+ // Never hold the event loop open: a guarded child must still exit.
425
+ timer.unref?.();
426
+ }
427
+ return {
428
+ mode,
429
+ allow,
430
+ reassert: wrapGlobalDispatcher,
431
+ stop() {
432
+ if (timer !== undefined)
433
+ clearInterval(timer);
434
+ },
435
+ };
436
+ }
437
+ /**
438
+ * Extract the destination host from `net.connect` / `tls.connect` arguments,
439
+ * across all of their overloads: `(options[, cb])`, `(port[, host][, cb])`,
440
+ * `(path[, cb])`. An IPC path or a portless local socket has no host, which is
441
+ * exactly the "nothing to say" answer.
442
+ */
443
+ function connectHost(args) {
444
+ const first = args[0];
445
+ if (typeof first === 'object' && first !== null) {
446
+ const host = first.host ??
447
+ first.hostname;
448
+ return typeof host === 'string' ? host : undefined;
449
+ }
450
+ if (typeof first === 'number' || (typeof first === 'string' && /^\d+$/.test(first))) {
451
+ // (port, host?, ...): the host, when given, is the next string argument.
452
+ const second = args[1];
453
+ if (typeof second === 'string')
454
+ return second;
455
+ if (typeof second === 'object' && second !== null) {
456
+ const host = second.host;
457
+ return typeof host === 'string' ? host : undefined;
458
+ }
459
+ }
460
+ return undefined;
461
+ }
462
+ //# sourceMappingURL=net-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"net-guard.js","sourceRoot":"","sources":["../../src/register/net-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { SandboxEvent } from 'pyric/sandbox';
2
+ /**
3
+ * AI diagnostics relay: headless dev visibility for the three things the
4
+ * broker does that no app-level signal reports.
5
+ *
6
+ * The broker lands `service_mutation` events (`service: 'ai'`) on the
7
+ * sandbox's unified stream. That stream is browser-side: the worker host fans
8
+ * it out over the port for Studio, and it never reaches the dev server. An
9
+ * agent driving `pyric dev` headlessly therefore saw NOTHING.
10
+ *
11
+ * - `request_rejected`: a bad role, empty `contents`, a missing thought
12
+ * signature, or an engine that answered an error envelope.
13
+ * - `response_blocked`: the SILENT refusal. A safety / recitation /
14
+ * blocklist filter answers HTTP 200 with an empty candidate, so nothing
15
+ * throws anywhere and the app simply renders nothing.
16
+ * - `model_substituted`: not a refusal at all. The answer arrives, from a
17
+ * model the developer never asked for (an openai `modelMap` entry or
18
+ * catch-all `model`, a gemini experimental alias). Same shape of problem:
19
+ * the sandbox quietly did something other than what the code said, and
20
+ * only the terminal can say so.
21
+ *
22
+ * One record per kind in {@link AI_DIAGNOSTIC_RELAYS} pairs the sandbox `op`
23
+ * with the narrower that turns it into a wire payload. The terminal formatter
24
+ * and throttle key for each kind live in `ai-terminal-blocks.ts`, keyed by the
25
+ * same {@link AiDiagnosticKind} union, so the compiler flags a kind that is
26
+ * relayed but never rendered.
27
+ *
28
+ * This is the AI twin of the Firebase Activity Guard reporter next door
29
+ * (`activity-guard.ts`): a browser-safe subscriber shared by the SharedWorker
30
+ * and in-page planes, which fire-and-forget POSTs to the dev server. It rides
31
+ * the DENIAL relay's existing channel (`POST /__pyric/denials`, see the denial
32
+ * relay section of `namespace.ts`) rather than opening a new one: a broker
33
+ * refusal is the same category of thing as a rules denial, it wants the same
34
+ * terminal treatment, and it wants that endpoint's per-(target, reason)
35
+ * throttle, because an agent retry loop re-sends the same request over and
36
+ * over.
37
+ *
38
+ * Best-effort, exactly like the activity reporter and the denial relay: never
39
+ * throws, never awaited into app flow, and a relay failure (dev server gone,
40
+ * no `fetch`, non-pyric host) is swallowed. Diagnostics, not a correctness
41
+ * path.
42
+ */
43
+ /** The slice of the sandbox this relay needs. Live events only: replaying
44
+ * `history()` on boot would re-announce refusals the terminal already
45
+ * printed (and the activity feed's reason for taking history does not apply,
46
+ * since nothing here correlates across events). */
47
+ export interface AiDiagnosticsFeed {
48
+ subscribe(listener: (event: SandboxEvent) => void): unknown;
49
+ }
50
+ /** The `kind` discriminator on every payload this relay POSTs. It is also the
51
+ * key of the formatter table in `ai-terminal-blocks.ts`. */
52
+ export type AiDiagnosticKind = 'ai-rejection' | 'ai-blocked' | 'ai-model-substituted';
53
+ /**
54
+ * Subscribe to the sandbox event stream and relay every broker refusal,
55
+ * rejected request or blocked response, plus every silent model substitution,
56
+ * to the dev server for terminal visibility.
57
+ *
58
+ * Browser-safe (shared by the SharedWorker host and the in-page runtime);
59
+ * returns nothing to unsubscribe with, mirroring the guard next door, since
60
+ * the subscription is observational and lives for the plane's lifetime.
61
+ */
62
+ export declare function setupAiDiagnosticsRelay(feed: AiDiagnosticsFeed, fetchFn: typeof fetch): void;
63
+ //# sourceMappingURL=ai-diagnostics-relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-diagnostics-relay.d.ts","sourceRoot":"","sources":["../../src/serve/ai-diagnostics-relay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH;;;oDAGoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC;CAC7D;AAED;6DAC6D;AAC7D,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,YAAY,GAAG,sBAAsB,CAAC;AA8JtF;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,KAAK,GAAG,IAAI,CAoB5F"}
@@ -0,0 +1,125 @@
1
+ import { capTerminalText } from './ai-terminal-text.js';
2
+ /**
3
+ * A string field off the event's free-form `detail` record, or `undefined`
4
+ * when the emitter did not set it. `detail` is a public contract anyone can
5
+ * post onto, so every field is re-checked, and every value is length-capped
6
+ * here rather than on the far side: a model server that answers with a
7
+ * megabyte in its `finishMessage` must not push a megabyte through the
8
+ * fire-and-forget POST just to have the terminal cut it.
9
+ */
10
+ function detailText(detail, field) {
11
+ const value = detail[field];
12
+ if (typeof value !== 'string')
13
+ return undefined;
14
+ return capTerminalText(value);
15
+ }
16
+ /** The event's `path` when it names a model, or `undefined`. */
17
+ function eventModel(event) {
18
+ if (typeof event.path !== 'string' || event.path === '')
19
+ return undefined;
20
+ return capTerminalText(event.path);
21
+ }
22
+ function detailOf(event) {
23
+ return (event.detail ?? {});
24
+ }
25
+ /** Narrow a `request_rejected` event to its relay payload. */
26
+ function toRejectionPayload(event) {
27
+ const detail = detailOf(event);
28
+ const payload = {
29
+ kind: 'ai-rejection',
30
+ message: detailText(detail, 'message') ?? 'request rejected',
31
+ };
32
+ payload.model = eventModel(event);
33
+ payload.engine = detailText(detail, 'engine');
34
+ payload.status = detailText(detail, 'status');
35
+ if (typeof detail.code === 'number')
36
+ payload.code = detail.code;
37
+ return payload;
38
+ }
39
+ /** Narrow a `response_blocked` event to its relay payload. */
40
+ function toBlockedPayload(event) {
41
+ const detail = detailOf(event);
42
+ const payload = { kind: 'ai-blocked' };
43
+ payload.model = eventModel(event);
44
+ payload.engine = detailText(detail, 'engine');
45
+ payload.finishReason = detailText(detail, 'finishReason');
46
+ payload.finishMessage = detailText(detail, 'finishMessage');
47
+ payload.blockReason = detailText(detail, 'blockReason');
48
+ return payload;
49
+ }
50
+ /**
51
+ * Narrow a `model_substituted` event to its relay payload, and enforce the
52
+ * invariant the terminal line depends on: an effective model equal to the
53
+ * requested one is NOT a substitution and never relays. The broker already
54
+ * compares before emitting; this re-checks because the event stream is a
55
+ * public contract anyone can post onto.
56
+ */
57
+ function toModelSubstitutionPayload(event) {
58
+ const detail = detailOf(event);
59
+ const requestedModel = detailText(detail, 'requestedModel') ?? eventModel(event) ?? '';
60
+ const effectiveModel = detailText(detail, 'effectiveModel') ?? '';
61
+ if (requestedModel === '' || effectiveModel === '')
62
+ return null;
63
+ let requestedBare = requestedModel;
64
+ if (requestedModel.startsWith('models/'))
65
+ requestedBare = requestedModel.slice('models/'.length);
66
+ if (effectiveModel === requestedBare || effectiveModel === requestedModel)
67
+ return null;
68
+ const payload = {
69
+ kind: 'ai-model-substituted',
70
+ requestedModel,
71
+ effectiveModel,
72
+ };
73
+ payload.engine = detailText(detail, 'engine');
74
+ payload.reason = detailText(detail, 'reason');
75
+ return payload;
76
+ }
77
+ const AI_DIAGNOSTIC_RELAYS = {
78
+ 'ai-rejection': { op: 'request_rejected', fromEvent: toRejectionPayload },
79
+ 'ai-blocked': { op: 'response_blocked', fromEvent: toBlockedPayload },
80
+ 'ai-model-substituted': { op: 'model_substituted', fromEvent: toModelSubstitutionPayload },
81
+ };
82
+ /** The relay record for a sandbox `op`, or `null` for an op nothing relays. */
83
+ function relayForOp(op) {
84
+ for (const relay of Object.values(AI_DIAGNOSTIC_RELAYS)) {
85
+ if (relay.op === op)
86
+ return relay;
87
+ }
88
+ return null;
89
+ }
90
+ /**
91
+ * Subscribe to the sandbox event stream and relay every broker refusal,
92
+ * rejected request or blocked response, plus every silent model substitution,
93
+ * to the dev server for terminal visibility.
94
+ *
95
+ * Browser-safe (shared by the SharedWorker host and the in-page runtime);
96
+ * returns nothing to unsubscribe with, mirroring the guard next door, since
97
+ * the subscription is observational and lives for the plane's lifetime.
98
+ */
99
+ export function setupAiDiagnosticsRelay(feed, fetchFn) {
100
+ feed.subscribe((event) => {
101
+ if (event.kind !== 'service_mutation')
102
+ return;
103
+ if (event.service !== 'ai')
104
+ return;
105
+ const relay = relayForOp(event.op);
106
+ if (relay === null)
107
+ return;
108
+ const payload = relay.fromEvent(event);
109
+ if (payload === null)
110
+ return;
111
+ try {
112
+ void fetchFn('/__pyric/denials', {
113
+ method: 'POST',
114
+ headers: { 'content-type': 'application/json' },
115
+ body: JSON.stringify(payload),
116
+ }).catch(() => {
117
+ /* Diagnostics are best-effort and must never affect app behavior. */
118
+ });
119
+ }
120
+ catch {
121
+ /* An injected or unavailable fetch must never affect app behavior. */
122
+ }
123
+ });
124
+ }
125
+ //# sourceMappingURL=ai-diagnostics-relay.js.map