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

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 (384) hide show
  1. package/README.md +13 -9
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +80 -72
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +80 -72
  5. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  6. package/dist/bridge/client/dispatch.js +1 -1
  7. package/dist/bridge/client/dispatch.js.map +1 -1
  8. package/dist/cli/database-rules.d.ts.map +1 -1
  9. package/dist/cli/database-rules.js +6 -4
  10. package/dist/cli/database-rules.js.map +1 -1
  11. package/dist/cli/dev-runner.d.ts +9 -0
  12. package/dist/cli/dev-runner.d.ts.map +1 -1
  13. package/dist/cli/dev-runner.js +18 -0
  14. package/dist/cli/dev-runner.js.map +1 -1
  15. package/dist/cli/serve.d.ts.map +1 -1
  16. package/dist/cli/serve.js +61 -6
  17. package/dist/cli/serve.js.map +1 -1
  18. package/dist/cli/verify.js +2 -2
  19. package/dist/cli/verify.js.map +1 -1
  20. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  21. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  22. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  23. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  24. package/dist/conformance/.generated/can-i-use.js +1 -1
  25. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  26. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
  27. package/dist/conformance/.generated/conformance-docs.js +1 -1
  28. package/dist/conformance/.generated/conformance-docs.js.map +1 -1
  29. package/dist/next/client-aliases.d.ts +11 -0
  30. package/dist/next/client-aliases.d.ts.map +1 -0
  31. package/dist/next/client-aliases.js +38 -0
  32. package/dist/next/client-aliases.js.map +1 -0
  33. package/dist/next/dev-rewrites.d.ts +9 -0
  34. package/dist/next/dev-rewrites.d.ts.map +1 -0
  35. package/dist/next/dev-rewrites.js +53 -0
  36. package/dist/next/dev-rewrites.js.map +1 -0
  37. package/dist/next/guard.d.ts +15 -0
  38. package/dist/next/guard.d.ts.map +1 -0
  39. package/dist/next/guard.js +52 -0
  40. package/dist/next/guard.js.map +1 -0
  41. package/dist/next/index.d.ts +12 -0
  42. package/dist/next/index.d.ts.map +1 -0
  43. package/dist/next/index.js +11 -0
  44. package/dist/next/index.js.map +1 -0
  45. package/dist/next/runtime-env.d.ts +7 -0
  46. package/dist/next/runtime-env.d.ts.map +1 -0
  47. package/dist/next/runtime-env.js +13 -0
  48. package/dist/next/runtime-env.js.map +1 -0
  49. package/dist/next/server-external-packages.d.ts +10 -0
  50. package/dist/next/server-external-packages.d.ts.map +1 -0
  51. package/dist/next/server-external-packages.js +34 -0
  52. package/dist/next/server-external-packages.js.map +1 -0
  53. package/dist/next/target-url.d.ts +11 -0
  54. package/dist/next/target-url.d.ts.map +1 -0
  55. package/dist/next/target-url.js +36 -0
  56. package/dist/next/target-url.js.map +1 -0
  57. package/dist/next/turbopack-config.d.ts +9 -0
  58. package/dist/next/turbopack-config.d.ts.map +1 -0
  59. package/dist/next/turbopack-config.js +39 -0
  60. package/dist/next/turbopack-config.js.map +1 -0
  61. package/dist/next/types.d.ts +40 -0
  62. package/dist/next/types.d.ts.map +1 -0
  63. package/dist/next/types.js +5 -0
  64. package/dist/next/types.js.map +1 -0
  65. package/dist/next/webpack-config.d.ts +11 -0
  66. package/dist/next/webpack-config.d.ts.map +1 -0
  67. package/dist/next/webpack-config.js +51 -0
  68. package/dist/next/webpack-config.js.map +1 -0
  69. package/dist/next/with-pyric.d.ts +22 -0
  70. package/dist/next/with-pyric.d.ts.map +1 -0
  71. package/dist/next/with-pyric.js +49 -0
  72. package/dist/next/with-pyric.js.map +1 -0
  73. package/dist/register/app-bridge.d.ts +9 -0
  74. package/dist/register/app-bridge.d.ts.map +1 -0
  75. package/dist/register/app-bridge.js +56 -0
  76. package/dist/register/app-bridge.js.map +1 -0
  77. package/dist/register/hooks.d.ts.map +1 -1
  78. package/dist/register/hooks.js +6 -1
  79. package/dist/register/hooks.js.map +1 -1
  80. package/dist/register/index.js +1 -1
  81. package/dist/register/index.js.map +1 -1
  82. package/dist/register/mapping.d.ts +3 -1
  83. package/dist/register/mapping.d.ts.map +1 -1
  84. package/dist/register/mapping.js +41 -5
  85. package/dist/register/mapping.js.map +1 -1
  86. package/dist/rtdb/rules-json.d.ts +12 -0
  87. package/dist/rtdb/rules-json.d.ts.map +1 -1
  88. package/dist/rtdb/rules-json.js +98 -0
  89. package/dist/rtdb/rules-json.js.map +1 -1
  90. package/dist/serve/bundler.d.ts.map +1 -1
  91. package/dist/serve/bundler.js +2 -0
  92. package/dist/serve/bundler.js.map +1 -1
  93. package/dist/serve/discovery.d.ts +4 -4
  94. package/dist/serve/discovery.d.ts.map +1 -1
  95. package/dist/serve/discovery.js +59 -38
  96. package/dist/serve/discovery.js.map +1 -1
  97. package/dist/serve/entries/app-ai-passthrough.d.ts +8 -0
  98. package/dist/serve/entries/app-ai-passthrough.d.ts.map +1 -0
  99. package/dist/serve/entries/app-ai-passthrough.js +59 -0
  100. package/dist/serve/entries/app-ai-passthrough.js.map +1 -0
  101. package/dist/serve/entries/auth-helper-core.d.ts +9 -0
  102. package/dist/serve/entries/auth-helper-core.d.ts.map +1 -1
  103. package/dist/serve/entries/auth-helper-core.js +37 -8
  104. package/dist/serve/entries/auth-helper-core.js.map +1 -1
  105. package/dist/serve/entries/auth.d.ts +1 -0
  106. package/dist/serve/entries/auth.d.ts.map +1 -1
  107. package/dist/serve/entries/auth.js +7 -4
  108. package/dist/serve/entries/auth.js.map +1 -1
  109. package/dist/serve/entries/bridge-url.d.ts.map +1 -1
  110. package/dist/serve/entries/bridge-url.js +7 -2
  111. package/dist/serve/entries/bridge-url.js.map +1 -1
  112. package/dist/serve/entries/database.d.ts +1 -0
  113. package/dist/serve/entries/database.d.ts.map +1 -1
  114. package/dist/serve/entries/database.js +1 -0
  115. package/dist/serve/entries/database.js.map +1 -1
  116. package/dist/serve/entries/firestore.d.ts +1 -0
  117. package/dist/serve/entries/firestore.d.ts.map +1 -1
  118. package/dist/serve/entries/firestore.js +1 -0
  119. package/dist/serve/entries/firestore.js.map +1 -1
  120. package/dist/serve/entries/init.d.ts.map +1 -1
  121. package/dist/serve/entries/init.js +4 -2
  122. package/dist/serve/entries/init.js.map +1 -1
  123. package/dist/serve/entries/runtime.js +23 -0
  124. package/dist/serve/entries/runtime.js.map +1 -1
  125. package/dist/serve/entries/storage.d.ts +2 -0
  126. package/dist/serve/entries/storage.d.ts.map +1 -1
  127. package/dist/serve/entries/storage.js +9 -2
  128. package/dist/serve/entries/storage.js.map +1 -1
  129. package/dist/serve/html-injection.d.ts +3 -1
  130. package/dist/serve/html-injection.d.ts.map +1 -1
  131. package/dist/serve/html-injection.js +27 -1
  132. package/dist/serve/html-injection.js.map +1 -1
  133. package/dist/serve/rules.js +2 -2
  134. package/dist/serve/rules.js.map +1 -1
  135. package/dist/serve/runtime/chip-config.d.ts +1 -1
  136. package/dist/serve/runtime/chip-config.d.ts.map +1 -1
  137. package/dist/serve/runtime/chip-config.js +16 -8
  138. package/dist/serve/runtime/chip-config.js.map +1 -1
  139. package/dist/serve/sandbox-session.d.ts +1 -0
  140. package/dist/serve/sandbox-session.d.ts.map +1 -1
  141. package/dist/serve/sandbox-session.js +30 -2
  142. package/dist/serve/sandbox-session.js.map +1 -1
  143. package/dist/serve/site-ui/_astro/_studio_.B6b_G1ev.css +1 -0
  144. package/dist/serve/site-ui/_astro/app.bnmVTkIY.js +11 -0
  145. package/dist/serve/site-ui/_astro/app.t6u-adB_.js +1 -0
  146. package/dist/serve/site-ui/_astro/{chess-showcase.DzPO6kz0.js → chess-showcase.kC8dXLKY.js} +1 -1
  147. package/dist/serve/site-ui/_astro/{example-runtime.CM0H02rx.js → example-runtime.D79PnoSk.js} +1 -1
  148. package/dist/serve/site-ui/_astro/index.DzVde04M.js +1 -0
  149. package/dist/serve/site-ui/_astro/reads.BYBRLbsE.js +1 -0
  150. package/dist/serve/site-ui/_astro/sandbox-controls.C9Aaazt8.js +1252 -0
  151. package/dist/serve/site-ui/_astro/{seed.BCn5DhHS.js → seed.DANAIyRw.js} +1 -1
  152. package/dist/serve/site-ui/auth/index.html +2 -2
  153. package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
  154. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +1 -1
  155. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
  156. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
  157. package/dist/serve/site-ui/docs/ai-compat/index.html +85 -85
  158. package/dist/serve/site-ui/docs/ai-compat.md +84 -84
  159. package/dist/serve/site-ui/docs/api-reference/index.html +3 -1
  160. package/dist/serve/site-ui/docs/api-reference.md +2 -0
  161. package/dist/serve/site-ui/docs/app-compat/index.html +28 -28
  162. package/dist/serve/site-ui/docs/app-compat.md +27 -27
  163. package/dist/serve/site-ui/docs/auth-compat/index.html +122 -122
  164. package/dist/serve/site-ui/docs/auth-compat.md +121 -121
  165. package/dist/serve/site-ui/docs/build/ai-logic/index.html +1 -1
  166. package/dist/serve/site-ui/docs/build/authentication/index.html +1 -1
  167. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +1 -1
  168. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
  169. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +1 -1
  170. package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
  171. package/dist/serve/site-ui/docs/conformance-scores/index.html +4 -4
  172. package/dist/serve/site-ui/docs/conformance-scores.md +3 -3
  173. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +6 -6
  174. package/dist/serve/site-ui/docs/create-pyric-reference-api.md +5 -5
  175. package/dist/serve/site-ui/docs/database-compat/index.html +200 -448
  176. package/dist/serve/site-ui/docs/database-compat.md +198 -461
  177. package/dist/serve/site-ui/docs/examples/chess/index.html +2 -2
  178. package/dist/serve/site-ui/docs/examples/index.html +1 -1
  179. package/dist/serve/site-ui/docs/firestore-compat/index.html +186 -195
  180. package/dist/serve/site-ui/docs/firestore-compat.md +184 -195
  181. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +15 -15
  182. package/dist/serve/site-ui/docs/functions-rtdb-compat.md +14 -14
  183. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  184. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +57 -0
  185. package/dist/serve/site-ui/docs/get-started/nextjs.md +86 -0
  186. package/dist/serve/site-ui/docs/get-started/start-building/index.html +25 -8
  187. package/dist/serve/site-ui/docs/get-started/start-building.md +34 -5
  188. package/dist/serve/site-ui/docs/get-started/vite/index.html +26 -0
  189. package/dist/serve/site-ui/docs/get-started/vite.md +45 -0
  190. package/dist/serve/site-ui/docs/index.json +668 -103
  191. package/dist/serve/site-ui/docs/messaging-compat/index.html +56 -56
  192. package/dist/serve/site-ui/docs/messaging-compat.md +55 -55
  193. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +1 -1
  194. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
  195. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
  196. package/dist/serve/site-ui/docs/overview/index.html +1 -1
  197. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +39 -13
  198. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api.md +28 -2
  199. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  200. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +38 -6
  201. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api.md +43 -0
  202. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +9 -1
  203. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api.md +8 -0
  204. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
  205. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +27 -4
  206. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api.md +23 -0
  207. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
  208. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  209. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
  210. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +2 -2
  211. package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +1 -1
  212. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  213. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  214. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  215. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  216. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  217. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  218. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  219. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  220. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  221. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +123 -0
  222. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api.md +99 -0
  223. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +127 -0
  224. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api.md +174 -0
  225. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  226. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  227. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +570 -326
  228. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api.md +198 -6
  229. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  230. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +1 -1
  231. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +1 -1
  232. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +2971 -627
  233. package/dist/serve/site-ui/docs/pyric-firestore-reference-api.md +2873 -517
  234. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  235. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  236. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +43 -3
  237. package/dist/serve/site-ui/docs/pyric-rules-reference-api.md +8 -0
  238. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +26 -2
  239. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api.md +24 -0
  240. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  241. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +77 -9
  242. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api.md +28 -13
  243. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +240 -63
  244. package/dist/serve/site-ui/docs/pyric-storage-reference-api.md +164 -5
  245. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  246. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  247. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  248. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  249. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  250. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  251. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  252. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  253. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  254. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  255. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  256. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  257. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +2 -1
  258. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api.md +1 -0
  259. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  260. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  261. package/dist/serve/site-ui/docs/rules-compat/index.html +87 -79
  262. package/dist/serve/site-ui/docs/rules-compat.md +86 -78
  263. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
  264. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  265. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
  266. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  267. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
  268. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  269. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +1 -1
  270. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  271. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
  272. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
  273. package/dist/serve/site-ui/docs/storage-compat/index.html +119 -125
  274. package/dist/serve/site-ui/docs/storage-compat.md +118 -124
  275. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  276. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
  277. package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +1 -1
  278. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  279. package/dist/serve/site-ui/docs/tutorial/index.html +1 -1
  280. package/dist/serve/site-ui/examples/chess/index.html +1 -1
  281. package/dist/serve/site-ui/examples/firestore-first-write/index.html +1 -1
  282. package/dist/serve/site-ui/firestore/index.html +2 -2
  283. package/dist/serve/site-ui/index.html +2 -2
  284. package/dist/serve/site-ui/llms.txt +6 -2
  285. package/dist/serve/site-ui/rtdb/index.html +2 -2
  286. package/dist/serve/site-ui/settings/index.html +2 -2
  287. package/dist/serve/site-ui/storage/index.html +2 -2
  288. package/dist/serve/site-ui/traffic/index.html +2 -2
  289. package/dist/serve/vite-ai-config.d.ts +4 -1
  290. package/dist/serve/vite-ai-config.d.ts.map +1 -1
  291. package/dist/serve/vite-ai-config.js +83 -19
  292. package/dist/serve/vite-ai-config.js.map +1 -1
  293. package/dist/serve/vite-generation-rules-watch.d.ts.map +1 -1
  294. package/dist/serve/vite-generation-rules-watch.js +61 -14
  295. package/dist/serve/vite-generation-rules-watch.js.map +1 -1
  296. package/dist/serve/vite-module-swap.d.ts +4 -1
  297. package/dist/serve/vite-module-swap.d.ts.map +1 -1
  298. package/dist/serve/vite-module-swap.js +106 -21
  299. package/dist/serve/vite-module-swap.js.map +1 -1
  300. package/dist/serve/vite-plugin.d.ts.map +1 -1
  301. package/dist/serve/vite-plugin.js +45 -5
  302. package/dist/serve/vite-plugin.js.map +1 -1
  303. package/dist/serve/vite-sandbox-generation.js +1 -1
  304. package/dist/serve/vite-sandbox-generation.js.map +1 -1
  305. package/dist/serve/worker/client/resumable.d.ts +30 -0
  306. package/dist/serve/worker/client/resumable.d.ts.map +1 -0
  307. package/dist/serve/worker/client/resumable.js +416 -0
  308. package/dist/serve/worker/client/resumable.js.map +1 -0
  309. package/dist/serve/worker/client/rtdb-references.d.ts.map +1 -1
  310. package/dist/serve/worker/client/rtdb-references.js +4 -1
  311. package/dist/serve/worker/client/rtdb-references.js.map +1 -1
  312. package/dist/serve/worker/client/storage.d.ts +16 -2
  313. package/dist/serve/worker/client/storage.d.ts.map +1 -1
  314. package/dist/serve/worker/client/storage.js +57 -6
  315. package/dist/serve/worker/client/storage.js.map +1 -1
  316. package/dist/serve/worker/host/rules.d.ts.map +1 -1
  317. package/dist/serve/worker/host/rules.js +2 -1
  318. package/dist/serve/worker/host/rules.js.map +1 -1
  319. package/dist/serve/worker/index.d.ts +1 -1
  320. package/dist/serve/worker/index.d.ts.map +1 -1
  321. package/dist/serve/worker/index.js +1 -1
  322. package/dist/serve/worker/index.js.map +1 -1
  323. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  324. package/dist/serve/worker/serve-init.js +31 -0
  325. package/dist/serve/worker/serve-init.js.map +1 -1
  326. package/package.json +15 -4
  327. package/src/assurance/.generated/conformance-verdicts.ts +80 -72
  328. package/src/bridge/client/dispatch.ts +1 -1
  329. package/src/cli/cli.test.ts +14 -0
  330. package/src/cli/database-rules.ts +6 -4
  331. package/src/cli/dev-runner.ts +21 -0
  332. package/src/cli/serve.ts +62 -5
  333. package/src/cli/verify.ts +2 -2
  334. package/src/conformance/.generated/can-i-use-browser.ts +1 -1
  335. package/src/conformance/.generated/can-i-use.ts +1 -1
  336. package/src/conformance/.generated/conformance-docs.ts +1 -1
  337. package/src/next/client-aliases.ts +39 -0
  338. package/src/next/dev-rewrites.ts +77 -0
  339. package/src/next/guard.ts +61 -0
  340. package/src/next/index.ts +16 -0
  341. package/src/next/runtime-env.ts +18 -0
  342. package/src/next/server-external-packages.ts +43 -0
  343. package/src/next/target-url.ts +46 -0
  344. package/src/next/turbopack-config.ts +54 -0
  345. package/src/next/types.ts +47 -0
  346. package/src/next/webpack-config.ts +71 -0
  347. package/src/next/with-pyric.ts +58 -0
  348. package/src/register/app-bridge.ts +79 -0
  349. package/src/register/hooks.ts +6 -1
  350. package/src/register/index.ts +1 -1
  351. package/src/register/mapping.ts +50 -4
  352. package/src/rtdb/rules-json.ts +110 -0
  353. package/src/serve/bundler.ts +2 -0
  354. package/src/serve/discovery.ts +65 -44
  355. package/src/serve/entries/app-ai-passthrough.ts +83 -0
  356. package/src/serve/entries/auth-helper-core.ts +44 -8
  357. package/src/serve/entries/auth.ts +9 -4
  358. package/src/serve/entries/bridge-url.ts +9 -2
  359. package/src/serve/entries/database.ts +1 -0
  360. package/src/serve/entries/firestore.ts +1 -0
  361. package/src/serve/entries/init.ts +5 -2
  362. package/src/serve/entries/runtime.ts +25 -0
  363. package/src/serve/entries/storage.ts +12 -1
  364. package/src/serve/html-injection.ts +26 -1
  365. package/src/serve/rules.ts +2 -2
  366. package/src/serve/runtime/chip-config.ts +19 -6
  367. package/src/serve/sandbox-session.ts +31 -2
  368. package/src/serve/vite-ai-config.ts +86 -19
  369. package/src/serve/vite-generation-rules-watch.ts +67 -15
  370. package/src/serve/vite-module-swap.ts +121 -21
  371. package/src/serve/vite-plugin.ts +44 -6
  372. package/src/serve/vite-sandbox-generation.ts +1 -1
  373. package/src/serve/worker/client/resumable.ts +506 -0
  374. package/src/serve/worker/client/rtdb-references.ts +4 -1
  375. package/src/serve/worker/client/storage.ts +77 -7
  376. package/src/serve/worker/host/rules.ts +2 -1
  377. package/src/serve/worker/index.ts +4 -0
  378. package/src/serve/worker/serve-init.ts +30 -0
  379. package/dist/serve/site-ui/_astro/_studio_.BtYpqe1A.css +0 -1
  380. package/dist/serve/site-ui/_astro/app.BnMC0ywl.js +0 -109
  381. package/dist/serve/site-ui/_astro/app.DVXXR-WI.js +0 -1
  382. package/dist/serve/site-ui/_astro/index.B4Kh80he.js +0 -1
  383. package/dist/serve/site-ui/_astro/reads.D1exkX1-.js +0 -1
  384. package/dist/serve/site-ui/_astro/sandbox-controls.BqMePr5V.js +0 -1153
@@ -23,11 +23,57 @@ const MAPPINGS: ReadonlyArray<readonly [from: string, to: string]> = [
23
23
  * Map a Firebase specifier to its pyric mirror, or return `null` when the
24
24
  * specifier is not a Firebase package (leave it for the default resolver).
25
25
  */
26
- export function mapFirebaseSpecifier(specifier: string): string | null {
27
- if (specifier === 'firebase/app') return 'pyric/app/register';
26
+ export function mapFirebaseSpecifier(
27
+ specifier: string,
28
+ importer?: string,
29
+ options?: { aiMode?: 'sandbox' | 'production' },
30
+ ): string | null {
31
+ const isShadowBridgeImporter = importer !== undefined &&
32
+ (importer.includes('app-bridge') || importer.includes('app-ai-passthrough'));
33
+ const isFirebaseAppSpecifier = specifier === 'firebase/app';
34
+ const isBypassedBridgeImport = isShadowBridgeImporter && isFirebaseAppSpecifier;
35
+ if (isBypassedBridgeImport) {
36
+ return null;
37
+ }
38
+
39
+ let mode: 'sandbox' | 'production' = 'sandbox';
40
+ const explicitMode = options?.aiMode;
41
+ const hasExplicitMode = explicitMode !== undefined;
42
+ if (hasExplicitMode) {
43
+ mode = explicitMode;
44
+ } else {
45
+ const isEnvProductionMode = process.env.PYRIC_AI_MODE === 'production';
46
+ const isEnvPassthroughFlag = process.env.PYRIC_AI_PASSTHROUGH === '1';
47
+ const isProductionEnv = isEnvProductionMode || isEnvPassthroughFlag;
48
+ if (isProductionEnv) {
49
+ mode = 'production';
50
+ }
51
+ }
52
+
53
+ const isProductionMode = mode === 'production';
54
+ const isFirebaseAiSpecifier = specifier === 'firebase/ai';
55
+ const isProductionAiPassthrough = isProductionMode && isFirebaseAiSpecifier;
56
+ if (isProductionAiPassthrough) {
57
+ return null;
58
+ }
59
+
60
+ if (isFirebaseAppSpecifier) {
61
+ if (isProductionMode) {
62
+ return '@pyric/cli/register/app-bridge';
63
+ }
64
+ return 'pyric/app/register';
65
+ }
66
+
28
67
  for (const [from, to] of MAPPINGS) {
29
- if (specifier === from) return to;
30
- if (specifier.startsWith(`${from}/`)) return to + specifier.slice(from.length);
68
+ const isExactMatch = specifier === from;
69
+ if (isExactMatch) {
70
+ return to;
71
+ }
72
+ const isSubpathMatch = specifier.startsWith(`${from}/`);
73
+ if (isSubpathMatch) {
74
+ const subpath = specifier.slice(from.length);
75
+ return to + subpath;
76
+ }
31
77
  }
32
78
  return null;
33
79
  }
@@ -27,3 +27,113 @@ export function isRtdbRulesDocument(value: unknown): value is RtdbRulesDocument
27
27
  function isRtdbRulesObject(value: unknown): value is Record<string, unknown> {
28
28
  return typeof value === 'object' && value !== null && !Array.isArray(value);
29
29
  }
30
+
31
+ /**
32
+ * Strip JavaScript-style line comments (`//...`) and block comments (`/*...*\/`)
33
+ * from JSON source text without altering string literals. Firebase Realtime
34
+ * Database security rules files (`database.rules.json`) permit comment blocks,
35
+ * requiring pre-processing before evaluation with standard JSON parsers.
36
+ */
37
+ export function stripJsonComments(text: string): string {
38
+ let result = '';
39
+ let inString = false;
40
+ let inSingleLineComment = false;
41
+ let inMultiLineComment = false;
42
+ let i = 0;
43
+
44
+ while (i < text.length) {
45
+ const char = text[i];
46
+ const nextChar = i + 1 < text.length ? text[i + 1] : '';
47
+
48
+ if (inSingleLineComment) {
49
+ const isNewline = char === '\n' || char === '\r';
50
+ if (isNewline) {
51
+ inSingleLineComment = false;
52
+ result += char;
53
+ }
54
+ i++;
55
+ continue;
56
+ }
57
+
58
+ if (inMultiLineComment) {
59
+ const isEndOfBlock = char === '*' && nextChar === '/';
60
+ if (isEndOfBlock) {
61
+ inMultiLineComment = false;
62
+ i += 2;
63
+ } else {
64
+ const isNewline = char === '\n' || char === '\r';
65
+ if (isNewline) {
66
+ result += char; // Preserve line numbering for accurate diagnostics
67
+ }
68
+ i++;
69
+ }
70
+ continue;
71
+ }
72
+
73
+ if (inString) {
74
+ const isEscape = char === '\\';
75
+ if (isEscape) {
76
+ result += char;
77
+ if (nextChar !== '') {
78
+ result += nextChar;
79
+ i++;
80
+ }
81
+ i++;
82
+ continue;
83
+ }
84
+ const isQuote = char === '"';
85
+ if (isQuote) {
86
+ inString = false;
87
+ }
88
+ result += char;
89
+ i++;
90
+ continue;
91
+ }
92
+
93
+ const isQuote = char === '"';
94
+ if (isQuote) {
95
+ inString = true;
96
+ result += char;
97
+ i++;
98
+ continue;
99
+ }
100
+
101
+ const isLineCommentStart = char === '/' && nextChar === '/';
102
+ if (isLineCommentStart) {
103
+ inSingleLineComment = true;
104
+ i += 2;
105
+ continue;
106
+ }
107
+
108
+ const isBlockCommentStart = char === '/' && nextChar === '*';
109
+ if (isBlockCommentStart) {
110
+ inMultiLineComment = true;
111
+ i += 2;
112
+ continue;
113
+ }
114
+
115
+ result += char;
116
+ i++;
117
+ }
118
+
119
+ return result;
120
+ }
121
+
122
+ /**
123
+ * Parse a JSON string that may contain line or block comments into a validated
124
+ * Realtime Database rules document structure.
125
+ */
126
+ export function parseRtdbRulesText(
127
+ text: string,
128
+ onInvalid: (error: Error) => Error,
129
+ ): RtdbRulesJson {
130
+ const clean = stripJsonComments(text);
131
+ let parsed: unknown;
132
+ try {
133
+ parsed = JSON.parse(clean);
134
+ } catch (e) {
135
+ const detail = e instanceof Error ? e.message : String(e);
136
+ throw onInvalid(new Error(`Failed to parse rules JSON: ${detail}`));
137
+ }
138
+ return parseRtdbRulesJson(parsed, () => onInvalid(new Error('Document must contain a top-level "rules" object.')));
139
+ }
@@ -57,6 +57,7 @@ export function defaultSdkEntries(): Record<string, string> {
57
57
  return {
58
58
  ai: pick('ai'),
59
59
  app: pick('app'),
60
+ 'app-ai-passthrough': pick('app-ai-passthrough'),
60
61
  auth: pick('auth'),
61
62
  firestore: pick('firestore'),
62
63
  database: pick('database'),
@@ -309,6 +310,7 @@ export async function bundleSdk(opts: BundleOptions): Promise<BundleResult> {
309
310
  sourcemap: 'linked',
310
311
  minify: opts.minify ?? true,
311
312
  logLevel: 'silent',
313
+ external: ['firebase/*'],
312
314
  // Provenance: any stack frame or "view source" into these bundles must
313
315
  // self-identify as the sandbox shim, not the real Firebase SDK.
314
316
  chunkNames: 'pyric-sandbox-[hash]',
@@ -17,16 +17,36 @@
17
17
  * first while the browser is on the other — split-brain.
18
18
  */
19
19
  import { existsSync, readFileSync } from 'node:fs';
20
- import { join } from 'node:path';
20
+ import { dirname, join, resolve } from 'node:path';
21
21
 
22
22
  /** Ports probed when the pointer is absent — serve's default scan window PLUS
23
- * the vite-plugin default (5174), which the plain 3473+ window would miss (so a
24
- * vite-only project was never found by scan). The standalone `pyric bridge`
25
- * serves `/health` (not `/__pyric/health`) and writes no pointer, so it is
26
- * registered directly via `claude mcp add`, not discovered here. */
27
- export const SCAN_PORTS = [3473, 3474, 3475, 3476, 3477, 5174];
23
+ * the standard Vite dev ports (5173-5177), which the plain 3473+ window would miss
24
+ * (so a vite-only or monorepo split-directory project is reliably found by scan).
25
+ * The standalone `pyric bridge` serves `/health` (not `/__pyric/health`) and
26
+ * writes no pointer, so it is registered directly via `claude mcp add`, not discovered here. */
27
+ export const SCAN_PORTS = [3473, 3474, 3475, 3476, 3477, 5173, 5174, 5175, 5176, 5177];
28
28
  export const POINTER = join('.pyric', 'serve.json');
29
29
 
30
+ function candidatePointerPaths(startDir: string): string[] {
31
+ const paths: string[] = [];
32
+ const seen = new Set<string>();
33
+ const subdirs = ['', 'web', 'frontend', 'client', 'app', 'ui', 'www'];
34
+ let current = resolve(startDir);
35
+ while (true) {
36
+ for (const sub of subdirs) {
37
+ const p = sub ? join(current, sub, POINTER) : join(current, POINTER);
38
+ if (!seen.has(p)) {
39
+ seen.add(p);
40
+ paths.push(p);
41
+ }
42
+ }
43
+ const parent = dirname(current);
44
+ if (parent === current) break;
45
+ current = parent;
46
+ }
47
+ return paths;
48
+ }
49
+
30
50
  export interface HealthLite {
31
51
  mode?: string;
32
52
  instanceId?: string;
@@ -141,46 +161,47 @@ export async function discoverServe(
141
161
  // real localhost ports, which a test environment can't guarantee are free.
142
162
  scanPorts: number[] = SCAN_PORTS,
143
163
  ): Promise<Discovered | null> {
144
- const pointerPath = join(cwd, POINTER);
145
- if (existsSync(pointerPath)) {
146
- try {
147
- const p = JSON.parse(readFileSync(pointerPath, 'utf8')) as {
148
- url?: string;
149
- mcpUrl?: string;
150
- port?: number;
151
- instanceId?: string;
152
- };
153
- const port = p.port ?? portOf(p.mcpUrl) ?? portOf(p.url);
154
- if (port) {
155
- const expectedId = typeof p.instanceId === 'string' && p.instanceId ? p.instanceId : null;
156
- const hit = await healthyBase(port, expectedId);
157
- if (hit) {
158
- return {
159
- mcpUrl: `${hit.base}/__pyric/mcp`,
160
- url: canonicalServeUrl(port, p.url),
161
- base: hit.base,
162
- instanceId: hit.instanceId,
163
- source: `pointer ${POINTER}`,
164
- };
165
- }
166
- // The pointer named a specific identity we could NOT find on its port:
167
- // a different sandbox may be squatting it (cross-family collision) or
168
- // the server stopped. Do NOT scan into a possibly-wrong server — that
169
- // split-brain is exactly what this identity check prevents. Fail legibly.
170
- if (expectedId) {
171
- log(
172
- `pointer ${POINTER} names a server (instanceId ${expectedId.slice(0, 8)}…) ` +
173
- `that isn't answering on port ${port} — another sandbox may be squatting the ` +
174
- `port on the other loopback family, or the server stopped. Not falling back to ` +
175
- `a blind port scan (it could hit the wrong sandbox). Restart your dev server, ` +
176
- `and open the exact URL it prints (http://localhost:<port> by default) — every ` +
177
- `page must share that ONE origin, or the browser splits into separate sandboxes.`,
178
- );
179
- return null;
164
+ for (const pointerPath of candidatePointerPaths(cwd)) {
165
+ if (existsSync(pointerPath)) {
166
+ try {
167
+ const p = JSON.parse(readFileSync(pointerPath, 'utf8')) as {
168
+ url?: string;
169
+ mcpUrl?: string;
170
+ port?: number;
171
+ instanceId?: string;
172
+ };
173
+ const port = p.port ?? portOf(p.mcpUrl) ?? portOf(p.url);
174
+ if (port) {
175
+ const expectedId = typeof p.instanceId === 'string' && p.instanceId ? p.instanceId : null;
176
+ const hit = await healthyBase(port, expectedId);
177
+ if (hit) {
178
+ return {
179
+ mcpUrl: `${hit.base}/__pyric/mcp`,
180
+ url: canonicalServeUrl(port, p.url),
181
+ base: hit.base,
182
+ instanceId: hit.instanceId,
183
+ source: `pointer ${pointerPath}`,
184
+ };
185
+ }
186
+ // The pointer named a specific identity we could NOT find on its port:
187
+ // a different sandbox may be squatting it (cross-family collision) or
188
+ // the server stopped. Do NOT scan into a possibly-wrong server — that
189
+ // split-brain is exactly what this identity check prevents. Fail legibly.
190
+ if (expectedId) {
191
+ log(
192
+ `pointer ${pointerPath} names a server (instanceId ${expectedId.slice(0, 8)}…) ` +
193
+ `that isn't answering on port ${port} — another sandbox may be squatting the ` +
194
+ `port on the other loopback family, or the server stopped. Not falling back to ` +
195
+ `a blind port scan (it could hit the wrong sandbox). Restart your dev server, ` +
196
+ `and open the exact URL it prints (http://localhost:<port> by default) — every ` +
197
+ `page must share that ONE origin, or the browser splits into separate sandboxes.`,
198
+ );
199
+ return null;
200
+ }
180
201
  }
202
+ } catch {
203
+ /* stale/corrupt pointer — fall through to next candidate */
181
204
  }
182
- } catch {
183
- /* stale/corrupt pointer — fall through to scan */
184
205
  }
185
206
  }
186
207
  for (const port of scanPorts) {
@@ -0,0 +1,83 @@
1
+ /** Served `firebase/app`: Pyric client registry with shadow container bridge for production AI pass-through. */
2
+ import { bindAppRegistrySandbox } from 'pyric/app/internal';
3
+ import { sandbox } from './app-backend.js';
4
+ import * as pyricApp from 'pyric/app';
5
+ import * as realApp from 'firebase/app';
6
+
7
+ bindAppRegistrySandbox(sandbox);
8
+
9
+ function decorateApp(
10
+ app: pyricApp.FirebaseApp,
11
+ options?: pyricApp.FirebaseOptions,
12
+ rawSettings?: string | pyricApp.FirebaseAppSettings,
13
+ ): pyricApp.FirebaseApp {
14
+ try {
15
+ let shadow: { container?: unknown };
16
+ try {
17
+ shadow = realApp.getApp(app.name) as { container?: unknown };
18
+ } catch {
19
+ const initOptions = (options ?? app.options) as realApp.FirebaseOptions;
20
+ const initSettings = rawSettings ?? app.name;
21
+ const isStringSettings = typeof initSettings === 'string';
22
+ if (isStringSettings) {
23
+ shadow = realApp.initializeApp(initOptions, initSettings) as { container?: unknown };
24
+ } else {
25
+ const objectSettings = initSettings as realApp.FirebaseAppSettings;
26
+ shadow = realApp.initializeApp(initOptions, objectSettings) as { container?: unknown };
27
+ }
28
+ }
29
+ const hasShadowContainer = shadow.container !== undefined && shadow.container !== null;
30
+ if (hasShadowContainer) {
31
+ Object.defineProperty(app, 'container', { value: shadow.container, configurable: true });
32
+ }
33
+ } catch {
34
+ // Observational/best-effort: do not break Pyric initialization if shadow initialization fails.
35
+ }
36
+ return app;
37
+ }
38
+
39
+ export function initializeApp(
40
+ options?: pyricApp.FirebaseOptions,
41
+ rawSettings?: string | pyricApp.FirebaseAppSettings,
42
+ ): pyricApp.FirebaseApp {
43
+ const app = pyricApp.initializeApp(options, rawSettings);
44
+ return decorateApp(app, options, rawSettings);
45
+ }
46
+
47
+ export function getApp(name?: string): pyricApp.FirebaseApp {
48
+ return decorateApp(pyricApp.getApp(name));
49
+ }
50
+
51
+ export function getApps(): pyricApp.FirebaseApp[] {
52
+ return pyricApp.getApps().map((app) => decorateApp(app));
53
+ }
54
+
55
+ export async function deleteApp(app: pyricApp.FirebaseApp): Promise<void> {
56
+ try {
57
+ const shadow = realApp.getApp(app.name);
58
+ const hasShadow = shadow !== undefined && shadow !== null;
59
+ if (hasShadow) {
60
+ await realApp.deleteApp(shadow);
61
+ }
62
+ } catch {
63
+ // Ignore if shadow app was not initialized or already deleted.
64
+ }
65
+ return pyricApp.deleteApp(app);
66
+ }
67
+
68
+ export {
69
+ FirebaseError,
70
+ SDK_VERSION,
71
+ onLog,
72
+ registerVersion,
73
+ setLogLevel,
74
+ } from 'pyric/app';
75
+ export type {
76
+ FirebaseApp,
77
+ FirebaseAppSettings,
78
+ FirebaseOptions,
79
+ LogCallback,
80
+ LogEntry,
81
+ LogLevel,
82
+ LogOptions,
83
+ } from 'pyric/app';
@@ -175,8 +175,16 @@ export class ServeAuthHelper {
175
175
  if (request.kind === 'pick') {
176
176
  return bareCredential(request.identity, request.providerId);
177
177
  }
178
+ // Same-email add resolves to the existing identity (Google-style account
179
+ // reuse) — mirrors `createSignInCredential`'s in-page policy, and keeps a
180
+ // repeated add idempotent instead of seeding a second account whose email
181
+ // mapping orphans the first.
182
+ const existing = this.findIdentityByEmail(request.spec.email);
183
+ if (existing) {
184
+ return bareCredential(existing, request.providerId);
185
+ }
178
186
  const identity: HelperIdentity = {
179
- uid: `${request.providerId}:${request.spec.email}`,
187
+ uid: mintProviderUid(),
180
188
  email: request.spec.email,
181
189
  displayName: request.spec.displayName ?? null,
182
190
  customClaims: request.spec.customClaims ?? {},
@@ -184,12 +192,44 @@ export class ServeAuthHelper {
184
192
  await Promise.resolve(this.directory.add?.(identity));
185
193
  return bareCredential(identity, request.providerId);
186
194
  }
195
+
196
+ private findIdentityByEmail(email: string): HelperIdentity | undefined {
197
+ const normalized = email.toLowerCase();
198
+ return this.identities.find(
199
+ (identity) => identity.email?.toLowerCase() === normalized,
200
+ );
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Recover the original custom claims from a helper credential's token claims.
206
+ * `bareCredential` (and the in-page backend mint) seed `sub` and the
207
+ * synthesized `firebase` envelope alongside the custom claims; neither is a
208
+ * custom claim, and seeding them back into the worker would persist
209
+ * synthesized metadata as user data.
210
+ */
211
+ export function customClaimsFromTokenClaims(
212
+ claims: Record<string, unknown>,
213
+ ): Record<string, unknown> {
214
+ const { sub: _sub, firebase: _firebase, ...customClaims } = claims;
215
+ return customClaims;
216
+ }
217
+
218
+ /** Provider UIDs are opaque Firebase identifiers, not encoded credentials. */
219
+ function mintProviderUid(): string {
220
+ return `provider-${globalThis.crypto.randomUUID()}`;
187
221
  }
188
222
 
189
223
  /** Bare helper User — worker path discards this in favor of `acceptIdentity`. */
190
224
  function bareCredential(identity: HelperIdentity, providerId: string): UserCredential {
191
225
  const issuedAtTime = new Date().toISOString();
192
226
  const expirationTime = new Date(Date.now() + 3600_000).toISOString();
227
+ const claims: Record<string, unknown> = {
228
+ sub: identity.uid,
229
+ ...identity.customClaims,
230
+ firebase: { sign_in_provider: providerId },
231
+ };
232
+ const token = `sandbox-id-token-${identity.uid}-0:${JSON.stringify(claims)}`;
193
233
  const user: User = {
194
234
  uid: identity.uid,
195
235
  email: identity.email,
@@ -209,14 +249,10 @@ function bareCredential(identity: HelperIdentity, providerId: string): UserCrede
209
249
  providerId,
210
250
  },
211
251
  ],
212
- getIdToken: async () => `pyric-serve-${identity.uid}`,
252
+ getIdToken: async () => token,
213
253
  getIdTokenResult: async () => ({
214
- token: `pyric-serve-${identity.uid}`,
215
- claims: {
216
- sub: identity.uid,
217
- ...identity.customClaims,
218
- firebase: { sign_in_provider: providerId },
219
- },
254
+ token,
255
+ claims,
220
256
  signInProvider: providerId,
221
257
  expirationTime,
222
258
  issuedAtTime,
@@ -13,12 +13,14 @@
13
13
  * in or seeds a user. Email/password + anonymous also go straight to the
14
14
  * worker. The COMPLETE surface is exported on both paths (import-time parity).
15
15
  */
16
+ import './init.js';
16
17
  import * as ipAuth from 'pyric/auth';
17
18
  import { getAuth as pyricGetAuth, setPersistence as pyricSetPersistence } from 'pyric/auth';
18
19
  import * as wcRaw from '../worker/client.js';
19
20
  import { acceptProviderCredential, restorePortSession } from '../worker/client.js';
20
21
  import { useWorker } from './worker-runtime.js';
21
22
  import { sessionStoreForApp } from './app-session-store.js';
23
+ import { customClaimsFromTokenClaims } from './auth-helper-core.js';
22
24
  import { resolveServeAuthFlow } from './auth-helper-runtime.js';
23
25
  import type { SessionMode } from './session-store.js';
24
26
  import { getApp, type FirebaseApp } from 'pyric/app';
@@ -153,9 +155,10 @@ export const setPersistence = (
153
155
 
154
156
  /**
155
157
  * Resolve a provider identity through the backend-free ServeAuthHelper, then
156
- * hand it to the worker. The
157
- * helper seeds `{ sub, ...claims }` into the resolved credential's token, so we
158
- * strip `sub` to recover the original custom claims for the worker seed.
158
+ * hand it to the worker. The helper seeds `{ sub, ...claims, firebase }` into
159
+ * the resolved credential's token, so we strip the synthesized `sub` and
160
+ * `firebase` entries to recover the original custom claims for the worker
161
+ * seed (see `customClaimsFromTokenClaims`).
159
162
  *
160
163
  * Enforcement lives at the hand-off: `auth.acceptIdentity` gates against the
161
164
  * WORKER's provider config and rejects `auth/operation-not-allowed` for a
@@ -173,7 +176,9 @@ async function bridgeProviderSignIn(
173
176
  kind,
174
177
  );
175
178
  const tokenResult = await cred.user.getIdTokenResult();
176
- const { sub: _sub, ...customClaims } = (tokenResult.claims ?? {}) as Record<string, unknown>;
179
+ const customClaims = customClaimsFromTokenClaims(
180
+ (tokenResult.claims ?? {}) as Record<string, unknown>,
181
+ );
177
182
  return acceptProviderCredential(auth as never, {
178
183
  uid: cred.user.uid,
179
184
  email: cred.user.email,
@@ -22,9 +22,16 @@ export function toPageOriginWsUrl(
22
22
  loc: { href: string; protocol: string; host: string },
23
23
  ): string {
24
24
  try {
25
- const path = new URL(raw, loc.href).pathname;
25
+ const rawUrl = new URL(raw, loc.href);
26
+ const locUrl = new URL(loc.href);
26
27
  const scheme = loc.protocol === 'https:' ? 'wss:' : 'ws:';
27
- return `${scheme}//${loc.host}${path}`;
28
+
29
+ const hasExplicitLocPort = locUrl.port.length > 0;
30
+ const hasExplicitRawPort = rawUrl.port.length > 0;
31
+ const shouldPreserveRawPort = hasExplicitLocPort && hasExplicitRawPort;
32
+ const hostTarget = shouldPreserveRawPort ? `${locUrl.hostname}:${rawUrl.port}` : locUrl.host;
33
+
34
+ return `${scheme}//${hostTarget}${rawUrl.pathname}`;
28
35
  } catch {
29
36
  return raw;
30
37
  }
@@ -5,6 +5,7 @@
5
5
  * and the Playground. This entry gives served apps the same common modular SDK
6
6
  * surface while the in-page fallback delegates to `pyric/database`.
7
7
  */
8
+ import './init.js';
8
9
  import * as ip from 'pyric/database';
9
10
  import { getDatabase as pyricGetDatabase } from 'pyric/database';
10
11
  import { queryIdentifier } from 'pyric/database/internal';
@@ -13,6 +13,7 @@
13
13
  *
14
14
  * Browser-bundled by `../bundler.ts`; never imported by node-side code.
15
15
  */
16
+ import './init.js';
16
17
  import * as ip from 'pyric/firestore';
17
18
  import { getFirestore as pyricGetFirestore } from 'pyric/firestore';
18
19
  import * as wcRaw from '../worker/client.js';
@@ -53,7 +53,10 @@ const helper = workerAuth
53
53
  const resolver = helper.resolver();
54
54
  installServeAuthResolver(resolver);
55
55
  if (localAuth) authSandbox.setAuthFlowResolver(localAuth, resolver);
56
- mountAuthHelperDialog(helper);
57
- installPyricRuntimeChip({ runtime: getPyricRuntimeStatus(), document });
56
+
57
+ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
58
+ mountAuthHelperDialog(helper);
59
+ installPyricRuntimeChip({ runtime: getPyricRuntimeStatus(), document });
60
+ }
58
61
 
59
62
  export {};
@@ -553,4 +553,29 @@ if (!useWorker && typeof EventSource !== 'undefined') {
553
553
  console.error('[pyric dev] rules hot-reload failed:', err instanceof Error ? err.message : String(err));
554
554
  }
555
555
  });
556
+ events.addEventListener('rtdb-rules-update', (e) => {
557
+ try {
558
+ const { rules, rulesHash } = JSON.parse((e as MessageEvent).data as string) as {
559
+ rules: { rules: Record<string, unknown> };
560
+ rulesHash: string;
561
+ };
562
+ rtdbSandbox.setRules(getDatabase(sandbox), rules);
563
+ diagnostics.databaseRulesDeployed = true;
564
+ let newHash: string | null = null;
565
+ const isHashDefined = rulesHash !== undefined;
566
+ if (isHashDefined) {
567
+ newHash = rulesHash;
568
+ }
569
+ diagnostics.databaseRulesHash = newHash;
570
+ console.info(`[pyric dev] database.rules.json hot-reloaded (hash ${rulesHash})`);
571
+ } catch (err) {
572
+ runtimeStatus.reportError(err, 'runtime');
573
+ const isErrorInstance = err instanceof Error;
574
+ let errorMessage = String(err);
575
+ if (isErrorInstance) {
576
+ errorMessage = (err as Error).message;
577
+ }
578
+ console.error('[pyric dev] database rules hot-reload failed:', errorMessage);
579
+ }
580
+ });
556
581
  }
@@ -6,6 +6,7 @@
6
6
  * still lack a worker protocol fail loudly. In in-page fallback mode, the entry
7
7
  * delegates to `pyric/storage` against the page sandbox.
8
8
  */
9
+ import './init.js';
9
10
  import * as ip from 'pyric/storage';
10
11
  import {
11
12
  getStorage as pyricGetStorage,
@@ -20,6 +21,8 @@ import {
20
21
  listAll as workerListAll,
21
22
  ref as workerRef,
22
23
  uploadBytes as workerUploadBytes,
24
+ uploadString as workerUploadString,
25
+ uploadBytesResumable as workerUploadBytesResumable,
23
26
  deleteObject as workerDeleteObject,
24
27
  } from '../worker/client.js';
25
28
  import { useWorker } from './worker-runtime.js';
@@ -85,8 +88,16 @@ function workerOrInPage<T extends (...args: any[]) => unknown>(name: string, fn:
85
88
  // ruleset; only their active Auth sessions differ. Payloads are capped at
86
89
  // 8 MiB per op.
87
90
  export const uploadBytes = (useWorker ? workerUploadBytes : ip.uploadBytes) as typeof ip.uploadBytes;
91
+
92
+ let selectedUploadBytesResumable = ip.uploadBytesResumable;
93
+ const isWorkerMode = useWorker === true;
94
+ if (isWorkerMode) {
95
+ selectedUploadBytesResumable = workerUploadBytesResumable as unknown as typeof ip.uploadBytesResumable;
96
+ }
97
+ export const uploadBytesResumable = selectedUploadBytesResumable;
98
+
88
99
  export const getBytes = (useWorker ? workerGetBytes : ip.getBytes) as typeof ip.getBytes;
89
100
  export const deleteObject = (useWorker ? workerDeleteObject : ip.deleteObject) as typeof ip.deleteObject;
90
101
 
91
- export const uploadString = workerOrInPage('uploadString', ip.uploadString);
102
+ export const uploadString = (useWorker ? workerUploadString : ip.uploadString) as typeof ip.uploadString;
92
103
  export const updateMetadata = workerOrInPage('updateMetadata', ip.updateMetadata);