pyric 0.0.1 → 0.1.0-alpha.7

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 (786) hide show
  1. package/README.md +52 -1
  2. package/dist/app/index.d.ts +81 -0
  3. package/dist/app/index.d.ts.map +1 -0
  4. package/dist/app/index.js +78 -0
  5. package/dist/app/index.js.map +1 -0
  6. package/dist/auth/index.d.ts +346 -0
  7. package/dist/auth/index.d.ts.map +1 -0
  8. package/dist/auth/index.js +701 -0
  9. package/dist/auth/index.js.map +1 -0
  10. package/dist/auth/prod-backend.d.ts +39 -0
  11. package/dist/auth/prod-backend.d.ts.map +1 -0
  12. package/dist/auth/prod-backend.js +179 -0
  13. package/dist/auth/prod-backend.js.map +1 -0
  14. package/dist/auth/providers.d.ts +107 -0
  15. package/dist/auth/providers.d.ts.map +1 -0
  16. package/dist/auth/providers.js +138 -0
  17. package/dist/auth/providers.js.map +1 -0
  18. package/dist/auth/sandbox-backend.d.ts +769 -0
  19. package/dist/auth/sandbox-backend.d.ts.map +1 -0
  20. package/dist/auth/sandbox-backend.js +1598 -0
  21. package/dist/auth/sandbox-backend.js.map +1 -0
  22. package/dist/auth/target.d.ts +40 -0
  23. package/dist/auth/target.d.ts.map +1 -0
  24. package/dist/auth/target.js +28 -0
  25. package/dist/auth/target.js.map +1 -0
  26. package/dist/auth/types.d.ts +252 -0
  27. package/dist/auth/types.d.ts.map +1 -0
  28. package/dist/auth/types.js +26 -0
  29. package/dist/auth/types.js.map +1 -0
  30. package/dist/database/constraints/atoms.d.ts +29 -0
  31. package/dist/database/constraints/atoms.d.ts.map +1 -0
  32. package/dist/database/constraints/atoms.js +43 -0
  33. package/dist/database/constraints/atoms.js.map +1 -0
  34. package/dist/database/constraints/compose.d.ts +16 -0
  35. package/dist/database/constraints/compose.d.ts.map +1 -0
  36. package/dist/database/constraints/compose.js +15 -0
  37. package/dist/database/constraints/compose.js.map +1 -0
  38. package/dist/database/constraints/data.d.ts +30 -0
  39. package/dist/database/constraints/data.d.ts.map +1 -0
  40. package/dist/database/constraints/data.js +46 -0
  41. package/dist/database/constraints/data.js.map +1 -0
  42. package/dist/database/constraints/document.d.ts +42 -0
  43. package/dist/database/constraints/document.d.ts.map +1 -0
  44. package/dist/database/constraints/document.js +86 -0
  45. package/dist/database/constraints/document.js.map +1 -0
  46. package/dist/database/constraints/game.d.ts +30 -0
  47. package/dist/database/constraints/game.d.ts.map +1 -0
  48. package/dist/database/constraints/game.js +49 -0
  49. package/dist/database/constraints/game.js.map +1 -0
  50. package/dist/database/constraints/index.d.ts +12 -0
  51. package/dist/database/constraints/index.d.ts.map +1 -0
  52. package/dist/database/constraints/index.js +9 -0
  53. package/dist/database/constraints/index.js.map +1 -0
  54. package/dist/database/constraints/policies.d.ts +16 -0
  55. package/dist/database/constraints/policies.d.ts.map +1 -0
  56. package/dist/database/constraints/policies.js +17 -0
  57. package/dist/database/constraints/policies.js.map +1 -0
  58. package/dist/database/constraints/ruleset.d.ts +5 -0
  59. package/dist/database/constraints/ruleset.d.ts.map +1 -0
  60. package/dist/database/constraints/ruleset.js +132 -0
  61. package/dist/database/constraints/ruleset.js.map +1 -0
  62. package/dist/database/constraints/schema.d.ts +17 -0
  63. package/dist/database/constraints/schema.d.ts.map +1 -0
  64. package/dist/database/constraints/schema.js +74 -0
  65. package/dist/database/constraints/schema.js.map +1 -0
  66. package/dist/database/constraints/types.d.ts +22 -0
  67. package/dist/database/constraints/types.d.ts.map +1 -0
  68. package/dist/database/constraints/types.js +2 -0
  69. package/dist/database/constraints/types.js.map +1 -0
  70. package/dist/database/crawl/handler.d.ts +7 -0
  71. package/dist/database/crawl/handler.d.ts.map +1 -0
  72. package/dist/database/crawl/handler.js +91 -0
  73. package/dist/database/crawl/handler.js.map +1 -0
  74. package/dist/database/crawl/semaphore.d.ts +9 -0
  75. package/dist/database/crawl/semaphore.d.ts.map +1 -0
  76. package/dist/database/crawl/semaphore.js +27 -0
  77. package/dist/database/crawl/semaphore.js.map +1 -0
  78. package/dist/database/crawl/spec.d.ts +33 -0
  79. package/dist/database/crawl/spec.d.ts.map +1 -0
  80. package/dist/database/crawl/spec.js +12 -0
  81. package/dist/database/crawl/spec.js.map +1 -0
  82. package/dist/database/data/handler.d.ts +9 -0
  83. package/dist/database/data/handler.d.ts.map +1 -0
  84. package/dist/database/data/handler.js +96 -0
  85. package/dist/database/data/handler.js.map +1 -0
  86. package/dist/database/data/spec.d.ts +77 -0
  87. package/dist/database/data/spec.d.ts.map +1 -0
  88. package/dist/database/data/spec.js +17 -0
  89. package/dist/database/data/spec.js.map +1 -0
  90. package/dist/database/data/validated.d.ts +8 -0
  91. package/dist/database/data/validated.d.ts.map +1 -0
  92. package/dist/database/data/validated.js +99 -0
  93. package/dist/database/data/validated.js.map +1 -0
  94. package/dist/database/grammar/RtdbExpr.ohm +98 -0
  95. package/dist/database/grammar/RtdbExpr.ohm.generated.d.ts +2 -0
  96. package/dist/database/grammar/RtdbExpr.ohm.generated.d.ts.map +1 -0
  97. package/dist/database/grammar/RtdbExpr.ohm.generated.js +103 -0
  98. package/dist/database/grammar/RtdbExpr.ohm.generated.js.map +1 -0
  99. package/dist/database/grammar/RtdbExprParser.d.ts +5 -0
  100. package/dist/database/grammar/RtdbExprParser.d.ts.map +1 -0
  101. package/dist/database/grammar/RtdbExprParser.js +53 -0
  102. package/dist/database/grammar/RtdbExprParser.js.map +1 -0
  103. package/dist/database/grammar/linter.d.ts +3 -0
  104. package/dist/database/grammar/linter.d.ts.map +1 -0
  105. package/dist/database/grammar/linter.js +66 -0
  106. package/dist/database/grammar/linter.js.map +1 -0
  107. package/dist/database/grammar/simulator.d.ts +31 -0
  108. package/dist/database/grammar/simulator.d.ts.map +1 -0
  109. package/dist/database/grammar/simulator.js +255 -0
  110. package/dist/database/grammar/simulator.js.map +1 -0
  111. package/dist/database/grammar/validator.d.ts +3 -0
  112. package/dist/database/grammar/validator.d.ts.map +1 -0
  113. package/dist/database/grammar/validator.js +84 -0
  114. package/dist/database/grammar/validator.js.map +1 -0
  115. package/dist/database/host.d.ts +50 -0
  116. package/dist/database/host.d.ts.map +1 -0
  117. package/dist/database/host.js +41 -0
  118. package/dist/database/host.js.map +1 -0
  119. package/dist/database/index.d.ts +40 -0
  120. package/dist/database/index.d.ts.map +1 -0
  121. package/dist/database/index.js +47 -0
  122. package/dist/database/index.js.map +1 -0
  123. package/dist/database/initialize-from-app.d.ts +28 -0
  124. package/dist/database/initialize-from-app.d.ts.map +1 -0
  125. package/dist/database/initialize-from-app.js +23 -0
  126. package/dist/database/initialize-from-app.js.map +1 -0
  127. package/dist/database/ir/handler.d.ts +6 -0
  128. package/dist/database/ir/handler.d.ts.map +1 -0
  129. package/dist/database/ir/handler.js +52 -0
  130. package/dist/database/ir/handler.js.map +1 -0
  131. package/dist/database/ir/spec.d.ts +25 -0
  132. package/dist/database/ir/spec.d.ts.map +1 -0
  133. package/dist/database/ir/spec.js +11 -0
  134. package/dist/database/ir/spec.js.map +1 -0
  135. package/dist/database/mapper.d.ts +9 -0
  136. package/dist/database/mapper.d.ts.map +1 -0
  137. package/dist/database/mapper.js +115 -0
  138. package/dist/database/mapper.js.map +1 -0
  139. package/dist/database/modular.d.ts +604 -0
  140. package/dist/database/modular.d.ts.map +1 -0
  141. package/dist/database/modular.js +1226 -0
  142. package/dist/database/modular.js.map +1 -0
  143. package/dist/database/replay.d.ts +33 -0
  144. package/dist/database/replay.d.ts.map +1 -0
  145. package/dist/database/replay.js +124 -0
  146. package/dist/database/replay.js.map +1 -0
  147. package/dist/database/resolver.d.ts +4 -0
  148. package/dist/database/resolver.d.ts.map +1 -0
  149. package/dist/database/resolver.js +66 -0
  150. package/dist/database/resolver.js.map +1 -0
  151. package/dist/database/sandbox/backend.d.ts +403 -0
  152. package/dist/database/sandbox/backend.d.ts.map +1 -0
  153. package/dist/database/sandbox/backend.js +1467 -0
  154. package/dist/database/sandbox/backend.js.map +1 -0
  155. package/dist/database/sandbox/data-tree.d.ts +123 -0
  156. package/dist/database/sandbox/data-tree.d.ts.map +1 -0
  157. package/dist/database/sandbox/data-tree.js +310 -0
  158. package/dist/database/sandbox/data-tree.js.map +1 -0
  159. package/dist/database/sandbox/normalize.d.ts +77 -0
  160. package/dist/database/sandbox/normalize.d.ts.map +1 -0
  161. package/dist/database/sandbox/normalize.js +165 -0
  162. package/dist/database/sandbox/normalize.js.map +1 -0
  163. package/dist/database/sandbox/push-id.d.ts +32 -0
  164. package/dist/database/sandbox/push-id.d.ts.map +1 -0
  165. package/dist/database/sandbox/push-id.js +82 -0
  166. package/dist/database/sandbox/push-id.js.map +1 -0
  167. package/dist/database/sandbox/query.d.ts +175 -0
  168. package/dist/database/sandbox/query.d.ts.map +1 -0
  169. package/dist/database/sandbox/query.js +269 -0
  170. package/dist/database/sandbox/query.js.map +1 -0
  171. package/dist/database/sandbox/rules-eval.d.ts +69 -0
  172. package/dist/database/sandbox/rules-eval.d.ts.map +1 -0
  173. package/dist/database/sandbox/rules-eval.js +124 -0
  174. package/dist/database/sandbox/rules-eval.js.map +1 -0
  175. package/dist/database/sandbox/sentinels.d.ts +71 -0
  176. package/dist/database/sandbox/sentinels.d.ts.map +1 -0
  177. package/dist/database/sandbox/sentinels.js +92 -0
  178. package/dist/database/sandbox/sentinels.js.map +1 -0
  179. package/dist/database/simulation/handler.d.ts +6 -0
  180. package/dist/database/simulation/handler.d.ts.map +1 -0
  181. package/dist/database/simulation/handler.js +236 -0
  182. package/dist/database/simulation/handler.js.map +1 -0
  183. package/dist/database/simulation/spec.d.ts +69 -0
  184. package/dist/database/simulation/spec.d.ts.map +1 -0
  185. package/dist/database/simulation/spec.js +25 -0
  186. package/dist/database/simulation/spec.js.map +1 -0
  187. package/dist/database/tools.d.ts +22 -0
  188. package/dist/database/tools.d.ts.map +1 -0
  189. package/dist/database/tools.js +272 -0
  190. package/dist/database/tools.js.map +1 -0
  191. package/dist/database/types.d.ts +210 -0
  192. package/dist/database/types.d.ts.map +1 -0
  193. package/dist/database/types.js +26 -0
  194. package/dist/database/types.js.map +1 -0
  195. package/dist/database/write/handler.d.ts +7 -0
  196. package/dist/database/write/handler.d.ts.map +1 -0
  197. package/dist/database/write/handler.js +42 -0
  198. package/dist/database/write/handler.js.map +1 -0
  199. package/dist/database/write/spec.d.ts +18 -0
  200. package/dist/database/write/spec.d.ts.map +1 -0
  201. package/dist/database/write/spec.js +7 -0
  202. package/dist/database/write/spec.js.map +1 -0
  203. package/dist/firestore/index.d.ts +533 -0
  204. package/dist/firestore/index.d.ts.map +1 -0
  205. package/dist/firestore/index.js +1536 -0
  206. package/dist/firestore/index.js.map +1 -0
  207. package/dist/firestore/tools.d.ts +67 -0
  208. package/dist/firestore/tools.d.ts.map +1 -0
  209. package/dist/firestore/tools.js +318 -0
  210. package/dist/firestore/tools.js.map +1 -0
  211. package/dist/firestore-values/index.d.ts +63 -0
  212. package/dist/firestore-values/index.d.ts.map +1 -0
  213. package/dist/firestore-values/index.js +148 -0
  214. package/dist/firestore-values/index.js.map +1 -0
  215. package/dist/project-scope.d.ts +5 -0
  216. package/dist/project-scope.d.ts.map +1 -0
  217. package/dist/project-scope.js +2 -0
  218. package/dist/project-scope.js.map +1 -0
  219. package/dist/rules/extract.d.ts +28 -0
  220. package/dist/rules/extract.d.ts.map +1 -0
  221. package/dist/rules/extract.js +25 -0
  222. package/dist/rules/extract.js.map +1 -0
  223. package/dist/rules/generators/assembler.d.ts +19 -0
  224. package/dist/rules/generators/assembler.d.ts.map +1 -0
  225. package/dist/rules/generators/assembler.js +292 -0
  226. package/dist/rules/generators/assembler.js.map +1 -0
  227. package/dist/rules/generators/expressions.d.ts +52 -0
  228. package/dist/rules/generators/expressions.d.ts.map +1 -0
  229. package/dist/rules/generators/expressions.js +117 -0
  230. package/dist/rules/generators/expressions.js.map +1 -0
  231. package/dist/rules/generators/grid.d.ts +22 -0
  232. package/dist/rules/generators/grid.d.ts.map +1 -0
  233. package/dist/rules/generators/grid.js +52 -0
  234. package/dist/rules/generators/grid.js.map +1 -0
  235. package/dist/rules/grammar/FirestoreAST.d.ts +129 -0
  236. package/dist/rules/grammar/FirestoreAST.d.ts.map +1 -0
  237. package/dist/rules/grammar/FirestoreAST.js +3 -0
  238. package/dist/rules/grammar/FirestoreAST.js.map +1 -0
  239. package/dist/rules/grammar/FirestoreAssembler.d.ts +5 -0
  240. package/dist/rules/grammar/FirestoreAssembler.d.ts.map +1 -0
  241. package/dist/rules/grammar/FirestoreAssembler.js +158 -0
  242. package/dist/rules/grammar/FirestoreAssembler.js.map +1 -0
  243. package/dist/rules/grammar/FirestoreParser.d.ts +46 -0
  244. package/dist/rules/grammar/FirestoreParser.d.ts.map +1 -0
  245. package/dist/rules/grammar/FirestoreParser.js +409 -0
  246. package/dist/rules/grammar/FirestoreParser.js.map +1 -0
  247. package/dist/rules/grammar/FirestoreRules.ohm +229 -0
  248. package/dist/rules/grammar/FirestoreRules.ohm.generated.d.ts +2 -0
  249. package/dist/rules/grammar/FirestoreRules.ohm.generated.d.ts.map +1 -0
  250. package/dist/rules/grammar/FirestoreRules.ohm.generated.js +234 -0
  251. package/dist/rules/grammar/FirestoreRules.ohm.generated.js.map +1 -0
  252. package/dist/rules/grammar/FirestoreValidator.d.ts +10 -0
  253. package/dist/rules/grammar/FirestoreValidator.d.ts.map +1 -0
  254. package/dist/rules/grammar/FirestoreValidator.js +482 -0
  255. package/dist/rules/grammar/FirestoreValidator.js.map +1 -0
  256. package/dist/rules/index.d.ts +67 -0
  257. package/dist/rules/index.d.ts.map +1 -0
  258. package/dist/rules/index.js +80 -0
  259. package/dist/rules/index.js.map +1 -0
  260. package/dist/rules/indexes/extract/annotation-collect.d.ts +42 -0
  261. package/dist/rules/indexes/extract/annotation-collect.d.ts.map +1 -0
  262. package/dist/rules/indexes/extract/annotation-collect.js +69 -0
  263. package/dist/rules/indexes/extract/annotation-collect.js.map +1 -0
  264. package/dist/rules/indexes/extract/annotations.d.ts +50 -0
  265. package/dist/rules/indexes/extract/annotations.d.ts.map +1 -0
  266. package/dist/rules/indexes/extract/annotations.js +144 -0
  267. package/dist/rules/indexes/extract/annotations.js.map +1 -0
  268. package/dist/rules/indexes/extract/ast.d.ts +54 -0
  269. package/dist/rules/indexes/extract/ast.d.ts.map +1 -0
  270. package/dist/rules/indexes/extract/ast.js +119 -0
  271. package/dist/rules/indexes/extract/ast.js.map +1 -0
  272. package/dist/rules/indexes/extract/classify.d.ts +41 -0
  273. package/dist/rules/indexes/extract/classify.d.ts.map +1 -0
  274. package/dist/rules/indexes/extract/classify.js +138 -0
  275. package/dist/rules/indexes/extract/classify.js.map +1 -0
  276. package/dist/rules/indexes/extract/composite.d.ts +38 -0
  277. package/dist/rules/indexes/extract/composite.d.ts.map +1 -0
  278. package/dist/rules/indexes/extract/composite.js +85 -0
  279. package/dist/rules/indexes/extract/composite.js.map +1 -0
  280. package/dist/rules/indexes/extract/dataflow.d.ts +45 -0
  281. package/dist/rules/indexes/extract/dataflow.d.ts.map +1 -0
  282. package/dist/rules/indexes/extract/dataflow.js +200 -0
  283. package/dist/rules/indexes/extract/dataflow.js.map +1 -0
  284. package/dist/rules/indexes/extract/enumerate.d.ts +41 -0
  285. package/dist/rules/indexes/extract/enumerate.d.ts.map +1 -0
  286. package/dist/rules/indexes/extract/enumerate.js +163 -0
  287. package/dist/rules/indexes/extract/enumerate.js.map +1 -0
  288. package/dist/rules/indexes/extract/extractor.d.ts +3 -0
  289. package/dist/rules/indexes/extract/extractor.d.ts.map +1 -0
  290. package/dist/rules/indexes/extract/extractor.js +274 -0
  291. package/dist/rules/indexes/extract/extractor.js.map +1 -0
  292. package/dist/rules/indexes/extract/types.d.ts +211 -0
  293. package/dist/rules/indexes/extract/types.d.ts.map +1 -0
  294. package/dist/rules/indexes/extract/types.js +14 -0
  295. package/dist/rules/indexes/extract/types.js.map +1 -0
  296. package/dist/rules/indexes/extractHandler.d.ts +16 -0
  297. package/dist/rules/indexes/extractHandler.d.ts.map +1 -0
  298. package/dist/rules/indexes/extractHandler.js +100 -0
  299. package/dist/rules/indexes/extractHandler.js.map +1 -0
  300. package/dist/rules/indexes/extractTool.d.ts +15 -0
  301. package/dist/rules/indexes/extractTool.d.ts.map +1 -0
  302. package/dist/rules/indexes/extractTool.js +55 -0
  303. package/dist/rules/indexes/extractTool.js.map +1 -0
  304. package/dist/rules/indexes/types.d.ts +71 -0
  305. package/dist/rules/indexes/types.d.ts.map +1 -0
  306. package/dist/rules/indexes/types.js +15 -0
  307. package/dist/rules/indexes/types.js.map +1 -0
  308. package/dist/rules/inspect/handler.d.ts +6 -0
  309. package/dist/rules/inspect/handler.d.ts.map +1 -0
  310. package/dist/rules/inspect/handler.js +144 -0
  311. package/dist/rules/inspect/handler.js.map +1 -0
  312. package/dist/rules/inspect/spec.d.ts +37 -0
  313. package/dist/rules/inspect/spec.d.ts.map +1 -0
  314. package/dist/rules/inspect/spec.js +2 -0
  315. package/dist/rules/inspect/spec.js.map +1 -0
  316. package/dist/rules/inspect/tools.d.ts +21 -0
  317. package/dist/rules/inspect/tools.d.ts.map +1 -0
  318. package/dist/rules/inspect/tools.js +21 -0
  319. package/dist/rules/inspect/tools.js.map +1 -0
  320. package/dist/rules/linter/ast-utils.d.ts +97 -0
  321. package/dist/rules/linter/ast-utils.d.ts.map +1 -0
  322. package/dist/rules/linter/ast-utils.js +491 -0
  323. package/dist/rules/linter/ast-utils.js.map +1 -0
  324. package/dist/rules/linter/hallucinations.d.ts +34 -0
  325. package/dist/rules/linter/hallucinations.d.ts.map +1 -0
  326. package/dist/rules/linter/hallucinations.js +334 -0
  327. package/dist/rules/linter/hallucinations.js.map +1 -0
  328. package/dist/rules/linter/linter.d.ts +84 -0
  329. package/dist/rules/linter/linter.d.ts.map +1 -0
  330. package/dist/rules/linter/linter.js +784 -0
  331. package/dist/rules/linter/linter.js.map +1 -0
  332. package/dist/rules/modules/resolver-browser.d.ts +41 -0
  333. package/dist/rules/modules/resolver-browser.d.ts.map +1 -0
  334. package/dist/rules/modules/resolver-browser.js +63 -0
  335. package/dist/rules/modules/resolver-browser.js.map +1 -0
  336. package/dist/rules/modules/resolver-core.d.ts +51 -0
  337. package/dist/rules/modules/resolver-core.d.ts.map +1 -0
  338. package/dist/rules/modules/resolver-core.js +338 -0
  339. package/dist/rules/modules/resolver-core.js.map +1 -0
  340. package/dist/rules/modules/resolver.d.ts +17 -0
  341. package/dist/rules/modules/resolver.d.ts.map +1 -0
  342. package/dist/rules/modules/resolver.js +49 -0
  343. package/dist/rules/modules/resolver.js.map +1 -0
  344. package/dist/rules/modules/stdlib/atomic.rules +52 -0
  345. package/dist/rules/modules/stdlib/atomic.test.json +152 -0
  346. package/dist/rules/modules/stdlib/auth.rules +7 -0
  347. package/dist/rules/modules/stdlib/auth.test.json +53 -0
  348. package/dist/rules/modules/stdlib/content.rules +50 -0
  349. package/dist/rules/modules/stdlib/content.test.json +238 -0
  350. package/dist/rules/modules/stdlib/counters.rules +41 -0
  351. package/dist/rules/modules/stdlib/counters.test.json +254 -0
  352. package/dist/rules/modules/stdlib/geometry.rules +43 -0
  353. package/dist/rules/modules/stdlib/geometry.test.json +200 -0
  354. package/dist/rules/modules/stdlib/joining.rules +49 -0
  355. package/dist/rules/modules/stdlib/joining.test.json +287 -0
  356. package/dist/rules/modules/stdlib/lifecycle.rules +51 -0
  357. package/dist/rules/modules/stdlib/lifecycle.test.json +288 -0
  358. package/dist/rules/modules/stdlib/lobby.rules +44 -0
  359. package/dist/rules/modules/stdlib/lobby.test.json +32 -0
  360. package/dist/rules/modules/stdlib/membership.rules +40 -0
  361. package/dist/rules/modules/stdlib/membership.test.json +107 -0
  362. package/dist/rules/modules/stdlib/spaces.rules +46 -0
  363. package/dist/rules/modules/stdlib/spaces.test.json +392 -0
  364. package/dist/rules/modules/stdlib/state.rules +28 -0
  365. package/dist/rules/modules/stdlib/state.test.json +55 -0
  366. package/dist/rules/modules/stdlib/timing.rules +20 -0
  367. package/dist/rules/modules/stdlib/timing.test.json +106 -0
  368. package/dist/rules/modules/stdlib/transitions.rules +34 -0
  369. package/dist/rules/modules/stdlib/transitions.test.json +86 -0
  370. package/dist/rules/modules/stdlib/turns.rules +27 -0
  371. package/dist/rules/modules/stdlib/turns.test.json +64 -0
  372. package/dist/rules/modules/stdlib/validation.rules +31 -0
  373. package/dist/rules/modules/stdlib/validation.test.json +184 -0
  374. package/dist/rules/modules/stdlib-content.d.ts +11 -0
  375. package/dist/rules/modules/stdlib-content.d.ts.map +1 -0
  376. package/dist/rules/modules/stdlib-content.js +590 -0
  377. package/dist/rules/modules/stdlib-content.js.map +1 -0
  378. package/dist/rules/node.d.ts +17 -0
  379. package/dist/rules/node.d.ts.map +1 -0
  380. package/dist/rules/node.js +21 -0
  381. package/dist/rules/node.js.map +1 -0
  382. package/dist/rules/rtdb.d.ts +28 -0
  383. package/dist/rules/rtdb.d.ts.map +1 -0
  384. package/dist/rules/rtdb.js +15 -0
  385. package/dist/rules/rtdb.js.map +1 -0
  386. package/dist/rules/simulator/evaluator.d.ts +179 -0
  387. package/dist/rules/simulator/evaluator.d.ts.map +1 -0
  388. package/dist/rules/simulator/evaluator.js +1221 -0
  389. package/dist/rules/simulator/evaluator.js.map +1 -0
  390. package/dist/rules/simulator/expression/eval-errors.d.ts +86 -0
  391. package/dist/rules/simulator/expression/eval-errors.d.ts.map +1 -0
  392. package/dist/rules/simulator/expression/eval-errors.js +68 -0
  393. package/dist/rules/simulator/expression/eval-errors.js.map +1 -0
  394. package/dist/rules/simulator/expression/evaluator.d.ts +43 -0
  395. package/dist/rules/simulator/expression/evaluator.d.ts.map +1 -0
  396. package/dist/rules/simulator/expression/evaluator.js +298 -0
  397. package/dist/rules/simulator/expression/evaluator.js.map +1 -0
  398. package/dist/rules/simulator/expression/lexer.d.ts +36 -0
  399. package/dist/rules/simulator/expression/lexer.d.ts.map +1 -0
  400. package/dist/rules/simulator/expression/lexer.js +318 -0
  401. package/dist/rules/simulator/expression/lexer.js.map +1 -0
  402. package/dist/rules/simulator/expression/parser.d.ts +39 -0
  403. package/dist/rules/simulator/expression/parser.d.ts.map +1 -0
  404. package/dist/rules/simulator/expression/parser.js +329 -0
  405. package/dist/rules/simulator/expression/parser.js.map +1 -0
  406. package/dist/rules/simulator/expression/types.d.ts +137 -0
  407. package/dist/rules/simulator/expression/types.d.ts.map +1 -0
  408. package/dist/rules/simulator/expression/types.js +90 -0
  409. package/dist/rules/simulator/expression/types.js.map +1 -0
  410. package/dist/rules/simulator/expression/walk-data.d.ts +52 -0
  411. package/dist/rules/simulator/expression/walk-data.d.ts.map +1 -0
  412. package/dist/rules/simulator/expression/walk-data.js +167 -0
  413. package/dist/rules/simulator/expression/walk-data.js.map +1 -0
  414. package/dist/rules/simulator/firestore-set.d.ts +25 -0
  415. package/dist/rules/simulator/firestore-set.d.ts.map +1 -0
  416. package/dist/rules/simulator/firestore-set.js +89 -0
  417. package/dist/rules/simulator/firestore-set.js.map +1 -0
  418. package/dist/rules/simulator/handler.d.ts +36 -0
  419. package/dist/rules/simulator/handler.d.ts.map +1 -0
  420. package/dist/rules/simulator/handler.js +583 -0
  421. package/dist/rules/simulator/handler.js.map +1 -0
  422. package/dist/rules/simulator/mapdiff.d.ts +29 -0
  423. package/dist/rules/simulator/mapdiff.d.ts.map +1 -0
  424. package/dist/rules/simulator/mapdiff.js +72 -0
  425. package/dist/rules/simulator/mapdiff.js.map +1 -0
  426. package/dist/rules/simulator/project-after-state.d.ts +33 -0
  427. package/dist/rules/simulator/project-after-state.d.ts.map +1 -0
  428. package/dist/rules/simulator/project-after-state.js +88 -0
  429. package/dist/rules/simulator/project-after-state.js.map +1 -0
  430. package/dist/rules/simulator/query-proof.d.ts +80 -0
  431. package/dist/rules/simulator/query-proof.d.ts.map +1 -0
  432. package/dist/rules/simulator/query-proof.js +142 -0
  433. package/dist/rules/simulator/query-proof.js.map +1 -0
  434. package/dist/rules/simulator/value-equality.d.ts +8 -0
  435. package/dist/rules/simulator/value-equality.d.ts.map +1 -0
  436. package/dist/rules/simulator/value-equality.js +40 -0
  437. package/dist/rules/simulator/value-equality.js.map +1 -0
  438. package/dist/rules/simulator/wrappers/base.d.ts +129 -0
  439. package/dist/rules/simulator/wrappers/base.d.ts.map +1 -0
  440. package/dist/rules/simulator/wrappers/base.js +90 -0
  441. package/dist/rules/simulator/wrappers/base.js.map +1 -0
  442. package/dist/rules/simulator/wrappers/bytes.d.ts +45 -0
  443. package/dist/rules/simulator/wrappers/bytes.d.ts.map +1 -0
  444. package/dist/rules/simulator/wrappers/bytes.js +130 -0
  445. package/dist/rules/simulator/wrappers/bytes.js.map +1 -0
  446. package/dist/rules/simulator/wrappers/duration.d.ts +76 -0
  447. package/dist/rules/simulator/wrappers/duration.d.ts.map +1 -0
  448. package/dist/rules/simulator/wrappers/duration.js +176 -0
  449. package/dist/rules/simulator/wrappers/duration.js.map +1 -0
  450. package/dist/rules/simulator/wrappers/float.d.ts +52 -0
  451. package/dist/rules/simulator/wrappers/float.d.ts.map +1 -0
  452. package/dist/rules/simulator/wrappers/float.js +88 -0
  453. package/dist/rules/simulator/wrappers/float.js.map +1 -0
  454. package/dist/rules/simulator/wrappers/latlng.d.ts +40 -0
  455. package/dist/rules/simulator/wrappers/latlng.d.ts.map +1 -0
  456. package/dist/rules/simulator/wrappers/latlng.js +100 -0
  457. package/dist/rules/simulator/wrappers/latlng.js.map +1 -0
  458. package/dist/rules/simulator/wrappers/path.d.ts +75 -0
  459. package/dist/rules/simulator/wrappers/path.d.ts.map +1 -0
  460. package/dist/rules/simulator/wrappers/path.js +158 -0
  461. package/dist/rules/simulator/wrappers/path.js.map +1 -0
  462. package/dist/rules/simulator/wrappers/reference.d.ts +82 -0
  463. package/dist/rules/simulator/wrappers/reference.d.ts.map +1 -0
  464. package/dist/rules/simulator/wrappers/reference.js +145 -0
  465. package/dist/rules/simulator/wrappers/reference.js.map +1 -0
  466. package/dist/rules/simulator/wrappers/timestamp.d.ts +86 -0
  467. package/dist/rules/simulator/wrappers/timestamp.d.ts.map +1 -0
  468. package/dist/rules/simulator/wrappers/timestamp.js +207 -0
  469. package/dist/rules/simulator/wrappers/timestamp.js.map +1 -0
  470. package/dist/rules/simulator/wrappers/vector.d.ts +43 -0
  471. package/dist/rules/simulator/wrappers/vector.d.ts.map +1 -0
  472. package/dist/rules/simulator/wrappers/vector.js +80 -0
  473. package/dist/rules/simulator/wrappers/vector.js.map +1 -0
  474. package/dist/rules/simulator-tools-impl.d.ts +64 -0
  475. package/dist/rules/simulator-tools-impl.d.ts.map +1 -0
  476. package/dist/rules/simulator-tools-impl.js +462 -0
  477. package/dist/rules/simulator-tools-impl.js.map +1 -0
  478. package/dist/rules/simulator.d.ts +20 -0
  479. package/dist/rules/simulator.d.ts.map +1 -0
  480. package/dist/rules/simulator.js +24 -0
  481. package/dist/rules/simulator.js.map +1 -0
  482. package/dist/rules/stdlib-modules.d.ts +73 -0
  483. package/dist/rules/stdlib-modules.d.ts.map +1 -0
  484. package/dist/rules/stdlib-modules.js +849 -0
  485. package/dist/rules/stdlib-modules.js.map +1 -0
  486. package/dist/rules/stdlib-tools.d.ts +19 -0
  487. package/dist/rules/stdlib-tools.d.ts.map +1 -0
  488. package/dist/rules/stdlib-tools.js +164 -0
  489. package/dist/rules/stdlib-tools.js.map +1 -0
  490. package/dist/rules/test/handler.d.ts +9 -0
  491. package/dist/rules/test/handler.d.ts.map +1 -0
  492. package/dist/rules/test/handler.js +124 -0
  493. package/dist/rules/test/handler.js.map +1 -0
  494. package/dist/rules/test/spec.d.ts +517 -0
  495. package/dist/rules/test/spec.d.ts.map +1 -0
  496. package/dist/rules/test/spec.js +227 -0
  497. package/dist/rules/test/spec.js.map +1 -0
  498. package/dist/rules/tools.d.ts +41 -0
  499. package/dist/rules/tools.d.ts.map +1 -0
  500. package/dist/rules/tools.js +124 -0
  501. package/dist/rules/tools.js.map +1 -0
  502. package/dist/rules/write/handler.d.ts +6 -0
  503. package/dist/rules/write/handler.d.ts.map +1 -0
  504. package/dist/rules/write/handler.js +126 -0
  505. package/dist/rules/write/handler.js.map +1 -0
  506. package/dist/rules/write/spec.d.ts +28 -0
  507. package/dist/rules/write/spec.d.ts.map +1 -0
  508. package/dist/rules/write/spec.js +2 -0
  509. package/dist/rules/write/spec.js.map +1 -0
  510. package/dist/sandbox/admin-compat.d.ts +20 -0
  511. package/dist/sandbox/admin-compat.d.ts.map +1 -0
  512. package/dist/sandbox/admin-compat.js +19 -0
  513. package/dist/sandbox/admin-compat.js.map +1 -0
  514. package/dist/sandbox/admin-firestore/error-translation.d.ts +86 -0
  515. package/dist/sandbox/admin-firestore/error-translation.d.ts.map +1 -0
  516. package/dist/sandbox/admin-firestore/error-translation.js +204 -0
  517. package/dist/sandbox/admin-firestore/error-translation.js.map +1 -0
  518. package/dist/sandbox/admin-firestore/index.d.ts +169 -0
  519. package/dist/sandbox/admin-firestore/index.d.ts.map +1 -0
  520. package/dist/sandbox/admin-firestore/index.js +456 -0
  521. package/dist/sandbox/admin-firestore/index.js.map +1 -0
  522. package/dist/sandbox/admin-firestore/remote.d.ts +97 -0
  523. package/dist/sandbox/admin-firestore/remote.d.ts.map +1 -0
  524. package/dist/sandbox/admin-firestore/remote.js +735 -0
  525. package/dist/sandbox/admin-firestore/remote.js.map +1 -0
  526. package/dist/sandbox/branches/index.d.ts +141 -0
  527. package/dist/sandbox/branches/index.d.ts.map +1 -0
  528. package/dist/sandbox/branches/index.js +327 -0
  529. package/dist/sandbox/branches/index.js.map +1 -0
  530. package/dist/sandbox/firestore/admin-compat/batch.d.ts +34 -0
  531. package/dist/sandbox/firestore/admin-compat/batch.d.ts.map +1 -0
  532. package/dist/sandbox/firestore/admin-compat/batch.js +73 -0
  533. package/dist/sandbox/firestore/admin-compat/batch.js.map +1 -0
  534. package/dist/sandbox/firestore/admin-compat/doc-ref.d.ts +38 -0
  535. package/dist/sandbox/firestore/admin-compat/doc-ref.d.ts.map +1 -0
  536. package/dist/sandbox/firestore/admin-compat/doc-ref.js +154 -0
  537. package/dist/sandbox/firestore/admin-compat/doc-ref.js.map +1 -0
  538. package/dist/sandbox/firestore/admin-compat/firestore.d.ts +45 -0
  539. package/dist/sandbox/firestore/admin-compat/firestore.d.ts.map +1 -0
  540. package/dist/sandbox/firestore/admin-compat/firestore.js +114 -0
  541. package/dist/sandbox/firestore/admin-compat/firestore.js.map +1 -0
  542. package/dist/sandbox/firestore/admin-compat/index.d.ts +45 -0
  543. package/dist/sandbox/firestore/admin-compat/index.d.ts.map +1 -0
  544. package/dist/sandbox/firestore/admin-compat/index.js +27 -0
  545. package/dist/sandbox/firestore/admin-compat/index.js.map +1 -0
  546. package/dist/sandbox/firestore/admin-compat/paths.d.ts +37 -0
  547. package/dist/sandbox/firestore/admin-compat/paths.d.ts.map +1 -0
  548. package/dist/sandbox/firestore/admin-compat/paths.js +49 -0
  549. package/dist/sandbox/firestore/admin-compat/paths.js.map +1 -0
  550. package/dist/sandbox/firestore/admin-compat/query.d.ts +261 -0
  551. package/dist/sandbox/firestore/admin-compat/query.d.ts.map +1 -0
  552. package/dist/sandbox/firestore/admin-compat/query.js +704 -0
  553. package/dist/sandbox/firestore/admin-compat/query.js.map +1 -0
  554. package/dist/sandbox/firestore/admin-compat/read-translation.d.ts +8 -0
  555. package/dist/sandbox/firestore/admin-compat/read-translation.d.ts.map +1 -0
  556. package/dist/sandbox/firestore/admin-compat/read-translation.js +59 -0
  557. package/dist/sandbox/firestore/admin-compat/read-translation.js.map +1 -0
  558. package/dist/sandbox/firestore/admin-compat/snapshots.d.ts +39 -0
  559. package/dist/sandbox/firestore/admin-compat/snapshots.d.ts.map +1 -0
  560. package/dist/sandbox/firestore/admin-compat/snapshots.js +50 -0
  561. package/dist/sandbox/firestore/admin-compat/snapshots.js.map +1 -0
  562. package/dist/sandbox/firestore/admin-compat/transaction.d.ts +35 -0
  563. package/dist/sandbox/firestore/admin-compat/transaction.d.ts.map +1 -0
  564. package/dist/sandbox/firestore/admin-compat/transaction.js +88 -0
  565. package/dist/sandbox/firestore/admin-compat/transaction.js.map +1 -0
  566. package/dist/sandbox/firestore/admin-compat/types.d.ts +297 -0
  567. package/dist/sandbox/firestore/admin-compat/types.d.ts.map +1 -0
  568. package/dist/sandbox/firestore/admin-compat/types.js +127 -0
  569. package/dist/sandbox/firestore/admin-compat/types.js.map +1 -0
  570. package/dist/sandbox/firestore/admin-compat/value-order.d.ts +49 -0
  571. package/dist/sandbox/firestore/admin-compat/value-order.d.ts.map +1 -0
  572. package/dist/sandbox/firestore/admin-compat/value-order.js +172 -0
  573. package/dist/sandbox/firestore/admin-compat/value-order.js.map +1 -0
  574. package/dist/sandbox/firestore/auto-id.d.ts +26 -0
  575. package/dist/sandbox/firestore/auto-id.d.ts.map +1 -0
  576. package/dist/sandbox/firestore/auto-id.js +36 -0
  577. package/dist/sandbox/firestore/auto-id.js.map +1 -0
  578. package/dist/sandbox/firestore/converters/bytes-geopoint.d.ts +48 -0
  579. package/dist/sandbox/firestore/converters/bytes-geopoint.d.ts.map +1 -0
  580. package/dist/sandbox/firestore/converters/bytes-geopoint.js +85 -0
  581. package/dist/sandbox/firestore/converters/bytes-geopoint.js.map +1 -0
  582. package/dist/sandbox/firestore/converters/fieldvalue.d.ts +69 -0
  583. package/dist/sandbox/firestore/converters/fieldvalue.d.ts.map +1 -0
  584. package/dist/sandbox/firestore/converters/fieldvalue.js +166 -0
  585. package/dist/sandbox/firestore/converters/fieldvalue.js.map +1 -0
  586. package/dist/sandbox/firestore/converters/reference.d.ts +31 -0
  587. package/dist/sandbox/firestore/converters/reference.d.ts.map +1 -0
  588. package/dist/sandbox/firestore/converters/reference.js +51 -0
  589. package/dist/sandbox/firestore/converters/reference.js.map +1 -0
  590. package/dist/sandbox/firestore/converters/timestamp.d.ts +32 -0
  591. package/dist/sandbox/firestore/converters/timestamp.d.ts.map +1 -0
  592. package/dist/sandbox/firestore/converters/timestamp.js +63 -0
  593. package/dist/sandbox/firestore/converters/timestamp.js.map +1 -0
  594. package/dist/sandbox/firestore/converters/user-timestamp.d.ts +46 -0
  595. package/dist/sandbox/firestore/converters/user-timestamp.d.ts.map +1 -0
  596. package/dist/sandbox/firestore/converters/user-timestamp.js +65 -0
  597. package/dist/sandbox/firestore/converters/user-timestamp.js.map +1 -0
  598. package/dist/sandbox/firestore/converters/vector.d.ts +24 -0
  599. package/dist/sandbox/firestore/converters/vector.d.ts.map +1 -0
  600. package/dist/sandbox/firestore/converters/vector.js +53 -0
  601. package/dist/sandbox/firestore/converters/vector.js.map +1 -0
  602. package/dist/sandbox/firestore/errors.d.ts +82 -0
  603. package/dist/sandbox/firestore/errors.d.ts.map +1 -0
  604. package/dist/sandbox/firestore/errors.js +54 -0
  605. package/dist/sandbox/firestore/errors.js.map +1 -0
  606. package/dist/sandbox/firestore/event-log.d.ts +99 -0
  607. package/dist/sandbox/firestore/event-log.d.ts.map +1 -0
  608. package/dist/sandbox/firestore/event-log.js +67 -0
  609. package/dist/sandbox/firestore/event-log.js.map +1 -0
  610. package/dist/sandbox/firestore/field-merge.d.ts +64 -0
  611. package/dist/sandbox/firestore/field-merge.d.ts.map +1 -0
  612. package/dist/sandbox/firestore/field-merge.js +221 -0
  613. package/dist/sandbox/firestore/field-merge.js.map +1 -0
  614. package/dist/sandbox/firestore/list-query-proof.d.ts +77 -0
  615. package/dist/sandbox/firestore/list-query-proof.d.ts.map +1 -0
  616. package/dist/sandbox/firestore/list-query-proof.js +170 -0
  617. package/dist/sandbox/firestore/list-query-proof.js.map +1 -0
  618. package/dist/sandbox/firestore/local-environment.d.ts +806 -0
  619. package/dist/sandbox/firestore/local-environment.d.ts.map +1 -0
  620. package/dist/sandbox/firestore/local-environment.js +3028 -0
  621. package/dist/sandbox/firestore/local-environment.js.map +1 -0
  622. package/dist/sandbox/firestore/local-state.d.ts +196 -0
  623. package/dist/sandbox/firestore/local-state.d.ts.map +1 -0
  624. package/dist/sandbox/firestore/local-state.js +413 -0
  625. package/dist/sandbox/firestore/local-state.js.map +1 -0
  626. package/dist/sandbox/firestore/overlay-backing.d.ts +44 -0
  627. package/dist/sandbox/firestore/overlay-backing.d.ts.map +1 -0
  628. package/dist/sandbox/firestore/overlay-backing.js +82 -0
  629. package/dist/sandbox/firestore/overlay-backing.js.map +1 -0
  630. package/dist/sandbox/firestore/sentinel-capture.d.ts +30 -0
  631. package/dist/sandbox/firestore/sentinel-capture.d.ts.map +1 -0
  632. package/dist/sandbox/firestore/sentinel-capture.js +61 -0
  633. package/dist/sandbox/firestore/sentinel-capture.js.map +1 -0
  634. package/dist/sandbox/firestore/snapshot-listeners.d.ts +284 -0
  635. package/dist/sandbox/firestore/snapshot-listeners.d.ts.map +1 -0
  636. package/dist/sandbox/firestore/snapshot-listeners.js +194 -0
  637. package/dist/sandbox/firestore/snapshot-listeners.js.map +1 -0
  638. package/dist/sandbox/firestore/topk.d.ts +12 -0
  639. package/dist/sandbox/firestore/topk.d.ts.map +1 -0
  640. package/dist/sandbox/firestore/topk.js +42 -0
  641. package/dist/sandbox/firestore/topk.js.map +1 -0
  642. package/dist/sandbox/firestore/transaction-merge.d.ts +55 -0
  643. package/dist/sandbox/firestore/transaction-merge.d.ts.map +1 -0
  644. package/dist/sandbox/firestore/transaction-merge.js +107 -0
  645. package/dist/sandbox/firestore/transaction-merge.js.map +1 -0
  646. package/dist/sandbox/firestore/transaction-types.d.ts +152 -0
  647. package/dist/sandbox/firestore/transaction-types.d.ts.map +1 -0
  648. package/dist/sandbox/firestore/transaction-types.js +10 -0
  649. package/dist/sandbox/firestore/transaction-types.js.map +1 -0
  650. package/dist/sandbox/firestore/transaction.d.ts +79 -0
  651. package/dist/sandbox/firestore/transaction.d.ts.map +1 -0
  652. package/dist/sandbox/firestore/transaction.js +95 -0
  653. package/dist/sandbox/firestore/transaction.js.map +1 -0
  654. package/dist/sandbox/firestore/value-equality.d.ts +2 -0
  655. package/dist/sandbox/firestore/value-equality.d.ts.map +1 -0
  656. package/dist/sandbox/firestore/value-equality.js +35 -0
  657. package/dist/sandbox/firestore/value-equality.js.map +1 -0
  658. package/dist/sandbox/firestore/value-resolver.d.ts +172 -0
  659. package/dist/sandbox/firestore/value-resolver.d.ts.map +1 -0
  660. package/dist/sandbox/firestore/value-resolver.js +221 -0
  661. package/dist/sandbox/firestore/value-resolver.js.map +1 -0
  662. package/dist/sandbox/firestore/wire-encoder.d.ts +14 -0
  663. package/dist/sandbox/firestore/wire-encoder.d.ts.map +1 -0
  664. package/dist/sandbox/firestore/wire-encoder.js +130 -0
  665. package/dist/sandbox/firestore/wire-encoder.js.map +1 -0
  666. package/dist/sandbox/index.d.ts +50 -0
  667. package/dist/sandbox/index.d.ts.map +1 -0
  668. package/dist/sandbox/index.js +63 -0
  669. package/dist/sandbox/index.js.map +1 -0
  670. package/dist/sandbox/internal/index.d.ts +36 -0
  671. package/dist/sandbox/internal/index.d.ts.map +1 -0
  672. package/dist/sandbox/internal/index.js +72 -0
  673. package/dist/sandbox/internal/index.js.map +1 -0
  674. package/dist/sandbox/internal/sandbox-impl.d.ts +343 -0
  675. package/dist/sandbox/internal/sandbox-impl.d.ts.map +1 -0
  676. package/dist/sandbox/internal/sandbox-impl.js +718 -0
  677. package/dist/sandbox/internal/sandbox-impl.js.map +1 -0
  678. package/dist/sandbox/persistence/backends.d.ts +37 -0
  679. package/dist/sandbox/persistence/backends.d.ts.map +1 -0
  680. package/dist/sandbox/persistence/backends.js +202 -0
  681. package/dist/sandbox/persistence/backends.js.map +1 -0
  682. package/dist/sandbox/persistence/chunk-format.d.ts +58 -0
  683. package/dist/sandbox/persistence/chunk-format.d.ts.map +1 -0
  684. package/dist/sandbox/persistence/chunk-format.js +163 -0
  685. package/dist/sandbox/persistence/chunk-format.js.map +1 -0
  686. package/dist/sandbox/persistence/controller.d.ts +39 -0
  687. package/dist/sandbox/persistence/controller.d.ts.map +1 -0
  688. package/dist/sandbox/persistence/controller.js +605 -0
  689. package/dist/sandbox/persistence/controller.js.map +1 -0
  690. package/dist/sandbox/persistence/index.d.ts +13 -0
  691. package/dist/sandbox/persistence/index.d.ts.map +1 -0
  692. package/dist/sandbox/persistence/index.js +5 -0
  693. package/dist/sandbox/persistence/index.js.map +1 -0
  694. package/dist/sandbox/persistence/serialize.d.ts +53 -0
  695. package/dist/sandbox/persistence/serialize.d.ts.map +1 -0
  696. package/dist/sandbox/persistence/serialize.js +98 -0
  697. package/dist/sandbox/persistence/serialize.js.map +1 -0
  698. package/dist/sandbox/persistence/types.d.ts +118 -0
  699. package/dist/sandbox/persistence/types.d.ts.map +1 -0
  700. package/dist/sandbox/persistence/types.js +15 -0
  701. package/dist/sandbox/persistence/types.js.map +1 -0
  702. package/dist/sandbox/remote.d.ts +118 -0
  703. package/dist/sandbox/remote.d.ts.map +1 -0
  704. package/dist/sandbox/remote.js +60 -0
  705. package/dist/sandbox/remote.js.map +1 -0
  706. package/dist/sandbox/replay/index.d.ts +106 -0
  707. package/dist/sandbox/replay/index.d.ts.map +1 -0
  708. package/dist/sandbox/replay/index.js +246 -0
  709. package/dist/sandbox/replay/index.js.map +1 -0
  710. package/dist/sandbox/sandbox-context.d.ts +40 -0
  711. package/dist/sandbox/sandbox-context.d.ts.map +1 -0
  712. package/dist/sandbox/sandbox-context.js +72 -0
  713. package/dist/sandbox/sandbox-context.js.map +1 -0
  714. package/dist/sandbox/tab-sync/index.d.ts +120 -0
  715. package/dist/sandbox/tab-sync/index.d.ts.map +1 -0
  716. package/dist/sandbox/tab-sync/index.js +272 -0
  717. package/dist/sandbox/tab-sync/index.js.map +1 -0
  718. package/dist/sandbox/types.d.ts +1235 -0
  719. package/dist/sandbox/types.d.ts.map +1 -0
  720. package/dist/sandbox/types.js +46 -0
  721. package/dist/sandbox/types.js.map +1 -0
  722. package/dist/storage/admin/api.d.ts +206 -0
  723. package/dist/storage/admin/api.d.ts.map +1 -0
  724. package/dist/storage/admin/api.js +349 -0
  725. package/dist/storage/admin/api.js.map +1 -0
  726. package/dist/storage/admin/handler.d.ts +29 -0
  727. package/dist/storage/admin/handler.d.ts.map +1 -0
  728. package/dist/storage/admin/handler.js +82 -0
  729. package/dist/storage/admin/handler.js.map +1 -0
  730. package/dist/storage/admin/spec.d.ts +64 -0
  731. package/dist/storage/admin/spec.d.ts.map +1 -0
  732. package/dist/storage/admin/spec.js +8 -0
  733. package/dist/storage/admin/spec.js.map +1 -0
  734. package/dist/storage/admin/tools.d.ts +23 -0
  735. package/dist/storage/admin/tools.d.ts.map +1 -0
  736. package/dist/storage/admin/tools.js +90 -0
  737. package/dist/storage/admin/tools.js.map +1 -0
  738. package/dist/storage/download.d.ts +27 -0
  739. package/dist/storage/download.d.ts.map +1 -0
  740. package/dist/storage/download.js +136 -0
  741. package/dist/storage/download.js.map +1 -0
  742. package/dist/storage/enforce.d.ts +26 -0
  743. package/dist/storage/enforce.d.ts.map +1 -0
  744. package/dist/storage/enforce.js +16 -0
  745. package/dist/storage/enforce.js.map +1 -0
  746. package/dist/storage/errors.d.ts +46 -0
  747. package/dist/storage/errors.d.ts.map +1 -0
  748. package/dist/storage/errors.js +62 -0
  749. package/dist/storage/errors.js.map +1 -0
  750. package/dist/storage/index.d.ts +49 -0
  751. package/dist/storage/index.d.ts.map +1 -0
  752. package/dist/storage/index.js +60 -0
  753. package/dist/storage/index.js.map +1 -0
  754. package/dist/storage/internal.d.ts +18 -0
  755. package/dist/storage/internal.d.ts.map +1 -0
  756. package/dist/storage/internal.js +18 -0
  757. package/dist/storage/internal.js.map +1 -0
  758. package/dist/storage/list.d.ts +17 -0
  759. package/dist/storage/list.d.ts.map +1 -0
  760. package/dist/storage/list.js +91 -0
  761. package/dist/storage/list.js.map +1 -0
  762. package/dist/storage/metadata.d.ts +86 -0
  763. package/dist/storage/metadata.d.ts.map +1 -0
  764. package/dist/storage/metadata.js +167 -0
  765. package/dist/storage/metadata.js.map +1 -0
  766. package/dist/storage/persistence.d.ts +134 -0
  767. package/dist/storage/persistence.d.ts.map +1 -0
  768. package/dist/storage/persistence.js +132 -0
  769. package/dist/storage/persistence.js.map +1 -0
  770. package/dist/storage/reference.d.ts +63 -0
  771. package/dist/storage/reference.d.ts.map +1 -0
  772. package/dist/storage/reference.js +156 -0
  773. package/dist/storage/reference.js.map +1 -0
  774. package/dist/storage/rules.d.ts +176 -0
  775. package/dist/storage/rules.d.ts.map +1 -0
  776. package/dist/storage/rules.js +621 -0
  777. package/dist/storage/rules.js.map +1 -0
  778. package/dist/storage/service.d.ts +139 -0
  779. package/dist/storage/service.d.ts.map +1 -0
  780. package/dist/storage/service.js +241 -0
  781. package/dist/storage/service.js.map +1 -0
  782. package/dist/storage/upload.d.ts +43 -0
  783. package/dist/storage/upload.d.ts.map +1 -0
  784. package/dist/storage/upload.js +235 -0
  785. package/dist/storage/upload.js.map +1 -0
  786. package/package.json +109 -3
@@ -0,0 +1,1226 @@
1
+ /**
2
+ * `@pyric/rtdb` modular SDK surface — Phase 3 implementation.
3
+ *
4
+ * Mirrors `firebase/database`'s tree-shakable free-function shape:
5
+ * `getDatabase`, `ref`, `child`, `get`, `set`, `update`, `remove`,
6
+ * `push`, `onValue`, `serverTimestamp`, `connectDatabaseEmulator`.
7
+ *
8
+ * Three backends picked by what's passed to `getDatabase`:
9
+ *
10
+ * - **Sandbox target** — wraps `RtdbBackend` (in-memory JSON tree
11
+ * plus the existing `@pyric/rtdb` rule simulator). Identity is the
12
+ * `SandboxContext`'s frozen `auth`.
13
+ * - **Sandbox-live target** — same backend, but identity is read
14
+ * per-op from `sandbox.currentUser` so a `pyric/auth`-driven
15
+ * sign-in flips the next op's `request.auth` without re-binding.
16
+ * - **Prod target** — wraps `firebase/database` against a real
17
+ * Firebase project.
18
+ *
19
+ * Dispatch machinery mirrors `pyric/firestore`:
20
+ * - {@link TARGET_SYMBOL} brand on every {@link Database} handle.
21
+ * - {@link refToTarget} WeakMap from refs to their owning target so
22
+ * chained calls (`child(ref, 'sub')`, `get(ref)`) recover routing.
23
+ *
24
+ * Every public function has a `target.kind` switch with explicit
25
+ * branches — structure is parallel and grep-friendly.
26
+ *
27
+ * **Critical contract — error shape (locked by oracle observation
28
+ * `scripts/oracle/observations/rtdb-rules-denied-error-code.json`):**
29
+ *
30
+ * - Throws a **plain `Error`** (NOT a `FirebaseError`).
31
+ * - `.code === 'PERMISSION_DENIED'` (uppercase snake-case — distinct
32
+ * from Firestore's `'permission-denied'`).
33
+ * - `.message === 'PERMISSION_DENIED: Permission denied'`.
34
+ *
35
+ * The sandbox backend matches this shape exactly. Tests assert against
36
+ * `.constructor.name === 'Error'` to catch any future "improvement" to
37
+ * a custom subclass.
38
+ */
39
+ import * as fb from 'firebase/database';
40
+ import { SandboxContextImpl } from 'pyric/sandbox';
41
+ // Phase 3 unified app handle. Adapter dispatch reads `APP_TARGET` and
42
+ // routes to the existing direct-handle path (sandbox vs prod).
43
+ import { APP_TARGET } from 'pyric/app';
44
+ import { RtdbBackend } from './sandbox/backend.js';
45
+ import { generatePushId } from './sandbox/push-id.js';
46
+ import { serverTimestampSentinel, incrementSentinel, } from './sandbox/sentinels.js';
47
+ import { joinPath, pathSegments } from './sandbox/data-tree.js';
48
+ import { coerceArrays } from './sandbox/normalize.js';
49
+ import { applyConstraint, emptySpec, } from './sandbox/query.js';
50
+ // ─── Brand + routing ─────────────────────────────────────────────────
51
+ /** Hidden brand on every {@link Database} handle. */
52
+ export const TARGET_SYMBOL = Symbol('@pyric/rtdb/target');
53
+ function isSandboxKind(t) {
54
+ return t.kind === 'sandbox' || t.kind === 'sandbox-live';
55
+ }
56
+ /** Resolve the active identity for a sandbox-flavored target. */
57
+ function authFor(t) {
58
+ if (t.admin)
59
+ return null;
60
+ return t.kind === 'sandbox' ? t.auth : t.sandbox.currentUser;
61
+ }
62
+ /**
63
+ * One backend per `Sandbox`. The modular surface tracks the binding
64
+ * here so successive `getDatabase(sandbox)` calls return handles that
65
+ * share data (matches `firebase/database`'s singleton-per-`FirebaseApp`).
66
+ */
67
+ const backendBySandbox = new WeakMap();
68
+ function getOrCreateBackend(sandbox) {
69
+ let backend = backendBySandbox.get(sandbox);
70
+ if (!backend) {
71
+ // Pass the owning sandbox so the backend can land RTDB write activity
72
+ // on the unified Studio `onEvent`/`history()` stream (keystone T1).
73
+ backend = new RtdbBackend(sandbox);
74
+ backendBySandbox.set(sandbox, backend);
75
+ // Register the RTDB tree as a persistable service on the sandbox — the
76
+ // same durability mechanism auth uses (see auth/index.ts:backendFor).
77
+ // This makes `enablePersistence` include the tree in the serialized blob
78
+ // and restore it on reload (worker death / browser restart), instead of
79
+ // the old memory-only behavior where RTDB data was lost while Firestore
80
+ // docs + auth users came back.
81
+ //
82
+ // Guarded by the WeakMap memoization above: we only reach this branch
83
+ // ONCE per sandbox, so double-registration is impossible in practice
84
+ // (registerPersistableService throws on duplicates anyway).
85
+ //
86
+ // - snapshot: serialize the tree as a plain JSON value.
87
+ // - restore : REPLACE the tree AND fire listeners so a live RTDB view
88
+ // (Studio's RTDB tab) converges on the restored data.
89
+ // - subscribe: notify the controller on ANY write so a mutation
90
+ // schedules a debounced flush. RTDB writes emit
91
+ // `service_mutation` events, which the controller's
92
+ // `isPersistableEvent` does NOT cover — so this hook is the
93
+ // sole flush trigger, exactly as auth does it.
94
+ const capturedBackend = backend;
95
+ sandbox.registerPersistableService('rtdb', {
96
+ snapshot: () => capturedBackend.exportTree(),
97
+ restore: (data) => {
98
+ capturedBackend.restoreTree(data);
99
+ },
100
+ subscribe: (onChange) => capturedBackend.subscribeWrites(onChange),
101
+ });
102
+ }
103
+ return backend;
104
+ }
105
+ const refToTarget = new WeakMap();
106
+ function tag(obj, target) {
107
+ refToTarget.set(obj, target);
108
+ return obj;
109
+ }
110
+ function targetOf(refOrDb) {
111
+ if (TARGET_SYMBOL in refOrDb) {
112
+ return refOrDb[TARGET_SYMBOL];
113
+ }
114
+ const t = refToTarget.get(refOrDb);
115
+ if (!t) {
116
+ throw new TypeError('@pyric/rtdb: unrecognized reference — was it produced by a factory in this package?');
117
+ }
118
+ return t;
119
+ }
120
+ /**
121
+ * Hidden brand on every {@link Query} (and on every QueryConstraint).
122
+ * Distinct from `TARGET_SYMBOL`; this brand is only used to dispatch
123
+ * `get` / `onValue` between plain refs and query-wrapped refs.
124
+ */
125
+ export const QUERY_SYMBOL = Symbol('@pyric/rtdb/query');
126
+ /** Hidden brand on every {@link QueryConstraint}. */
127
+ const CONSTRAINT_SYMBOL = Symbol('@pyric/rtdb/query-constraint');
128
+ function buildConstraint(type, internal) {
129
+ return Object.freeze({
130
+ type,
131
+ [CONSTRAINT_SYMBOL]: internal,
132
+ });
133
+ }
134
+ function isQuery(v) {
135
+ return QUERY_SYMBOL in v;
136
+ }
137
+ /** Internal-only: bridge our constraint into the prod-side fb constraint. */
138
+ function toFbConstraint(c) {
139
+ switch (c.type) {
140
+ case 'orderByChild': {
141
+ const ic = c[CONSTRAINT_SYMBOL];
142
+ return fb.orderByChild(ic.spec.path);
143
+ }
144
+ case 'orderByKey':
145
+ return fb.orderByKey();
146
+ case 'orderByValue':
147
+ return fb.orderByValue();
148
+ case 'startAt': {
149
+ const ic = c[CONSTRAINT_SYMBOL];
150
+ return fb.startAt(ic.bound.value, ic.bound.key);
151
+ }
152
+ case 'startAfter': {
153
+ const ic = c[CONSTRAINT_SYMBOL];
154
+ return fb.startAfter(ic.bound.value, ic.bound.key);
155
+ }
156
+ case 'endAt': {
157
+ const ic = c[CONSTRAINT_SYMBOL];
158
+ return fb.endAt(ic.bound.value, ic.bound.key);
159
+ }
160
+ case 'endBefore': {
161
+ const ic = c[CONSTRAINT_SYMBOL];
162
+ return fb.endBefore(ic.bound.value, ic.bound.key);
163
+ }
164
+ case 'equalTo': {
165
+ const ic = c[CONSTRAINT_SYMBOL];
166
+ return fb.equalTo(ic.bound.value, ic.bound.key);
167
+ }
168
+ case 'limitToFirst': {
169
+ const ic = c[CONSTRAINT_SYMBOL];
170
+ return fb.limitToFirst(ic.n);
171
+ }
172
+ case 'limitToLast': {
173
+ const ic = c[CONSTRAINT_SYMBOL];
174
+ return fb.limitToLast(ic.n);
175
+ }
176
+ }
177
+ }
178
+ export function getDatabase(target) {
179
+ // PyricApp dispatch: inspect the brand and forward to the existing
180
+ // direct-handle path. Ordered FIRST so a PyricApp's outer shell
181
+ // never falls through to a structural sniff for `Sandbox`.
182
+ if (isPyricApp(target)) {
183
+ return target[APP_TARGET] === 'sandbox'
184
+ ? getDatabase(target.sandbox)
185
+ : getDatabase(target.firebaseApp);
186
+ }
187
+ if (isSandboxContext(target)) {
188
+ const backend = getOrCreateBackend(target.sandbox);
189
+ const t = { kind: 'sandbox', backend, auth: target.auth };
190
+ return { [TARGET_SYMBOL]: t };
191
+ }
192
+ if (isSandbox(target)) {
193
+ const backend = getOrCreateBackend(target);
194
+ const t = { kind: 'sandbox-live', backend, sandbox: target };
195
+ return { [TARGET_SYMBOL]: t };
196
+ }
197
+ const fbDb = fb.getDatabase(target);
198
+ const t = { kind: 'prod', db: fbDb };
199
+ return { [TARGET_SYMBOL]: t };
200
+ }
201
+ export function getAdminDatabase(target) {
202
+ if (isPyricApp(target)) {
203
+ if (target[APP_TARGET] !== 'sandbox') {
204
+ throw new TypeError('getAdminDatabase: the admin (rules-bypass) lens is sandbox-only — ' +
205
+ 'a prod-backed app has no way to bypass deployed security rules.');
206
+ }
207
+ return getAdminDatabase(target.sandbox);
208
+ }
209
+ const sandbox = isSandboxContext(target) ? target.sandbox : target;
210
+ const backend = getOrCreateBackend(sandbox);
211
+ const t = { kind: 'sandbox', backend, auth: null, admin: true };
212
+ return { [TARGET_SYMBOL]: t };
213
+ }
214
+ /**
215
+ * Brand-based test for the {@link PyricApp} overload. Reads the
216
+ * `APP_TARGET` symbol that `pyric/app`'s `initializeApp` stamps on
217
+ * every handle. Cheap + collision-free: a `Sandbox` / `FirebaseApp`
218
+ * / `SandboxContext` will never carry this symbol.
219
+ */
220
+ function isPyricApp(target) {
221
+ return (target !== null
222
+ && typeof target === 'object'
223
+ && APP_TARGET in target);
224
+ }
225
+ function isSandboxContext(target) {
226
+ return target instanceof SandboxContextImpl;
227
+ }
228
+ function isSandbox(target) {
229
+ if (target === null || typeof target !== 'object')
230
+ return false;
231
+ const o = target;
232
+ return (typeof o.withAuth === 'function'
233
+ && typeof o.onCurrentUserChanged === 'function'
234
+ && 'currentUser' in o
235
+ && 'admin' in o);
236
+ }
237
+ // ─── Reference constructors ──────────────────────────────────────────
238
+ /**
239
+ * Build a {@link DatabaseReference} at `path` (default root).
240
+ *
241
+ * Sandbox: returns a lightweight ref object owning its absolute path.
242
+ * Prod: delegates to `firebase/database`'s `ref(db, path)` and tags
243
+ * the returned ref so chained ops route correctly.
244
+ *
245
+ * Path normalisation: leading + trailing slashes are stripped;
246
+ * empty path / `'/'` becomes the root.
247
+ */
248
+ export function ref(db, path) {
249
+ const target = targetOf(db);
250
+ if (isSandboxKind(target)) {
251
+ return buildSandboxRef(target, path ?? '/');
252
+ }
253
+ const r = fb.ref(target.db, path);
254
+ // Tag so subsequent free-function calls (child, get, set, …)
255
+ // recover routing without inspecting the ref shape.
256
+ tag(r, target);
257
+ return r;
258
+ }
259
+ /**
260
+ * Sub-path constructor. `child(ref, 'sub/path')` returns a ref at
261
+ * `<ref>/sub/path`.
262
+ *
263
+ * Mirrors `firebase/database`'s `child(parent, path)` — leading +
264
+ * empty segments stripped; the result inherits the parent's target.
265
+ */
266
+ export function child(parent, path) {
267
+ const target = targetOf(parent);
268
+ if (isSandboxKind(target)) {
269
+ const absSegs = [...pathSegments(parent._path), ...pathSegments(path)];
270
+ return buildSandboxRef(target, joinPath(absSegs));
271
+ }
272
+ const r = fb.child(parent, path);
273
+ tag(r, target);
274
+ return r;
275
+ }
276
+ /**
277
+ * Build a sandbox-backed `DatabaseReference`. Cached parent / root
278
+ * pointers are computed lazily so a long chain doesn't materialise
279
+ * every intermediate ref upfront.
280
+ */
281
+ function buildSandboxRef(target, path) {
282
+ const canonical = joinPath(pathSegments(path));
283
+ const segs = pathSegments(canonical);
284
+ const key = segs.length === 0 ? null : segs[segs.length - 1];
285
+ const self = {
286
+ key,
287
+ _path: canonical,
288
+ get parent() {
289
+ if (segs.length === 0)
290
+ return null;
291
+ return buildSandboxRef(target, joinPath(segs.slice(0, -1)));
292
+ },
293
+ get root() {
294
+ return buildSandboxRef(target, '/');
295
+ },
296
+ toString() {
297
+ return `sandbox://rtdb${canonical}`;
298
+ },
299
+ };
300
+ tag(self, target);
301
+ return self;
302
+ }
303
+ // ─── Reads ───────────────────────────────────────────────────────────
304
+ /**
305
+ * `get(ref)` — one-shot read at the ref's path. Resolves to a
306
+ * `DataSnapshot`-shaped object.
307
+ *
308
+ * Sandbox: runs through the rule engine; denial throws the plain-`Error`
309
+ * shape locked by the oracle. Prod: delegates to `firebase/database`'s
310
+ * `get(ref)` and wraps the returned snapshot in our minimal shape.
311
+ *
312
+ * Absent path → `snap.val() === null && snap.exists() === false`.
313
+ * Matches the SDK's `DataSnapshot.val()` contract.
314
+ */
315
+ export async function get(r) {
316
+ // Query branch — windowed read.
317
+ if (isQuery(r)) {
318
+ const q = r;
319
+ const target = targetOf(q.ref);
320
+ if (isSandboxKind(target)) {
321
+ const rows = target.admin
322
+ ? target.backend.adminGetQuery(q.ref._path, q._spec)
323
+ : target.backend.getQuery(authFor(target), q.ref._path, q._spec);
324
+ return buildSandboxQuerySnap(target, q.ref, rows);
325
+ }
326
+ // Prod — q._fbQuery was built via fb.query() at construction time.
327
+ const fbQ = q._fbQuery ?? q.ref;
328
+ const snap = await fb.get(fbQ);
329
+ return wrapFbSnap(snap, target, q.ref);
330
+ }
331
+ const ref0 = r;
332
+ const target = targetOf(ref0);
333
+ if (isSandboxKind(target)) {
334
+ const val = target.admin
335
+ ? target.backend.adminGet(ref0._path)
336
+ : target.backend.get(authFor(target), ref0._path);
337
+ return buildSandboxSnap(target, ref0, val);
338
+ }
339
+ const snap = await fb.get(ref0);
340
+ return wrapFbSnap(snap, target, ref0);
341
+ }
342
+ /**
343
+ * `set(ref, value)` — replace the value at `ref`'s path. `null`
344
+ * deletes (matches the RTDB invariant — locked by oracle observation
345
+ * `rtdb-remove-vs-set-null.json`).
346
+ *
347
+ * `serverTimestamp()` sentinels are resolved at write time on the
348
+ * sandbox side; the prod side relies on `firebase/database`'s wire
349
+ * encoder.
350
+ */
351
+ export async function set(r, value) {
352
+ const target = targetOf(r);
353
+ if (isSandboxKind(target)) {
354
+ if (target.admin) {
355
+ target.backend.adminSet(r._path, value);
356
+ }
357
+ else {
358
+ target.backend.set(authFor(target), r._path, value);
359
+ }
360
+ return;
361
+ }
362
+ await fb.set(r, value);
363
+ }
364
+ /**
365
+ * `update(ref, values)` — partial update.
366
+ *
367
+ * - When `values` keys contain `/`, the call is a **multi-path atomic
368
+ * update**: every listed path is written as one transaction (any
369
+ * denial fails the whole batch).
370
+ * - Otherwise it's a **shallow merge** at the ref's path: each
371
+ * top-level key replaces the corresponding child. `null` values
372
+ * delete.
373
+ *
374
+ * Both behaviors are sandbox-implemented per the RtdbBackend's
375
+ * `update` method (`rtdb-modular`-spec atomic claim, matrix row #23).
376
+ */
377
+ export async function update(r, values) {
378
+ const target = targetOf(r);
379
+ if (isSandboxKind(target)) {
380
+ if (target.admin) {
381
+ target.backend.adminUpdate(r._path, values);
382
+ }
383
+ else {
384
+ target.backend.update(authFor(target), r._path, values);
385
+ }
386
+ return;
387
+ }
388
+ await fb.update(r, values);
389
+ }
390
+ /**
391
+ * `remove(ref)` — delete the subtree at the ref's path.
392
+ *
393
+ * RTDB invariant (oracle: `rtdb-remove-vs-set-null.json`): equivalent
394
+ * to `set(ref, null)`. The sandbox backend dispatches `remove` through
395
+ * the same code path as `set(_, null)`.
396
+ */
397
+ export async function remove(r) {
398
+ const target = targetOf(r);
399
+ if (isSandboxKind(target)) {
400
+ if (target.admin) {
401
+ target.backend.adminRemove(r._path);
402
+ }
403
+ else {
404
+ target.backend.remove(authFor(target), r._path);
405
+ }
406
+ return;
407
+ }
408
+ await fb.remove(r);
409
+ }
410
+ /**
411
+ * `push(ref, value?)` — mint an auto-id child key under `ref`'s path,
412
+ * optionally writing `value` at the new child.
413
+ *
414
+ * Returns a ref at the new child path. The ref's `key` is the minted
415
+ * id (locked by oracle observation `rtdb-push-autoid-format.json`:
416
+ * 20 chars, leading `-`, lex-sortable).
417
+ *
418
+ * Production note: the key is minted **client-side** (no server
419
+ * round-trip required); it's available synchronously on the returned
420
+ * ref even when the optional write is denied by rules. The oracle
421
+ * observation confirms this — the sandbox matches.
422
+ */
423
+ export function push(r, value) {
424
+ const target = targetOf(r);
425
+ if (isSandboxKind(target)) {
426
+ // Mint the key SYNCHRONOUSLY (client-side, no rule check) so the
427
+ // returned ref + `.key` are available even if the optional write is
428
+ // later denied (DB-B7). The write is deferred onto the thenable's
429
+ // promise — a rules denial REJECTS the promise rather than throwing
430
+ // here and discarding the key.
431
+ const key = target.backend.mintKey();
432
+ const childPath = joinPath([...pathSegments(r._path), key]);
433
+ // Two refs (mirroring upstream): `thenablePushRef` gets then/catch and
434
+ // is returned; `pushRef` is a SEPARATE plain ref used as the promise's
435
+ // fulfilled value — so resolving the promise doesn't re-enter the
436
+ // thenable's own `then` (the self-reference unwrap trap).
437
+ const thenablePushRef = buildSandboxRef(target, childPath);
438
+ const pushRef = buildSandboxRef(target, childPath);
439
+ const promise = value === undefined
440
+ ? Promise.resolve(pushRef)
441
+ : set(pushRef, value).then(() => pushRef);
442
+ return makeThenable(thenablePushRef, promise);
443
+ }
444
+ const out = value === undefined
445
+ ? fb.push(r)
446
+ : fb.push(r, value);
447
+ tag(out, target);
448
+ return out;
449
+ }
450
+ /**
451
+ * Attach `then`/`catch` to a ref so it satisfies {@link ThenableReference}.
452
+ * Mirrors upstream's `thenablePushRef.then = promise.then.bind(promise)`
453
+ * (`api/Reference_impl.ts:627-629`). The ref's own fields are untouched —
454
+ * it stays a usable {@link DatabaseReference}.
455
+ */
456
+ function makeThenable(pushRef, promise) {
457
+ const thenable = pushRef;
458
+ thenable.then = promise.then.bind(promise);
459
+ thenable.catch = promise.catch.bind(promise);
460
+ return thenable;
461
+ }
462
+ /**
463
+ * Pre-mint a push key without writing. Used by callers that need the
464
+ * key for a multi-path update (`update(rootRef, { [\`/users/${key}\`]: ... })`).
465
+ * Sandbox-side: returns a freshly-minted key. Prod-side: same — the
466
+ * `push(ref).key` pattern is the documented way.
467
+ */
468
+ export function pushKey() {
469
+ return generatePushId();
470
+ }
471
+ // ─── Listeners (Tier 2) ──────────────────────────────────────────────
472
+ /**
473
+ * `onValue(ref, cb)` — subscribe to value changes at the ref's path.
474
+ *
475
+ * Fires immediately on subscribe with the current value (or
476
+ * `null` + `exists: false` for an absent path), then on every
477
+ * subsequent write that touches the path or any descendant.
478
+ *
479
+ * Returns an unsubscribe function. The unsubscribe is idempotent;
480
+ * calling it twice is a no-op.
481
+ *
482
+ * `options.onlyOnce` (DB-B12): when `true`, the listener auto-unsubscribes
483
+ * after its first fire (mirrors `api/Reference_impl.ts:975-980`).
484
+ *
485
+ * Errors path: subscribing under rules that deny the read throws the
486
+ * plain-`Error` `PERMISSION_DENIED` shape synchronously (matching the
487
+ * production behavior where the subscribe path immediately errors).
488
+ */
489
+ export function onValue(r, cb, options) {
490
+ // `onlyOnce` (DB-B12): wrap the callback so it unsubscribes itself
491
+ // after the first fire. The unsub is filled in once the real
492
+ // subscription is created below.
493
+ if (options?.onlyOnce) {
494
+ let unsub = null;
495
+ let fired = false;
496
+ const onceCb = (snap) => {
497
+ if (fired)
498
+ return;
499
+ fired = true;
500
+ // `unsub` may not be assigned yet if the initial fire is
501
+ // synchronous (the backend fires during subscribe, before
502
+ // `onValue` returns). The post-subscribe check below covers it.
503
+ if (unsub)
504
+ unsub();
505
+ cb(snap);
506
+ };
507
+ unsub = onValue(r, onceCb);
508
+ // Synchronous initial fire: `onceCb` ran before `unsub` was set, so
509
+ // remove the now-stale listener here.
510
+ if (fired)
511
+ unsub();
512
+ return fired ? () => { } : unsub;
513
+ }
514
+ // Query branch — fire only when the windowed result changes.
515
+ // Locked by oracle observation `rtdb-modular-onvalue-with-query.json`:
516
+ // a write OUTSIDE the window does NOT re-fire the listener; a write
517
+ // INSIDE or one that displaces a member DOES.
518
+ if (isQuery(r)) {
519
+ const q = r;
520
+ const target = targetOf(q.ref);
521
+ if (isSandboxKind(target)) {
522
+ return target.backend.onValue(authFor(target), q.ref._path, (raw) => {
523
+ const snap = buildSandboxSnapFromRaw(target, q.ref, raw.val);
524
+ try {
525
+ cb(snap);
526
+ }
527
+ catch {
528
+ // Listener throws are swallowed.
529
+ }
530
+ }, q._spec);
531
+ }
532
+ const fbQ = q._fbQuery ?? q.ref;
533
+ const off = fb.onValue(fbQ, (snap) => {
534
+ cb(wrapFbSnap(snap, target, q.ref));
535
+ });
536
+ return off;
537
+ }
538
+ const ref0 = r;
539
+ const target = targetOf(ref0);
540
+ if (isSandboxKind(target)) {
541
+ const wrapper = (raw) => {
542
+ const snap = buildSandboxSnapFromRaw(target, ref0, raw.val);
543
+ try {
544
+ cb(snap);
545
+ }
546
+ catch {
547
+ // Listener throws are swallowed — match `firebase/database`'s
548
+ // behavior where one observer's exception doesn't block others.
549
+ }
550
+ };
551
+ rememberWrapper(target.backend, ref0._path, 'value', cb, wrapper);
552
+ const unsub = target.backend.onValue(authFor(target), ref0._path, wrapper);
553
+ return () => {
554
+ forgetWrapper(target.backend, ref0._path, 'value', cb);
555
+ unsub();
556
+ };
557
+ }
558
+ const off = fb.onValue(ref0, (snap) => {
559
+ cb(wrapFbSnap(snap, target, ref0));
560
+ });
561
+ return off;
562
+ }
563
+ /**
564
+ * `onChildAdded(ref, cb)` — subscribe to child-added events at the
565
+ * ref's path.
566
+ *
567
+ * Semantics (locked by oracle observations under
568
+ * `scripts/oracle/observations/rtdb-modular-onchildadded-*.json`):
569
+ *
570
+ * - On subscribe, replays every existing direct child of `ref`'s path
571
+ * (one fire per existing key, in `orderByKey`-default order).
572
+ * - After subscribe, fires exactly once per new direct child write.
573
+ *
574
+ * Also accepts a {@link Query} (a `query(ref, ...)` with `orderBy*` /
575
+ * `limitTo*` constraints): child events are then computed against the
576
+ * ordered, windowed result — a child ENTERING the window fires
577
+ * `child_added`; on subscribe the current window is replayed in window
578
+ * order.
579
+ *
580
+ * Returns an unsubscribe; calling it twice is a no-op.
581
+ */
582
+ export function onChildAdded(r, cb) {
583
+ return onChildEvent(r, 'child_added', cb);
584
+ }
585
+ /**
586
+ * `onChildChanged(ref, cb)` — subscribe to child-changed events.
587
+ *
588
+ * Semantics (oracle: `rtdb-modular-onchildchanged-fires-on-update`):
589
+ *
590
+ * - No initial replay.
591
+ * - Fires when an existing direct child's value transitions to a
592
+ * NEW non-null value. Snapshot carries the NEW value.
593
+ * - Does NOT fire for added or removed children.
594
+ *
595
+ * Also accepts a {@link Query}: fires when a child that is IN the query
596
+ * window changes value (an in-window update).
597
+ */
598
+ export function onChildChanged(r, cb) {
599
+ return onChildEvent(r, 'child_changed', cb);
600
+ }
601
+ /**
602
+ * `onChildRemoved(ref, cb)` — subscribe to child-removed events.
603
+ *
604
+ * Semantics (oracle: `rtdb-modular-onchildremoved-fires-on-delete`):
605
+ *
606
+ * - No initial replay.
607
+ * - Fires when a direct child is deleted (via `remove(child)` or
608
+ * `set(child, null)`).
609
+ * - Snapshot carries the PRIOR (now-removed) value — the listener
610
+ * sees what was there before deletion.
611
+ *
612
+ * Also accepts a {@link Query}: a child LEAVING the query window (e.g.
613
+ * displaced past a `limitTo*` boundary or filtered out) fires
614
+ * `child_removed` carrying its prior value.
615
+ */
616
+ export function onChildRemoved(r, cb) {
617
+ return onChildEvent(r, 'child_removed', cb);
618
+ }
619
+ /**
620
+ * `onChildMoved(ref, cb)` — subscribe to child-moved events.
621
+ *
622
+ * Semantics (oracle: `rtdb-modular-onchildmoved-with-orderby`):
623
+ *
624
+ * - Only fires under an ordered query (`query(ref, orderByChild(...))`).
625
+ * - Under a plain ref, this listener is effectively a no-op — the
626
+ * upstream SDK accepts the subscription but never fires it
627
+ * (matches RTDB docs).
628
+ *
629
+ * Accepts a {@link Query} WITHOUT throwing, but the sandbox deliberately
630
+ * does NOT fire `child_moved` on reorder yet: prod fires here (matrix row
631
+ * `rtdb-modular#137`) while the sandbox holds — the reorder /
632
+ * `previousChildName` ordering semantics are pending two new oracle
633
+ * captures. This is a documented, pinned divergence (both sides asserted
634
+ * in `test/database/modular/sandbox-child-events.test.ts`).
635
+ */
636
+ export function onChildMoved(r, cb) {
637
+ return onChildEvent(r, 'child_moved', cb);
638
+ }
639
+ /**
640
+ * Map from a user-supplied callback to the wrapper the backend actually
641
+ * stored. Used by `off(ref, eventType, userCb)` to find the wrapper to
642
+ * remove — otherwise the user's callback identity wouldn't match the
643
+ * backend's registered listener.
644
+ *
645
+ * Keyed by `(backend, path, event, userCb)` — same user-cb can subscribe
646
+ * to multiple paths/events under different wrappers. The `WeakMap` outer
647
+ * layer is on the backend so removing a sandbox releases the inner refs.
648
+ */
649
+ const wrapperRegistry = new WeakMap();
650
+ function registryKey(path, event, userCb) {
651
+ // Identity by cb-object — JS `Map` keys can be objects but we need a
652
+ // string-shaped composite. Use a Symbol-keyed identity weakRefId. The
653
+ // simplest approach: assign each unique user-cb a numeric id once.
654
+ const id = idForCb(userCb);
655
+ return `${path}${event}${id}`;
656
+ }
657
+ let nextCbId = 1;
658
+ const cbIds = new WeakMap();
659
+ function idForCb(cb) {
660
+ let id = cbIds.get(cb);
661
+ if (id === undefined) {
662
+ id = nextCbId++;
663
+ cbIds.set(cb, id);
664
+ }
665
+ return id;
666
+ }
667
+ function rememberWrapper(backend, path, event, userCb, wrapper) {
668
+ let map = wrapperRegistry.get(backend);
669
+ if (!map) {
670
+ map = new Map();
671
+ wrapperRegistry.set(backend, map);
672
+ }
673
+ map.set(registryKey(path, event, userCb), wrapper);
674
+ }
675
+ function lookupWrapper(backend, path, event, userCb) {
676
+ return wrapperRegistry.get(backend)?.get(registryKey(path, event, userCb));
677
+ }
678
+ function forgetWrapper(backend, path, event, userCb) {
679
+ wrapperRegistry.get(backend)?.delete(registryKey(path, event, userCb));
680
+ }
681
+ /**
682
+ * Internal shared implementation for the four `onChild*` variants.
683
+ *
684
+ * Accepts a plain {@link DatabaseReference} OR a {@link Query}
685
+ * (a `query(ref, ...)` with `orderBy*` / `limitTo*`). For a query, the
686
+ * child-event diff is computed against the ordered, windowed result rather
687
+ * than the raw child
688
+ * key-set — a child entering/leaving the window fires `child_added` /
689
+ * `child_removed`, an in-window value change fires `child_changed`. (Note
690
+ * `child_moved` on a query registers but does not fire on reorder — the
691
+ * reorder semantics are held pending fresh oracle captures.)
692
+ */
693
+ function onChildEvent(r, event, cb) {
694
+ // Unwrap a Query into its base ref + spec; a plain ref has no spec.
695
+ const isQ = isQuery(r);
696
+ const baseRef = isQ ? r.ref : r;
697
+ const spec = isQ ? r._spec : undefined;
698
+ const target = targetOf(baseRef);
699
+ if (isSandboxKind(target)) {
700
+ const wrapper = (raw) => {
701
+ // Synthesize a snapshot rooted at the child path so `snap.key`
702
+ // and `snap.val()` match the upstream `onChildAdded` snapshot
703
+ // shape (key = the child's key, val = the child's value).
704
+ const childRef = child(baseRef, raw.key);
705
+ const snap = buildSandboxSnapFromRaw(target, childRef, raw.val);
706
+ try {
707
+ cb(snap);
708
+ }
709
+ catch {
710
+ // Listener throws are swallowed — match `firebase/database`'s
711
+ // behavior where one observer's exception doesn't block others.
712
+ }
713
+ };
714
+ rememberWrapper(target.backend, baseRef._path, event, cb, wrapper);
715
+ const unsub = target.backend.onChild(authFor(target), event, baseRef._path, wrapper, spec);
716
+ return () => {
717
+ forgetWrapper(target.backend, baseRef._path, event, cb);
718
+ unsub();
719
+ };
720
+ }
721
+ const handler = (snap) => {
722
+ cb(wrapFbSnap(snap, target, child(baseRef, snap.key ?? '')));
723
+ };
724
+ // Prod: subscribe against the fb Query when one was built at construction
725
+ // time, else the plain fb ref.
726
+ const fbListenTarget = (isQ
727
+ ? (r._fbQuery ?? baseRef)
728
+ : baseRef);
729
+ switch (event) {
730
+ case 'child_added':
731
+ return fb.onChildAdded(fbListenTarget, handler);
732
+ case 'child_changed':
733
+ return fb.onChildChanged(fbListenTarget, handler);
734
+ case 'child_removed':
735
+ return fb.onChildRemoved(fbListenTarget, handler);
736
+ case 'child_moved':
737
+ return fb.onChildMoved(fbListenTarget, handler);
738
+ }
739
+ }
740
+ /**
741
+ * `off(ref, eventType?, callback?)` — unsubscribe variant.
742
+ *
743
+ * Semantics (locked by oracle observation
744
+ * `scripts/oracle/observations/rtdb-modular-off-stops-child-fires.json`):
745
+ *
746
+ * - `off(ref)` (no eventType) removes ALL listeners at that ref —
747
+ * value + every child event variety.
748
+ * - `off(ref, 'value')` removes only `value` listeners.
749
+ * - `off(ref, 'child_added')` (or any child event type) removes only
750
+ * that variety.
751
+ * - `off(ref, eventType, cb)` removes only the matching callback.
752
+ *
753
+ * The returned-unsubscribe pattern from `onValue` / `onChild*` is
754
+ * functionally equivalent to `off(ref, eventType, cb)` for a specific
755
+ * registration — both are supported.
756
+ */
757
+ export function off(r, eventType, callback) {
758
+ const target = targetOf(r);
759
+ if (isSandboxKind(target)) {
760
+ if (callback !== undefined && eventType !== undefined) {
761
+ // Translate the user-supplied callback to the wrapper actually
762
+ // registered with the backend.
763
+ const wrapper = lookupWrapper(target.backend, r._path, eventType, callback);
764
+ if (wrapper !== undefined) {
765
+ target.backend.off(r._path, eventType, wrapper);
766
+ forgetWrapper(target.backend, r._path, eventType, callback);
767
+ }
768
+ // If no wrapper was found, the user-cb wasn't registered against
769
+ // this ref + eventType — no-throw, matches upstream behavior.
770
+ return;
771
+ }
772
+ target.backend.off(r._path, eventType, undefined);
773
+ return;
774
+ }
775
+ fb.off(r, eventType, callback);
776
+ }
777
+ // ─── Queries (Tier 3) ────────────────────────────────────────────────
778
+ /**
779
+ * `query(ref, ...constraints)` — wrap a ref in an immutable
780
+ * constraint chain. The resulting {@link Query} routes through
781
+ * {@link get}/{@link onValue} and applies the ordering + filtering +
782
+ * limit pipeline on the sandbox backend; on prod it delegates to
783
+ * `firebase/database`'s `query()`.
784
+ *
785
+ * Chaining is supported — `query(query(ref, orderByChild('x')),
786
+ * limitToFirst(2))` folds both constraints into one spec.
787
+ *
788
+ * Locked semantics (oracle):
789
+ * - `orderByChild('p') + startAt(v) + endAt(w)` is BOTH-inclusive
790
+ * (`rtdb-modular-orderbychild-window.json`).
791
+ * - `orderByKey() + startAt('b') + endAt('d')` matches `[b, c, d]`
792
+ * (`rtdb-modular-orderbykey-window.json`).
793
+ * - `orderByValue() + limitToFirst(3)` returns the 3 smallest by
794
+ * value (`rtdb-modular-orderbyvalue-numeric.json` — note: prod
795
+ * requires `.indexOn: ".value"`; sandbox does not enforce indexes).
796
+ * - `orderByChild('group') + equalTo('b')` returns ALL matching
797
+ * children (`rtdb-modular-equalTo-filter.json`).
798
+ * - `limitToFirst(N)` / `limitToLast(N)` take from the start / end of
799
+ * the ordered window (`rtdb-modular-limittofirst-vs-limittolast.json`).
800
+ * - `startAfter` / `endBefore` are EXCLUSIVE
801
+ * (`rtdb-modular-startafter-endbefore-exclusive.json`).
802
+ */
803
+ export function query(refOrQuery, ...constraints) {
804
+ // Resolve base — could be a ref or a prior query (chaining).
805
+ let baseRef;
806
+ let baseSpec;
807
+ let basePriorFbQuery;
808
+ if (isQuery(refOrQuery)) {
809
+ const prior = refOrQuery;
810
+ baseRef = prior.ref;
811
+ baseSpec = prior._spec;
812
+ basePriorFbQuery = prior._fbQuery;
813
+ }
814
+ else {
815
+ baseRef = refOrQuery;
816
+ baseSpec = emptySpec();
817
+ }
818
+ let spec = baseSpec;
819
+ for (const c of constraints) {
820
+ spec = applyConstraint(spec, c[CONSTRAINT_SYMBOL]);
821
+ }
822
+ // Prod branch — chain into fb.query so the wire encoder + index
823
+ // checks happen in the upstream SDK exactly as a non-shim consumer
824
+ // would see them.
825
+ const target = targetOf(baseRef);
826
+ let fbQuery;
827
+ if (target.kind === 'prod') {
828
+ const fbBase = (basePriorFbQuery ?? baseRef);
829
+ fbQuery = constraints.length === 0
830
+ ? fbBase
831
+ : fb.query(fbBase, ...constraints.map(toFbConstraint));
832
+ }
833
+ const q = {
834
+ ref: baseRef,
835
+ _spec: spec,
836
+ _fbQuery: fbQuery,
837
+ [QUERY_SYMBOL]: true,
838
+ toString() {
839
+ return baseRef.toString();
840
+ },
841
+ };
842
+ return q;
843
+ }
844
+ /** `orderByChild('path')` — order children by the value at the nested
845
+ * child path. Locked by oracle observation
846
+ * `rtdb-modular-orderbychild-window.json`. */
847
+ export function orderByChild(path) {
848
+ return buildConstraint('orderByChild', {
849
+ kind: 'orderBy',
850
+ spec: { kind: 'child', path },
851
+ });
852
+ }
853
+ /** `orderByKey()` — order children lexicographically by key string.
854
+ * Locked by oracle observation `rtdb-modular-orderbykey-window.json`. */
855
+ export function orderByKey() {
856
+ return buildConstraint('orderByKey', {
857
+ kind: 'orderBy',
858
+ spec: { kind: 'key' },
859
+ });
860
+ }
861
+ /** `orderByValue()` — order children by primitive value. Prod requires
862
+ * `.indexOn: ".value"` (oracle: `rtdb-modular-orderbyvalue-numeric.json`
863
+ * threw `Index not defined` against blockingfun); sandbox does NOT
864
+ * enforce indexes (the rules engine here checks read-allow only, not
865
+ * query-index conformance). */
866
+ export function orderByValue() {
867
+ return buildConstraint('orderByValue', {
868
+ kind: 'orderBy',
869
+ spec: { kind: 'value' },
870
+ });
871
+ }
872
+ /** `startAt(value, key?)` — INCLUSIVE lower bound under the active
873
+ * ordering. Optional `key` is the tie-breaker when ordering by
874
+ * child/value and multiple children share the bound's value. */
875
+ export function startAt(value, key) {
876
+ return buildConstraint('startAt', {
877
+ kind: 'bound',
878
+ bound: { kind: 'startAt', value, key },
879
+ });
880
+ }
881
+ /** `startAfter(value, key?)` — EXCLUSIVE lower bound. Locked by
882
+ * `rtdb-modular-startafter-endbefore-exclusive.json`. */
883
+ export function startAfter(value, key) {
884
+ return buildConstraint('startAfter', {
885
+ kind: 'bound',
886
+ bound: { kind: 'startAfter', value, key },
887
+ });
888
+ }
889
+ /** `endAt(value, key?)` — INCLUSIVE upper bound. Adjacent to startAt;
890
+ * same key tie-breaker semantics. */
891
+ export function endAt(value, key) {
892
+ return buildConstraint('endAt', {
893
+ kind: 'bound',
894
+ bound: { kind: 'endAt', value, key },
895
+ });
896
+ }
897
+ /** `endBefore(value, key?)` — EXCLUSIVE upper bound. Locked by
898
+ * `rtdb-modular-startafter-endbefore-exclusive.json`. */
899
+ export function endBefore(value, key) {
900
+ return buildConstraint('endBefore', {
901
+ kind: 'bound',
902
+ bound: { kind: 'endBefore', value, key },
903
+ });
904
+ }
905
+ /** `equalTo(value, key?)` — sugar for `startAt(value, key) +
906
+ * endAt(value, key)`. Returns ALL matching children (no uniqueness).
907
+ * Locked by oracle observation `rtdb-modular-equalTo-filter.json`. */
908
+ export function equalTo(value, key) {
909
+ return buildConstraint('equalTo', {
910
+ kind: 'bound',
911
+ bound: { kind: 'equalTo', value, key },
912
+ });
913
+ }
914
+ /** `limitToFirst(n)` — keep the first N children of the ordered window.
915
+ * Locked by oracle observation `rtdb-modular-limittofirst-vs-limittolast.json`. */
916
+ export function limitToFirst(n) {
917
+ return buildConstraint('limitToFirst', {
918
+ kind: 'limit',
919
+ limitKind: 'limitToFirst',
920
+ n,
921
+ });
922
+ }
923
+ /** `limitToLast(n)` — keep the last N children of the ordered window.
924
+ * Locked by oracle observation `rtdb-modular-limittofirst-vs-limittolast.json`. */
925
+ export function limitToLast(n) {
926
+ return buildConstraint('limitToLast', {
927
+ kind: 'limit',
928
+ limitKind: 'limitToLast',
929
+ n,
930
+ });
931
+ }
932
+ /**
933
+ * `runTransaction(ref, transactionUpdate, options?)` — atomic
934
+ * read-modify-write.
935
+ *
936
+ * Contract (oracle-locked):
937
+ *
938
+ * 1. `transactionUpdate` is called with the CURRENT value at `ref`'s
939
+ * path. For an absent path the arg is `null` (NOT `undefined`);
940
+ * oracle:
941
+ * `rtdb-modular-runtransaction-current-value-arg.json` →
942
+ * `missingFirstWasNull: true`.
943
+ * 2. Returning `undefined` from the update fn ABORTS the transaction:
944
+ * resolves `{ committed: false, snapshot }` where the snapshot is
945
+ * the pre-transaction value; oracle:
946
+ * `rtdb-modular-runtransaction-abort-undefined.json` → `committed:
947
+ * false, snapVal: null`.
948
+ * 3. Returning any defined value WRITES that value (rules-checked);
949
+ * resolves `{ committed: true, snapshot }` where `snapshot.val()`
950
+ * is the committed value; oracle:
951
+ * `rtdb-modular-runtransaction-success.json` → `committedNewValue:
952
+ * true` and
953
+ * `rtdb-modular-runtransaction-returns-committed-snapshot.json`.
954
+ * 4. If rules deny the write, the promise REJECTS with a plain
955
+ * `Error` whose `message === 'permission_denied'` and NO `.code`
956
+ * field (distinct from `set`/`get`'s `'PERMISSION_DENIED:
957
+ * Permission denied'`); oracle:
958
+ * `rtdb-modular-runtransaction-on-rules-denied-path.json`.
959
+ *
960
+ * `options.applyLocally` (default `true`): when `false`, the
961
+ * intermediate optimistic value is NOT fanned out to listeners — they
962
+ * see only the committed value. In a single-client harness this is
963
+ * usually invisible; we honor the flag for prod-parity. Oracle
964
+ * observation `rtdb-modular-runtransaction-options-applylocally.json`
965
+ * confirms both branches commit and end at the same value; the
966
+ * intermediate-fire difference isn't observable from a single client.
967
+ *
968
+ * Single-client sandbox doesn't model concurrency conflicts; the
969
+ * documented "retry on conflict" path is degenerate (no other writer
970
+ * exists to conflict with). The fn is invoked once.
971
+ */
972
+ export async function runTransaction(r, transactionUpdate, options) {
973
+ const target = targetOf(r);
974
+ if (isSandboxKind(target)) {
975
+ const result = target.backend.runTransaction(authFor(target), r._path, transactionUpdate, options);
976
+ const snap = buildSandboxSnapFromRaw(target, r, result.val);
977
+ return { committed: result.committed, snapshot: snap };
978
+ }
979
+ const fbResult = await fb.runTransaction(r, transactionUpdate, options);
980
+ return {
981
+ committed: fbResult.committed,
982
+ snapshot: wrapFbSnap(fbResult.snapshot, target, r),
983
+ };
984
+ }
985
+ // ─── Sentinels ───────────────────────────────────────────────────────
986
+ /**
987
+ * `serverTimestamp()` — returns the `{ ".sv": "timestamp" }` sentinel
988
+ * the wire encoder recognises. Resolves to `Date.now()` (epoch ms) on
989
+ * write — locked by the prod SDK's resolved-as-number contract
990
+ * (oracle: `rtdb-servertimestamp-resolves.json`).
991
+ *
992
+ * Same shape across targets: the sandbox backend recognises the
993
+ * marker; the prod backend's wire encoder does too. Agent code that
994
+ * imports `serverTimestamp` from `@pyric/rtdb` works identically on
995
+ * either target.
996
+ */
997
+ export function serverTimestamp() {
998
+ return serverTimestampSentinel();
999
+ }
1000
+ /**
1001
+ * `increment(delta)` — returns the `{ ".sv": { increment: delta } }`
1002
+ * sentinel that atomically adds `delta` to the current value at the
1003
+ * write's field. Starts from `0` when the field is absent or
1004
+ * non-numeric (oracle: `rtdb-modular-increment-from-missing.json`).
1005
+ *
1006
+ * Same shape across targets: the sandbox backend resolves it against the
1007
+ * field's prior value at write time; the prod backend's wire encoder
1008
+ * recognises the marker. Mirrors `firebase/database`'s `increment`
1009
+ * (`api/ServerValue.ts:38-44`).
1010
+ */
1011
+ export function increment(delta) {
1012
+ return incrementSentinel(delta);
1013
+ }
1014
+ // ─── Emulator (no-op on sandbox) ─────────────────────────────────────
1015
+ /**
1016
+ * `connectDatabaseEmulator(db, host, port)` — point a prod handle at
1017
+ * a Firebase emulator. No-op on sandbox handles (the sandbox IS a
1018
+ * local emulator); the call is still accepted so consumer code that
1019
+ * does the wiring unconditionally compiles against both targets.
1020
+ */
1021
+ export function connectDatabaseEmulator(db, host, port,
1022
+ // The modular SDK's signature lets you pass an optional namespace
1023
+ // (multi-DB projects). We accept-and-forward.
1024
+ options) {
1025
+ const target = targetOf(db);
1026
+ if (isSandboxKind(target))
1027
+ return;
1028
+ fb.connectDatabaseEmulator(target.db, host, port, options);
1029
+ }
1030
+ // ─── Sandbox-only ops ───────────────────────────────────────────────
1031
+ //
1032
+ // Mirrors `pyric/firestore`'s `sandbox` namespace — explicit
1033
+ // per-package sandbox lifecycle that the prod target doesn't ship.
1034
+ // Calling against a prod handle throws.
1035
+ export const sandbox = {
1036
+ /**
1037
+ * Replace deployed rules. Pass `null` to clear (sandbox returns to
1038
+ * default-allow). Rules are evaluated through the existing
1039
+ * `@pyric/rtdb` simulator — same engine as `simulate()` /
1040
+ * `rtdb_simulate_access`.
1041
+ *
1042
+ * @example
1043
+ * ```ts
1044
+ * sandbox.setRules(db, {
1045
+ * rules: {
1046
+ * '.read': 'auth != null',
1047
+ * '.write': 'auth != null',
1048
+ * },
1049
+ * });
1050
+ * ```
1051
+ */
1052
+ setRules(db, rulesJson) {
1053
+ const target = targetOf(db);
1054
+ if (!isSandboxKind(target)) {
1055
+ throw new Error('sandbox.setRules is sandbox-only.');
1056
+ }
1057
+ target.backend.setRules(rulesJson);
1058
+ },
1059
+ /**
1060
+ * Bulk-load data bypassing rules. The supplied map's keys are
1061
+ * absolute paths (`'/users/alice'`) and the values land at those
1062
+ * paths. Convenient for test fixtures.
1063
+ */
1064
+ setData(db, data) {
1065
+ const target = targetOf(db);
1066
+ if (!isSandboxKind(target)) {
1067
+ throw new Error('sandbox.setData is sandbox-only.');
1068
+ }
1069
+ target.backend.setData(data);
1070
+ },
1071
+ /** Snapshot the full sandbox tree (rule-bypass read). Usually a keyed
1072
+ * object; may be a primitive when the root holds one (DB-B13). */
1073
+ snapshotState(db) {
1074
+ const target = targetOf(db);
1075
+ if (!isSandboxKind(target)) {
1076
+ throw new Error('sandbox.snapshotState is sandbox-only.');
1077
+ }
1078
+ return target.backend.snapshotState();
1079
+ },
1080
+ };
1081
+ // ─── Snapshot wrappers ───────────────────────────────────────────────
1082
+ function buildSandboxSnap(target, refForSnap, val) {
1083
+ return buildSandboxSnapFromRaw(target, refForSnap, val);
1084
+ }
1085
+ function buildSandboxSnapFromRaw(_target, refForSnap, val) {
1086
+ const exists = val !== null;
1087
+ // `val` is the STORED (integer-keyed) shape. Structural ops
1088
+ // (`child`/`forEach`/`hasChildren`/`numChildren`) walk it directly;
1089
+ // `val()`/`toJSON()` render the DB-B2 array coercion lazily so a list
1090
+ // written as an array reads back as an array.
1091
+ const coerced = coerceArrays(val);
1092
+ const childCount = (val !== null && typeof val === 'object' && !Array.isArray(val))
1093
+ ? Object.keys(val).length
1094
+ : 0;
1095
+ return {
1096
+ key: refForSnap.key,
1097
+ ref: refForSnap,
1098
+ size: childCount,
1099
+ priority: null,
1100
+ exists() { return exists; },
1101
+ val() { return coerced; },
1102
+ child(p) {
1103
+ const segs = pathSegments(p);
1104
+ let cur = val;
1105
+ for (const s of segs) {
1106
+ if (cur === null || typeof cur !== 'object' || Array.isArray(cur)) {
1107
+ cur = null;
1108
+ break;
1109
+ }
1110
+ cur = cur[s] ?? null;
1111
+ }
1112
+ const childRef = child(refForSnap, p);
1113
+ return buildSandboxSnapFromRaw(_target, childRef, cur);
1114
+ },
1115
+ hasChild(p) {
1116
+ return this.child(p).exists();
1117
+ },
1118
+ hasChildren() {
1119
+ return val !== null && typeof val === 'object' && !Array.isArray(val)
1120
+ && Object.keys(val).length > 0;
1121
+ },
1122
+ exportVal() { return coerced; },
1123
+ toJSON() { return coerced; },
1124
+ forEach(cb) {
1125
+ if (val === null || typeof val !== 'object' || Array.isArray(val))
1126
+ return false;
1127
+ for (const [k, v] of Object.entries(val)) {
1128
+ const childRef = child(refForSnap, k);
1129
+ const childSnap = buildSandboxSnapFromRaw(_target, childRef, v);
1130
+ if (cb(childSnap) === true)
1131
+ return true;
1132
+ }
1133
+ return false;
1134
+ },
1135
+ };
1136
+ }
1137
+ /**
1138
+ * Build a snapshot from a query result. Differs from
1139
+ * {@link buildSandboxSnapFromRaw} in that the children iterate in the
1140
+ * order the executor produced them (not insertion order).
1141
+ *
1142
+ * `val()` returns a `Record<string, JsonValue>` containing only the
1143
+ * windowed children (or `null` if the window is empty), matching
1144
+ * `firebase/database`'s `DataSnapshot.val()` on a query snap.
1145
+ *
1146
+ * `numChildren()` is the window size; `forEach` walks the ordered rows.
1147
+ */
1148
+ function buildSandboxQuerySnap(target, refForSnap, rows) {
1149
+ let val;
1150
+ if (rows.length === 0) {
1151
+ val = null;
1152
+ }
1153
+ else {
1154
+ const obj = {};
1155
+ for (const { key, value } of rows)
1156
+ obj[key] = value;
1157
+ val = obj;
1158
+ }
1159
+ const exists = rows.length > 0;
1160
+ const coerced = coerceArrays(val);
1161
+ return {
1162
+ key: refForSnap.key,
1163
+ ref: refForSnap,
1164
+ size: rows.length,
1165
+ priority: null,
1166
+ exists() { return exists; },
1167
+ val() { return coerced; },
1168
+ child(p) {
1169
+ const segs = pathSegments(p);
1170
+ let cur = val;
1171
+ for (const s of segs) {
1172
+ if (cur === null || typeof cur !== 'object' || Array.isArray(cur)) {
1173
+ cur = null;
1174
+ break;
1175
+ }
1176
+ cur = cur[s] ?? null;
1177
+ }
1178
+ const childRef = child(refForSnap, p);
1179
+ return buildSandboxSnapFromRaw(target, childRef, cur);
1180
+ },
1181
+ hasChild(p) {
1182
+ return this.child(p).exists();
1183
+ },
1184
+ hasChildren() { return rows.length > 0; },
1185
+ exportVal() { return coerced; },
1186
+ toJSON() { return coerced; },
1187
+ forEach(cb) {
1188
+ for (const { key, value } of rows) {
1189
+ const childRef = child(refForSnap, key);
1190
+ const childSnap = buildSandboxSnapFromRaw(target, childRef, value);
1191
+ if (cb(childSnap) === true)
1192
+ return true;
1193
+ }
1194
+ return false;
1195
+ },
1196
+ };
1197
+ }
1198
+ /**
1199
+ * Adapt a `firebase/database` `DataSnapshot` to our minimal interface.
1200
+ *
1201
+ * The fb snap already has all the methods our `DataSnapshot` shape
1202
+ * promises; we just need a `ref` that routes through our `Database`
1203
+ * handle's target on subsequent calls. Returning `fbSnap` unchanged
1204
+ * works for everything except the ref — the snap's `.ref` is an
1205
+ * `fb.DatabaseReference` that hasn't been tagged. Tag it.
1206
+ */
1207
+ function wrapFbSnap(fbSnap, target, refForSnap) {
1208
+ // The fb snap's `.ref` is the same `fb.DatabaseReference` semantically
1209
+ // identical to what we built in `get(r)`. Tag it so chained ops
1210
+ // through `snap.ref` route correctly.
1211
+ tag(fbSnap.ref, target);
1212
+ return new Proxy(fbSnap, {
1213
+ get(t, prop) {
1214
+ if (prop === 'ref')
1215
+ return refForSnap;
1216
+ // Forward through to the fb snap for everything else; bind
1217
+ // methods so `this` stays the fb snap (it relies on private
1218
+ // state).
1219
+ const v = t[prop];
1220
+ if (typeof v === 'function')
1221
+ return v.bind(t);
1222
+ return v;
1223
+ },
1224
+ });
1225
+ }
1226
+ //# sourceMappingURL=modular.js.map