@pyric/cli 0.1.0-alpha.11 → 0.1.0-alpha.12

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 (301) hide show
  1. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  2. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  3. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  4. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  5. package/dist/conformance/.generated/can-i-use.js +2 -2
  6. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  7. package/dist/serve/docs-ui/docs/_rhythm/index.html +1 -1
  8. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +1 -1
  9. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +1 -1
  10. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +1 -1
  11. package/dist/serve/docs-ui/docs/ai-compat/index.html +1 -1
  12. package/dist/serve/docs-ui/docs/api-reference/index.html +2 -2
  13. package/dist/serve/docs-ui/docs/api-reference.md +1 -1
  14. package/dist/serve/docs-ui/docs/app-compat/index.html +1 -1
  15. package/dist/serve/docs-ui/docs/auth-compat/index.html +1 -1
  16. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +1 -1
  17. package/dist/serve/docs-ui/docs/build/authentication/index.html +1 -1
  18. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +1 -1
  19. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +1 -1
  20. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +1 -1
  21. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +1 -1
  22. package/dist/serve/docs-ui/docs/conformance-scores/index.html +1 -1
  23. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +1 -1
  24. package/dist/serve/docs-ui/docs/database-compat/index.html +1 -1
  25. package/dist/serve/docs-ui/docs/firestore-compat/index.html +1 -1
  26. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +1 -1
  27. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  28. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +1 -1
  29. package/dist/serve/docs-ui/docs/index.json +200 -25
  30. package/dist/serve/docs-ui/docs/messaging-compat/index.html +1 -1
  31. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +1 -1
  32. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +1 -1
  33. package/dist/serve/docs-ui/docs/overview/index.html +1 -1
  34. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  35. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  36. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  37. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  38. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
  39. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
  40. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  41. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +1 -1
  42. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  43. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +1 -1
  44. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +1 -1
  45. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  46. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  47. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  48. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  49. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  50. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  51. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  52. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  53. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  54. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  55. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  56. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +131 -66
  57. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +130 -65
  58. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  59. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +1 -1
  60. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1 -1
  61. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1 -1
  62. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  63. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  64. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +1 -1
  65. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
  66. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  67. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +37 -14
  68. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +28 -8
  69. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +1 -1
  70. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  71. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  72. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  73. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  74. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  75. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  76. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  77. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  78. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  79. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  80. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  81. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  82. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
  83. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  84. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  85. package/dist/serve/docs-ui/docs/rules-compat/index.html +1 -1
  86. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +1 -1
  87. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  88. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +1 -1
  89. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  90. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +1 -1
  91. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  92. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +1 -1
  93. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  94. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +1 -1
  95. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +1 -1
  96. package/dist/serve/docs-ui/docs/storage-compat/index.html +1 -1
  97. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  98. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  99. package/dist/serve/docs-ui/llms.txt +1 -1
  100. package/dist/serve/worker/host/core.js +1 -1
  101. package/dist/serve/worker/host/core.js.map +1 -1
  102. package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
  103. package/dist/serve/worker/host/firestore-writes.js +3 -2
  104. package/dist/serve/worker/host/firestore-writes.js.map +1 -1
  105. package/dist/serve/worker/index.d.ts +2 -1
  106. package/dist/serve/worker/index.d.ts.map +1 -1
  107. package/dist/serve/worker/index.js +2 -1
  108. package/dist/serve/worker/index.js.map +1 -1
  109. package/dist/serve/worker/protocol.js +2 -2
  110. package/dist/serve/worker/protocol.js.map +1 -1
  111. package/package.json +5 -4
  112. package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
  113. package/src/assurance/attachment.ts +211 -0
  114. package/src/assurance/browser.ts +80 -0
  115. package/src/assurance/campaign.ts +496 -0
  116. package/src/assurance/capabilities.ts +446 -0
  117. package/src/assurance/cases.ts +43 -0
  118. package/src/assurance/index.ts +75 -0
  119. package/src/assurance/runner.ts +885 -0
  120. package/src/assurance/tool-names.ts +15 -0
  121. package/src/assurance/tools.ts +830 -0
  122. package/src/assurance/types.ts +352 -0
  123. package/src/assurance/validation.ts +434 -0
  124. package/src/bridge/client/bridge.ts +550 -0
  125. package/src/bridge/client/dispatch.ts +137 -0
  126. package/src/bridge/client.ts +45 -0
  127. package/src/bridge/protocol.ts +351 -0
  128. package/src/bridge/server/audit.ts +53 -0
  129. package/src/bridge/server/bridge.ts +597 -0
  130. package/src/bridge/server/headless.ts +160 -0
  131. package/src/bridge/server/json-schema-to-zod.ts +108 -0
  132. package/src/bridge/server/local-bridge.ts +66 -0
  133. package/src/bridge/server/logger.ts +50 -0
  134. package/src/bridge/server/mcp-contract.ts +93 -0
  135. package/src/bridge/server/mcp.ts +129 -0
  136. package/src/bridge/server/peer.ts +232 -0
  137. package/src/bridge/server/standalone.ts +347 -0
  138. package/src/bridge/server/tool-metadata.ts +99 -0
  139. package/src/bridge/server.ts +28 -0
  140. package/src/cli/can-i-use.ts +50 -0
  141. package/src/cli/cli.test.ts +493 -0
  142. package/src/cli/database-rules.ts +329 -0
  143. package/src/cli/dev-runner.ts +282 -0
  144. package/src/cli/firebase-json.ts +100 -0
  145. package/src/cli/firestore-indexes.ts +70 -0
  146. package/src/cli/index.ts +425 -0
  147. package/src/cli/init.ts +260 -0
  148. package/src/cli/mcp-proxy.ts +196 -0
  149. package/src/cli/parse-args.ts +80 -0
  150. package/src/cli/rules.ts +259 -0
  151. package/src/cli/scope.ts +67 -0
  152. package/src/cli/serve.ts +996 -0
  153. package/src/cli/service-commands.ts +73 -0
  154. package/src/cli/snapshot.ts +164 -0
  155. package/src/cli/storage-rules.ts +172 -0
  156. package/src/cli/verify.ts +416 -0
  157. package/src/conformance/.generated/can-i-use-browser.ts +113 -0
  158. package/src/conformance/.generated/can-i-use.ts +117 -0
  159. package/src/conformance/.generated/conformance-docs.ts +14 -0
  160. package/src/conformance/browser.ts +24 -0
  161. package/src/conformance/can-i-use-tool.ts +51 -0
  162. package/src/conformance/can-i-use.ts +18 -0
  163. package/src/conformance/docs.ts +8 -0
  164. package/src/conformance/index.ts +20 -0
  165. package/src/conformance/tools.ts +16 -0
  166. package/src/credentials/core/memoize-ttl.ts +142 -0
  167. package/src/credentials/core/types.ts +10 -0
  168. package/src/credentials/node/from-adc.ts +96 -0
  169. package/src/credentials/node/from-service-account.ts +133 -0
  170. package/src/credentials/node/index.ts +6 -0
  171. package/src/discover/concurrency.ts +127 -0
  172. package/src/discover/crawler-adapter.ts +142 -0
  173. package/src/discover/crawler.ts +1127 -0
  174. package/src/discover/credential-free.ts +27 -0
  175. package/src/discover/findCollectionGroup.ts +131 -0
  176. package/src/discover/firestore-source.ts +59 -0
  177. package/src/discover/index.ts +5 -0
  178. package/src/discover/merge.ts +523 -0
  179. package/src/discover/session.ts +402 -0
  180. package/src/discover/tools.ts +201 -0
  181. package/src/discover/types.ts +187 -0
  182. package/src/discover/wire.ts +324 -0
  183. package/src/functions-rtdb/child.ts +382 -0
  184. package/src/functions-rtdb/delivery.ts +7 -0
  185. package/src/functions-rtdb/discovery.ts +136 -0
  186. package/src/functions-rtdb/event.ts +64 -0
  187. package/src/functions-rtdb/execution.ts +111 -0
  188. package/src/functions-rtdb/in-memory-delivery.ts +40 -0
  189. package/src/functions-rtdb/project.ts +74 -0
  190. package/src/functions-rtdb/projection.ts +104 -0
  191. package/src/functions-rtdb/reference-pattern.ts +20 -0
  192. package/src/functions-rtdb/remote-delivery.ts +23 -0
  193. package/src/pkg-version.ts +49 -0
  194. package/src/register/esm-exports.ts +63 -0
  195. package/src/register/hooks.ts +30 -0
  196. package/src/register/index.ts +150 -0
  197. package/src/register/mapping.ts +33 -0
  198. package/src/remote/index.ts +1050 -0
  199. package/src/rtdb/crawl-snapshot.ts +118 -0
  200. package/src/rtdb/inspection.ts +137 -0
  201. package/src/rtdb/load-rules-document.ts +56 -0
  202. package/src/rtdb/rules-generation-tool.ts +38 -0
  203. package/src/rtdb/rules-json.ts +29 -0
  204. package/src/serve/activity-guard.ts +29 -0
  205. package/src/serve/activity-route.ts +164 -0
  206. package/src/serve/activity-warning.ts +26 -0
  207. package/src/serve/bridge-mount.ts +200 -0
  208. package/src/serve/bundler.ts +493 -0
  209. package/src/serve/capture-store.ts +65 -0
  210. package/src/serve/discovery.ts +199 -0
  211. package/src/serve/entries/ai.ts +292 -0
  212. package/src/serve/entries/app-backend.ts +4 -0
  213. package/src/serve/entries/app-client.ts +26 -0
  214. package/src/serve/entries/app-session-store.ts +47 -0
  215. package/src/serve/entries/app.ts +11 -0
  216. package/src/serve/entries/auth-helper-core.ts +181 -0
  217. package/src/serve/entries/auth-helper-dom.ts +134 -0
  218. package/src/serve/entries/auth-helper-runtime.ts +20 -0
  219. package/src/serve/entries/auth.ts +255 -0
  220. package/src/serve/entries/bridge-url.ts +31 -0
  221. package/src/serve/entries/database.ts +129 -0
  222. package/src/serve/entries/firestore.ts +232 -0
  223. package/src/serve/entries/init.ts +46 -0
  224. package/src/serve/entries/keepalive.ts +46 -0
  225. package/src/serve/entries/messaging-sw.ts +75 -0
  226. package/src/serve/entries/messaging.ts +96 -0
  227. package/src/serve/entries/runtime.ts +540 -0
  228. package/src/serve/entries/session-store.ts +97 -0
  229. package/src/serve/entries/storage.ts +92 -0
  230. package/src/serve/entries/tab-sync-wiring.ts +274 -0
  231. package/src/serve/entries/worker-runtime.ts +75 -0
  232. package/src/serve/init-payload.ts +42 -0
  233. package/src/serve/namespace.ts +675 -0
  234. package/src/serve/open-browser.ts +68 -0
  235. package/src/serve/rules.ts +272 -0
  236. package/src/serve/sandbox-marker.ts +31 -0
  237. package/src/serve/server.ts +428 -0
  238. package/src/serve/standalone-assets.ts +180 -0
  239. package/src/serve/state-store.ts +166 -0
  240. package/src/serve/studio/disk-project-store.ts +185 -0
  241. package/src/serve/studio/disk-workspace.ts +162 -0
  242. package/src/serve/studio/index.ts +20 -0
  243. package/src/serve/studio/routes.ts +237 -0
  244. package/src/serve/studio/store-types.ts +48 -0
  245. package/src/serve/studio/studio-storage.test.ts +289 -0
  246. package/src/serve/vite-plugin.ts +1102 -0
  247. package/src/serve/worker/activity-bootstrap.ts +24 -0
  248. package/src/serve/worker/client/admin-firestore.ts +38 -0
  249. package/src/serve/worker/client/ai.ts +124 -0
  250. package/src/serve/worker/client/auth.ts +489 -0
  251. package/src/serve/worker/client/connection.ts +202 -0
  252. package/src/serve/worker/client/core.ts +350 -0
  253. package/src/serve/worker/client/disconnect.ts +45 -0
  254. package/src/serve/worker/client/firestore-reads.ts +181 -0
  255. package/src/serve/worker/client/firestore-refs.ts +226 -0
  256. package/src/serve/worker/client/firestore-writes.ts +232 -0
  257. package/src/serve/worker/client/handles.ts +91 -0
  258. package/src/serve/worker/client/messaging.ts +119 -0
  259. package/src/serve/worker/client/presence.ts +174 -0
  260. package/src/serve/worker/client/rtdb.ts +311 -0
  261. package/src/serve/worker/client/rules.ts +63 -0
  262. package/src/serve/worker/client/service-worker-connection.ts +59 -0
  263. package/src/serve/worker/client/snapshots.ts +86 -0
  264. package/src/serve/worker/client/storage.ts +195 -0
  265. package/src/serve/worker/client/studio.ts +88 -0
  266. package/src/serve/worker/client.ts +57 -0
  267. package/src/serve/worker/durable-persistence.ts +137 -0
  268. package/src/serve/worker/entry.ts +179 -0
  269. package/src/serve/worker/host/admin-firestore.ts +88 -0
  270. package/src/serve/worker/host/connection.ts +179 -0
  271. package/src/serve/worker/host/core.ts +387 -0
  272. package/src/serve/worker/host/dispatch.ts +316 -0
  273. package/src/serve/worker/host/firestore-reads.ts +117 -0
  274. package/src/serve/worker/host/firestore-writes.ts +456 -0
  275. package/src/serve/worker/host/presence.ts +312 -0
  276. package/src/serve/worker/host/rtdb.ts +136 -0
  277. package/src/serve/worker/host/rules.ts +128 -0
  278. package/src/serve/worker/host/storage.ts +312 -0
  279. package/src/serve/worker/host/studio.ts +75 -0
  280. package/src/serve/worker/host/subscriptions.ts +238 -0
  281. package/src/serve/worker/host-ai.ts +165 -0
  282. package/src/serve/worker/host-auth.ts +469 -0
  283. package/src/serve/worker/host-context.ts +273 -0
  284. package/src/serve/worker/host-events.ts +94 -0
  285. package/src/serve/worker/host-messaging.ts +240 -0
  286. package/src/serve/worker/host.ts +47 -0
  287. package/src/serve/worker/index.ts +196 -0
  288. package/src/serve/worker/presence-timing.ts +15 -0
  289. package/src/serve/worker/protocol.ts +1112 -0
  290. package/src/serve/worker/serve-init.ts +606 -0
  291. package/src/serve/worker/service-worker-channel.ts +33 -0
  292. package/src/serve/worker/service-worker-relay.ts +86 -0
  293. package/src/serve/writer-lock.ts +53 -0
  294. package/src/verify/cases.ts +233 -0
  295. package/src/verify/fixture.ts +258 -0
  296. package/src/verify/index.ts +519 -0
  297. package/src/verify/tools.ts +108 -0
  298. package/src/version/compat-target.ts +17 -0
  299. package/src/vite.ts +17 -0
  300. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -31
  301. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -29
@@ -0,0 +1,387 @@
1
+ /**
2
+ * SharedWorker host — shared resolution layer (host/core.ts).
3
+ *
4
+ * The helpers every firestore-touching family module leans on:
5
+ * - the auth-lens → live-handle resolvers (`lensDb`/`lensRtdb`/`sessionDb`/…),
6
+ * the single place a per-op `actAs` lens or a port session becomes a live
7
+ * Firestore/RTDB handle;
8
+ * - descriptor → live ref/query resolution (`resolveTarget`/`resolveConstraint`),
9
+ * used by both the read ops and the subscription handlers;
10
+ * - cross-port snapshot serialization (`serializeDocSnap`);
11
+ * - `opProvenance`, the issue-time provenance both the ambient-provenance
12
+ * window (dispatch) and the storage ops (explicit thread) read.
13
+ *
14
+ * Genuinely-shared STATE lives on `HostCtx` (host-context.ts) — the dependency
15
+ * root. This module adds the shared FUNCTIONS that resolve against that state;
16
+ * it imports the pyric firestore/database engine, so it is deliberately kept
17
+ * out of host-context.ts (which stays engine-free).
18
+ */
19
+
20
+ import {
21
+ getFirestore as pyricGetFirestore,
22
+ getAdminFirestore as pyricGetAdminFirestore,
23
+ doc as pyricDoc,
24
+ collection as pyricCollection,
25
+ collectionGroup as pyricCollectionGroup,
26
+ query as pyricQuery,
27
+ where as pyricWhere,
28
+ and as pyricAnd,
29
+ or as pyricOr,
30
+ orderBy as pyricOrderBy,
31
+ limit as pyricLimit,
32
+ limitToLast as pyricLimitToLast,
33
+ startAt as pyricStartAt,
34
+ startAfter as pyricStartAfter,
35
+ endAt as pyricEndAt,
36
+ endBefore as pyricEndBefore,
37
+ type Firestore,
38
+ type DocumentReference,
39
+ type CollectionReference,
40
+ type Query,
41
+ } from 'pyric/firestore';
42
+ import { rehydrateDocValue } from 'pyric/firestore/internal/value-codec';
43
+ import {
44
+ getDatabase as pyricGetDatabase,
45
+ getAdminDatabase as pyricGetAdminDatabase,
46
+ type Database,
47
+ } from 'pyric/database';
48
+ import type { AuthLens, EventProvenance } from 'pyric/sandbox';
49
+ import type { MintedSession } from 'pyric/auth';
50
+
51
+ import type {
52
+ InboundMessage,
53
+ TargetDescriptor,
54
+ QueryConstraintDescriptor,
55
+ } from '../protocol.js';
56
+ import { serializeDocData } from '../protocol.js';
57
+ import { type HostCtx, type PortLike } from '../host-context.js';
58
+ import { portSession } from '../host-auth.js';
59
+
60
+ // ─── Descriptor → live ref resolution ───────────────────────────────────
61
+
62
+ /**
63
+ * Resolve a TargetDescriptor into a live pyric ref or query.
64
+ *
65
+ * WHY WE RESOLVE ON THE WORKER
66
+ * The client never holds live pyric refs — it holds plain `DocRef`/
67
+ * `CollRef`/`GroupRef`/`QueryDescriptor` objects that serialize cleanly
68
+ * across the MessagePort. On every op the worker rebuilds the live ref
69
+ * from these descriptors. This keeps the client completely stateless with
70
+ * respect to sandbox internals and makes retries trivially correct.
71
+ */
72
+ export function resolveTarget(
73
+ db: Firestore,
74
+ target: TargetDescriptor,
75
+ ): DocumentReference | CollectionReference | Query {
76
+ if (target.__ref === 'doc') {
77
+ return pyricDoc(db, target.path);
78
+ }
79
+ if (target.__ref === 'collection') {
80
+ return pyricCollection(db, target.path);
81
+ }
82
+ if (target.__ref === 'group') {
83
+ return pyricCollectionGroup(db, target.collectionId);
84
+ }
85
+ // query descriptor
86
+ const source = resolveTarget(db, target.source) as CollectionReference | Query;
87
+ const constraints = target.constraints.map((c) => resolveConstraint(c));
88
+ return pyricQuery(source, ...constraints);
89
+ }
90
+
91
+ function resolveConstraint(c: QueryConstraintDescriptor): ReturnType<typeof pyricWhere> {
92
+ switch (c.kind) {
93
+ case 'where':
94
+ // Rehydrate the comparison value (same rationale as prepareWriteData,
95
+ // spike gap 4, applied to READ inputs): over the JSON relay legs a
96
+ // Node-side Timestamp/Bytes/GeoPoint arrives as its marker shape;
97
+ // without rehydration the comparison would see a plain map and the
98
+ // filter would silently mismatch typed stored values.
99
+ return pyricWhere(c.field, c.op as Parameters<typeof pyricWhere>[1], rehydrateDocValue(c.value));
100
+ // Composite filters rebuild through the modular `and`/`or` factories,
101
+ // which validate operands: an empty composite or a nested non-filter
102
+ // throws the same TypeError the in-page SDK raises (surfaces as an
103
+ // error res / snap-error, never a crash).
104
+ case 'and':
105
+ return pyricAnd(...c.filters.map(resolveConstraint));
106
+ case 'or':
107
+ return pyricOr(...c.filters.map(resolveConstraint));
108
+ case 'orderBy':
109
+ return pyricOrderBy(c.field, c.direction);
110
+ case 'limit':
111
+ return pyricLimit(c.n);
112
+ case 'limitToLast':
113
+ return pyricLimitToLast(c.n);
114
+ // Cursor values rehydrate for the same reason as `where` values —
115
+ // `startAfter(<timestamp>)` must position against real Timestamps.
116
+ case 'startAt':
117
+ return pyricStartAt(...c.values.map(rehydrateDocValue));
118
+ case 'startAfter':
119
+ return pyricStartAfter(...c.values.map(rehydrateDocValue));
120
+ case 'endAt':
121
+ return pyricEndAt(...c.values.map(rehydrateDocValue));
122
+ case 'endBefore':
123
+ return pyricEndBefore(...c.values.map(rehydrateDocValue));
124
+ }
125
+ }
126
+
127
+ // ─── Snapshot serialization ───────────────────────────────────────────────
128
+
129
+ /**
130
+ * Serialize a document snapshot to cross-port form.
131
+ * Uses JSON-via-serializeDocData so Timestamp/Bytes/LatLng survive.
132
+ */
133
+ export function serializeDocSnap(snap: {
134
+ id: string;
135
+ path?: string;
136
+ ref?: { path?: string };
137
+ exists: boolean | (() => boolean);
138
+ data(): Record<string, unknown> | undefined;
139
+ }): { id: string; path?: string; exists: boolean; data?: { json: string } } {
140
+ const existsBool = typeof snap.exists === 'function' ? snap.exists() : snap.exists;
141
+ const data = existsBool ? snap.data() : undefined;
142
+ return {
143
+ id: snap.id,
144
+ // Doc snapshots carry a top-level `path`; QUERY doc snapshots carry it on
145
+ // `.ref.path`. Read both so query rows serialize their FULL path (Studio's
146
+ // browse resolves the document detail from it).
147
+ path: snap.path ?? snap.ref?.path,
148
+ exists: existsBool,
149
+ data: data ? serializeDocData(data) : undefined,
150
+ };
151
+ }
152
+
153
+ // ─── Auth lens (Pyric Studio) ─────────────────────────────────────────────
154
+
155
+ /**
156
+ * Resolve the Firestore handle an op runs against, given its `actAs` lens
157
+ * (Pyric Studio auth lens, T2 — implements the C2 protocol seam).
158
+ *
159
+ * Resolution by `actAs.mode` (absent ⇒ the app's session):
160
+ *
161
+ * - `app-session` (and `actAs` absent): `ctx.db` — the shared sandbox-live
162
+ * handle. Reads `sandbox.currentUser` per op, so rules evaluate under
163
+ * whoever the served app is signed in as. This is the unchanged default
164
+ * and the ONLY lens the app itself ever uses.
165
+ *
166
+ * - `{ mode: 'as', uid }` (impersonation — the rules-debugging primitive):
167
+ * a FROZEN-identity `getFirestore(sandbox.withAuth({ uid }))` handle.
168
+ * Security rules APPLY and evaluate as that user — `request.auth.uid`
169
+ * resolves to `uid`. This lets Studio "re-run this denied op as the user
170
+ * who attempted it" (Wave-2 rules-debugging, F4). Handles are cached
171
+ * per-uid on `ctx.lensHandles`.
172
+ *
173
+ * - `{ mode: 'admin' }` (rule bypass): a modular `getAdminFirestore(sandbox)`
174
+ * handle (pyric Gap #2) whose ops skip security-rule evaluation while still
175
+ * reading/writing the same store and emitting events. This is Studio's
176
+ * "edit anything as admin" surface (F2). Cached on `ctx.adminDb`.
177
+ *
178
+ * - `{ mode: 'anon' }` (explicitly unauthenticated): a frozen
179
+ * `getFirestore(sandbox.withAuth(null))` handle — rules apply with
180
+ * `request.auth == null`. The remote arm's `withAuth(null)`; distinct from
181
+ * an ABSENT lens, which resolves to the port's session. Cached on
182
+ * `ctx.anonDb`.
183
+ *
184
+ * WRITE-IMPERSONATION GATING (open micro-decision #1, honoured): the resolver
185
+ * itself is symmetric — an `{ mode: 'as', uid }` lens applies to BOTH reads and
186
+ * writes (a write-as-user is denied/allowed exactly as that user's rules say).
187
+ * The POLICY decision — "read-as-user always; write-as-user only on an explicit
188
+ * reproduce path" — is enforced at the CALLER (the Studio client / UI chooses
189
+ * when to attach a write op's `actAs`), NOT here. Default behaviour stays admin/
190
+ * app-session unless a caller sets `actAs`; no UI is added by T2.
191
+ */
192
+ export function lensDb(ctx: HostCtx, actAs?: AuthLens): Firestore {
193
+ // Absent / app-session → the app's live session handle.
194
+ if (!actAs || actAs.mode === 'app-session') {
195
+ return ctx.db;
196
+ }
197
+
198
+ // { mode: 'admin' } → a modular rules-bypass handle (cached per ctx).
199
+ if (actAs.mode === 'admin') {
200
+ return (ctx.adminDb ??= pyricGetAdminFirestore(ctx.sandbox));
201
+ }
202
+
203
+ // { mode: 'anon' } → a genuinely UNAUTHENTICATED handle
204
+ // (`withAuth(null)` — `request.auth == null` in rules). NOT the same as an
205
+ // absent lens, which resolves to the PORT'S SESSION: a relayed op that
206
+ // means "no auth" must pin this lens or it silently runs as whoever the
207
+ // browser tab is signed in as.
208
+ if (actAs.mode === 'anon') {
209
+ return (ctx.anonDb ??= pyricGetFirestore(ctx.sandbox.withAuth(null)));
210
+ }
211
+
212
+ // { mode: 'as', uid } → a frozen-identity handle; rules evaluate as `uid`.
213
+ const handles = (ctx.lensHandles ??= new Map());
214
+ const key = lensCacheKey(actAs);
215
+ let handle = handles.get(key);
216
+ if (!handle) {
217
+ handle = pyricGetFirestore(ctx.sandbox.withAuth(authStateForLens(actAs)));
218
+ handles.set(key, handle);
219
+ }
220
+ return handle;
221
+ }
222
+
223
+ export function authStateForLens(actAs: Extract<AuthLens, { mode: 'as' }>): { uid: string; token?: Record<string, unknown> } {
224
+ return actAs.token === undefined
225
+ ? { uid: actAs.uid }
226
+ : { uid: actAs.uid, token: actAs.token };
227
+ }
228
+
229
+ export function lensCacheKey(actAs: Extract<AuthLens, { mode: 'as' }>): string {
230
+ return actAs.token === undefined
231
+ ? actAs.uid
232
+ : `${actAs.uid}:${JSON.stringify(actAs.token)}`;
233
+ }
234
+
235
+ /** Cache key for a real port session; claims are part of authorization identity. */
236
+ export function sessionCacheKey(session: MintedSession): string {
237
+ return session.state.token === undefined
238
+ ? session.user.uid
239
+ : `${session.user.uid}:${JSON.stringify(session.state.token)}`;
240
+ }
241
+
242
+ /**
243
+ * Normalise a per-op `actAs` lens to the {@link AuthLens} provenance shape that
244
+ * the unified sandbox event stream stamps on each event's `authLens` field.
245
+ *
246
+ * Absent ⇒ `{ mode: 'app-session' }` (the app's own session) — matching how
247
+ * `EventProvenance.authLens` reads when omitted. C1 added the field to events;
248
+ * T1 owns the EMIT path that actually writes it. T2's job is to thread the lens
249
+ * THROUGH the host so T1 has the value at emit time: see the call in `handleOp`
250
+ * where the resolved lens is passed to the sandbox via `withLens` when that
251
+ * emit seam exists. Today the sandbox event emitters infer `authLens` from the
252
+ * acting identity (the impersonation handle's frozen `auth` is `{ uid }`, so a
253
+ * rules eval already carries that uid); this helper exists so the host has a
254
+ * single canonical normaliser when the explicit emit-time stamp lands.
255
+ */
256
+ export function lensProvenance(actAs?: AuthLens): AuthLens {
257
+ return actAs ?? { mode: 'app-session' };
258
+ }
259
+
260
+ /**
261
+ * Resolve the data handle for an op/sub carrying NO explicit lens: the
262
+ * PORT'S SESSION (#754). A signed-in port gets a per-session-token cached
263
+ * `getFirestore(sandbox.withAuth(session.state))` handle — rules evaluate
264
+ * under its uid + custom claims, exactly like a globally signed-in user. A
265
+ * signed-out port falls back to `ctx.db` (sandbox-live; `currentUser` is
266
+ * never set in served mode, so that is the unauthenticated view).
267
+ *
268
+ * This is NOT the impersonation lens: the session was minted by validated
269
+ * sign-in on this port (`sandbox.mintSession`), so both reads and writes
270
+ * legitimately run as that user — the write-impersonation gate on the
271
+ * Studio `as` lens does not apply to a port's own session.
272
+ *
273
+ * Claim changes become visible when the client forces an ID-token refresh;
274
+ * host-auth updates the port session, clears all session-bound service
275
+ * caches, and re-establishes that port's listeners under the new token.
276
+ */
277
+ export function sessionDb(ctx: HostCtx, port: PortLike): Firestore {
278
+ const session = portSession(ctx, port);
279
+ if (!session) return ctx.db;
280
+ const cache = (ctx.sessionDbs ??= new Map());
281
+ const key = sessionCacheKey(session);
282
+ let handle = cache.get(key);
283
+ if (!handle) {
284
+ handle = pyricGetFirestore(ctx.sandbox.withAuth(session.state));
285
+ cache.set(key, handle);
286
+ }
287
+ return handle;
288
+ }
289
+
290
+ function sessionRtdb(ctx: HostCtx, port: PortLike): Database {
291
+ const session = portSession(ctx, port);
292
+ if (!session) return ensureRtdb(ctx);
293
+ const cache = (ctx.sessionRtdbs ??= new Map());
294
+ const key = sessionCacheKey(session);
295
+ let handle = cache.get(key);
296
+ if (!handle) {
297
+ handle = pyricGetDatabase(ctx.sandbox.withAuth(session.state));
298
+ cache.set(key, handle);
299
+ }
300
+ return handle;
301
+ }
302
+
303
+ export function lensRtdb(ctx: HostCtx, actAs: AuthLens | undefined, port: PortLike): Database {
304
+ if (!actAs || actAs.mode === 'app-session') {
305
+ return sessionRtdb(ctx, port);
306
+ }
307
+ if (actAs.mode === 'admin') {
308
+ return (ctx.adminRtdb ??= pyricGetAdminDatabase(ctx.sandbox));
309
+ }
310
+ // Genuinely unauthenticated — see the `anon` note on lensDb.
311
+ if (actAs.mode === 'anon') {
312
+ return (ctx.anonRtdb ??= pyricGetDatabase(ctx.sandbox.withAuth(null)));
313
+ }
314
+
315
+ const handles = (ctx.lensRtdbs ??= new Map());
316
+ const key = lensCacheKey(actAs);
317
+ let handle = handles.get(key);
318
+ if (!handle) {
319
+ handle = pyricGetDatabase(ctx.sandbox.withAuth(authStateForLens(actAs)));
320
+ handles.set(key, handle);
321
+ }
322
+ return handle;
323
+ }
324
+
325
+ export function ensureRtdb(ctx: HostCtx): Database {
326
+ return (ctx.rtdb ??= pyricGetDatabase(ctx.sandbox));
327
+ }
328
+
329
+ // ─── Op provenance ─────────────────────────────────────────────────────────
330
+
331
+ /**
332
+ * Op provenance from an inbound message, bound at ISSUE time. This is the
333
+ * source of truth for both the synchronous ambient window used by immediate
334
+ * emitters and the operation-scoped Storage handle used across awaits.
335
+ *
336
+ * - `actor`: a client that DECLARED itself the issuer (`issuer: 'studio'`,
337
+ * stamped by Studio's worker client — `setOpIssuer` in client.ts) gets
338
+ * `actor: { kind: 'studio' }`. Bridge-relayed frames are forwarded
339
+ * with the stamp cleared (client.ts `relayWorkerOp`), so remote traffic
340
+ * carries `relaySource: 'remote'` and remains unattributed rather than
341
+ * being silently promoted to either Studio or page app traffic.
342
+ * - `authLens`: the op's EFFECTIVE lens (`msg.actAs`) whenever present —
343
+ * independent of issuer, because admin is admin regardless of who asked
344
+ * (an agent tool relay's admin op must classify as a rules BYPASS in
345
+ * Traffic, not a rules allow).
346
+ *
347
+ * Plain served-app operations get provenance from their service handles.
348
+ * Firestore subscription registration is the exception: listener lifecycle
349
+ * envelopes originate below that handle, so a normal worker subscription is
350
+ * stamped here as app/app-session. Its later unattributed detach can then be
351
+ * correlated to the accepted registration by the activity monitor.
352
+ */
353
+ export function opProvenance(
354
+ msg: InboundMessage,
355
+ activityJourneyId?: string,
356
+ ): EventProvenance | undefined {
357
+ const issuer = (msg as { issuer?: 'studio' }).issuer;
358
+ const relaySource = (msg as { relaySource?: 'remote' }).relaySource;
359
+ const actAs = (msg as { actAs?: AuthLens }).actAs;
360
+ const target = msg.t === 'sub' ? msg.target : undefined;
361
+ const isAppFirestoreSubscription = issuer !== 'studio'
362
+ && relaySource !== 'remote'
363
+ && target !== null
364
+ && typeof target === 'object'
365
+ && '__ref' in target;
366
+ if (
367
+ issuer !== 'studio'
368
+ && relaySource !== 'remote'
369
+ && !actAs
370
+ && !isAppFirestoreSubscription
371
+ && activityJourneyId === undefined
372
+ ) return undefined;
373
+ return {
374
+ actor: relaySource === 'remote'
375
+ ? { kind: 'unattributed' }
376
+ : issuer === 'studio'
377
+ ? { kind: 'studio' }
378
+ : { kind: 'app', ...(activityJourneyId ? { journeyId: activityJourneyId } : {}) },
379
+ authLens: actAs ?? { mode: 'app-session' },
380
+ ...(isAppFirestoreSubscription
381
+ ? { activity: { listenerId: (msg as { subId: string }).subId } }
382
+ : {}),
383
+ ...(msg.t === 'op' && msg.method === 'getDoc' && msg.activity?.groupKind
384
+ ? { activity: { groupKind: msg.activity.groupKind } }
385
+ : {}),
386
+ };
387
+ }