@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,129 @@
1
+ /**
2
+ * The bundle the import map serves for `firebase/database`.
3
+ *
4
+ * The SharedWorker client already carries the RTDB data-plane used by Studio
5
+ * and the Playground. This entry gives served apps the same common modular SDK
6
+ * surface while the in-page fallback delegates to `pyric/database`.
7
+ */
8
+ import * as ip from 'pyric/database';
9
+ import { getDatabase as pyricGetDatabase } from 'pyric/database';
10
+ import {
11
+ rtdbChild,
12
+ rtdbConnectDatabaseEmulator,
13
+ rtdbGet,
14
+ rtdbGetDatabase,
15
+ rtdbOff,
16
+ rtdbOnValue,
17
+ rtdbPush,
18
+ rtdbRef,
19
+ rtdbRemove,
20
+ rtdbServerTimestamp,
21
+ rtdbSet,
22
+ rtdbUpdate,
23
+ } from '../worker/client.js';
24
+ import { useWorker } from './worker-runtime.js';
25
+ import { getApp, type FirebaseApp } from 'pyric/app';
26
+ import { workerClientForApp } from './app-client.js';
27
+
28
+ const workerDatabaseByApp = new WeakMap<FirebaseApp, ReturnType<typeof pyricGetDatabase>>();
29
+
30
+ export const getDatabase = ((app?: FirebaseApp) => {
31
+ const resolved = app ?? getApp();
32
+ if (!useWorker) return pyricGetDatabase(resolved);
33
+ const existing = workerDatabaseByApp.get(resolved);
34
+ if (existing) return existing;
35
+ const client = workerClientForApp(resolved);
36
+ const handle = Object.assign(rtdbGetDatabase(client), { app: resolved }) as unknown as ReturnType<typeof pyricGetDatabase>;
37
+ workerDatabaseByApp.set(resolved, handle);
38
+ return handle;
39
+ }) as typeof pyricGetDatabase;
40
+
41
+ export const ref = (useWorker ? rtdbRef : ip.ref) as typeof ip.ref;
42
+ export const child = (useWorker ? rtdbChild : ip.child) as typeof ip.child;
43
+ export const get = (useWorker ? rtdbGet : ip.get) as typeof ip.get;
44
+ export const set = (useWorker ? rtdbSet : ip.set) as typeof ip.set;
45
+ export const update = (useWorker ? rtdbUpdate : ip.update) as typeof ip.update;
46
+ export const remove = (useWorker ? rtdbRemove : ip.remove) as typeof ip.remove;
47
+ export const push = (useWorker ? rtdbPush : ip.push) as typeof ip.push;
48
+ export const onValue = (useWorker ? rtdbOnValue : ip.onValue) as typeof ip.onValue;
49
+ export const off = (useWorker ? rtdbOff : ip.off) as typeof ip.off;
50
+ export const serverTimestamp = (
51
+ useWorker ? rtdbServerTimestamp : ip.serverTimestamp
52
+ ) as typeof ip.serverTimestamp;
53
+ export const connectDatabaseEmulator = (
54
+ useWorker ? rtdbConnectDatabaseEmulator : ip.connectDatabaseEmulator
55
+ ) as typeof ip.connectDatabaseEmulator;
56
+
57
+ // ── Low-hanging-fruit exports (issue #149) ────────────────────────────────
58
+ // Served mode is always sandbox-backed (never a prod handle), and these are
59
+ // honest no-ops in the sandbox model regardless of the worker/in-page split,
60
+ // so they are unconditional no-ops here — no worker RPC needed. This also
61
+ // gives served apps import-time parity for the `firebase/database` surface.
62
+ export const goOffline = ((_db?: unknown) => {}) as typeof ip.goOffline;
63
+ export const goOnline = ((_db?: unknown) => {}) as typeof ip.goOnline;
64
+ export const forceLongPolling = (() => {}) as typeof ip.forceLongPolling;
65
+ export const forceWebSockets = (() => {}) as typeof ip.forceWebSockets;
66
+ export const enableLogging = ((_logger?: unknown, _persistent?: unknown) => {}) as typeof ip.enableLogging;
67
+
68
+ /**
69
+ * `refFromURL(db, url)` — parse the path out of the URL and delegate to the
70
+ * picked `ref` (worker or in-page), so the resolved ref behaves exactly like
71
+ * `ref(db, path)`. The URL host/namespace is not honored (served sandbox is
72
+ * single-database) — matching the in-page `pyric/database` behavior.
73
+ */
74
+ export const refFromURL = ((db: unknown, url: string) => {
75
+ let path: string;
76
+ try {
77
+ path = new URL(url).pathname;
78
+ } catch {
79
+ throw new Error(
80
+ `firebase/database refFromURL received a value that is not an absolute URL: ${url}`,
81
+ );
82
+ }
83
+ return (ref as (db: unknown, path?: string) => unknown)(db, path);
84
+ }) as typeof ip.refFromURL;
85
+
86
+ function unsupportedWorkerApi(name: string): never {
87
+ throw new Error(
88
+ `firebase/database ${name}() is not supported over the pyric SharedWorker yet. ` +
89
+ 'Use the in-page fallback for this operation.',
90
+ );
91
+ }
92
+
93
+ export const runTransaction = (
94
+ useWorker ? (() => unsupportedWorkerApi('runTransaction')) : ip.runTransaction
95
+ ) as typeof ip.runTransaction;
96
+
97
+ export const query = (
98
+ useWorker ? (() => unsupportedWorkerApi('query')) : ip.query
99
+ ) as typeof ip.query;
100
+ export const orderByChild = (
101
+ useWorker ? (() => unsupportedWorkerApi('orderByChild')) : ip.orderByChild
102
+ ) as typeof ip.orderByChild;
103
+ export const orderByKey = (
104
+ useWorker ? (() => unsupportedWorkerApi('orderByKey')) : ip.orderByKey
105
+ ) as typeof ip.orderByKey;
106
+ export const orderByValue = (
107
+ useWorker ? (() => unsupportedWorkerApi('orderByValue')) : ip.orderByValue
108
+ ) as typeof ip.orderByValue;
109
+ export const startAt = (
110
+ useWorker ? (() => unsupportedWorkerApi('startAt')) : ip.startAt
111
+ ) as typeof ip.startAt;
112
+ export const startAfter = (
113
+ useWorker ? (() => unsupportedWorkerApi('startAfter')) : ip.startAfter
114
+ ) as typeof ip.startAfter;
115
+ export const endAt = (
116
+ useWorker ? (() => unsupportedWorkerApi('endAt')) : ip.endAt
117
+ ) as typeof ip.endAt;
118
+ export const endBefore = (
119
+ useWorker ? (() => unsupportedWorkerApi('endBefore')) : ip.endBefore
120
+ ) as typeof ip.endBefore;
121
+ export const equalTo = (
122
+ useWorker ? (() => unsupportedWorkerApi('equalTo')) : ip.equalTo
123
+ ) as typeof ip.equalTo;
124
+ export const limitToFirst = (
125
+ useWorker ? (() => unsupportedWorkerApi('limitToFirst')) : ip.limitToFirst
126
+ ) as typeof ip.limitToFirst;
127
+ export const limitToLast = (
128
+ useWorker ? (() => unsupportedWorkerApi('limitToLast')) : ip.limitToLast
129
+ ) as typeof ip.limitToLast;
@@ -0,0 +1,232 @@
1
+ /**
2
+ * The bundle the import map serves for `firebase/firestore`.
3
+ *
4
+ * DUAL-PATH (Phase 3c): when a SharedWorker is available, the data ops route
5
+ * to the ONE worker-hosted sandbox (multi-tab sync + IDB/`--persist`
6
+ * durability); otherwise they run against the in-page sandbox — the unchanged
7
+ * fallback. The branch is picked ONCE at module load (`useWorker`).
8
+ *
9
+ * The COMPLETE modular surface is exported on BOTH paths: a missing named
10
+ * export fails the page at import time (the firebase/app failure class), so the
11
+ * worker path fills the functions the thin worker-client lacks (`or`/`and`,
12
+ * `Timestamp`, the client-cache config no-ops) right here.
13
+ *
14
+ * Browser-bundled by `../bundler.ts`; never imported by node-side code.
15
+ */
16
+ import * as ip from 'pyric/firestore';
17
+ import { getFirestore as pyricGetFirestore } from 'pyric/firestore';
18
+ import * as wcRaw from '../worker/client.js';
19
+ import { useWorker } from './worker-runtime.js';
20
+ import { getApp, type FirebaseApp } from 'pyric/app';
21
+ import { workerClientForApp } from './app-client.js';
22
+
23
+ // The worker client mirrors pyric/firestore's DATA surface (same names + arg
24
+ // shapes); cast so the picked bindings type-check against the canonical module.
25
+ // Members the worker client genuinely lacks (or/and/Timestamp/cache config) are
26
+ // handled explicitly below — NOT taken from this cast.
27
+ const wc = wcRaw as unknown as typeof ip;
28
+
29
+ /** The data-path implementation chosen at load. */
30
+ const D = useWorker ? wc : ip;
31
+
32
+ // ── Data ops — route to the worker-hosted or in-page sandbox ──────────────
33
+ export const onSnapshot = D.onSnapshot;
34
+ export const collection = D.collection;
35
+ export const collectionGroup = D.collectionGroup;
36
+ export const doc = D.doc;
37
+ export const getDoc = D.getDoc;
38
+ export const getDocs = D.getDocs;
39
+ export const setDoc = D.setDoc;
40
+ export const addDoc = D.addDoc;
41
+ export const updateDoc = D.updateDoc;
42
+ export const deleteDoc = D.deleteDoc;
43
+ export const query = D.query;
44
+ export const where = D.where;
45
+ export const orderBy = D.orderBy;
46
+ export const limit = D.limit;
47
+ export const limitToLast = D.limitToLast;
48
+ export const startAt = D.startAt;
49
+ export const startAfter = D.startAfter;
50
+ export const endAt = D.endAt;
51
+ export const endBefore = D.endBefore;
52
+ export const runTransaction = D.runTransaction;
53
+ export const writeBatch = D.writeBatch;
54
+ export const serverTimestamp = D.serverTimestamp;
55
+ export const increment = D.increment;
56
+ export const arrayUnion = D.arrayUnion;
57
+ export const arrayRemove = D.arrayRemove;
58
+ export const deleteField = D.deleteField;
59
+
60
+ // ── Value class — path-independent (builds data; the worker serializes it via
61
+ // the shared codec) ──────────────────────────────────────────────────────
62
+ export const Timestamp = ip.Timestamp;
63
+
64
+ // ── Composite filters — path-independent (issue #144). The worker query
65
+ // protocol carries the composite filter tree end-to-end: the client `or`/
66
+ // `and` factories emit nested `FilterConstraintDescriptor`s, `query()`
67
+ // embeds them in the query descriptor, and the host rebuilds them through
68
+ // the REAL `pyric/firestore` `and`/`or` factories (see
69
+ // `worker/host.ts` resolveConstraint + `worker/protocol.ts`
70
+ // FilterConstraintDescriptor). So on BOTH paths `or`/`and` come from the
71
+ // chosen data impl `D` — the worker client on the worker path, in-page
72
+ // otherwise. Nested `and`/`or`/`where` composites and composition with
73
+ // orderBy/limit all cross intact; malformed composites (empty / non-filter
74
+ // operand) still raise the same modular-SDK TypeError. ────────────────────
75
+ export const or = D.or;
76
+ export const and = D.and;
77
+
78
+ // ── getFirestore — the canonical bare call returns the page's shared backend:
79
+ // the worker ClientDb on the worker path, the in-page sandbox otherwise. ──
80
+ const workerFirestoreByApp = new WeakMap<FirebaseApp, ReturnType<typeof pyricGetFirestore>>();
81
+
82
+ export const getFirestore = ((app?: FirebaseApp) => {
83
+ const resolved = app ?? getApp();
84
+ if (!useWorker) return pyricGetFirestore(resolved);
85
+ const existing = workerFirestoreByApp.get(resolved);
86
+ if (existing) return existing;
87
+ const client = workerClientForApp(resolved);
88
+ const handle = Object.assign(client, { app: resolved }) as unknown as ReturnType<typeof pyricGetFirestore>;
89
+ workerFirestoreByApp.set(resolved, handle);
90
+ return handle;
91
+ }) as typeof pyricGetFirestore;
92
+
93
+ // ── section 3c tier 2: ACCEPTED, sandbox-managed (no-op + one-time notice). ──────
94
+ // Apps configure client caching unconditionally; a missing named export
95
+ // fails the page at IMPORT time (the firebase/app failure class). None of
96
+ // these are emulated — the sandbox (in-page OR worker) IS the source of
97
+ // truth, so the client cache layer these configure has no role. Durable data
98
+ // is the worker's IDB (default) + `pyric dev --persist`. Path-independent.
99
+
100
+ let cacheNoticeShown = false;
101
+ function acceptedNoOp(name: string): void {
102
+ if (cacheNoticeShown) return;
103
+ cacheNoticeShown = true;
104
+ console.info(
105
+ `[pyric dev] ${name}(): client cache/persistence settings are accepted but unused — ` +
106
+ 'the pyric sandbox is the source of truth. Durable state is the worker store / `pyric dev --persist`.',
107
+ );
108
+ }
109
+
110
+ /** firebase's sentinel value, re-exported for settings parity. */
111
+ export const CACHE_SIZE_UNLIMITED = -1;
112
+
113
+ export function initializeFirestore(
114
+ app?: Parameters<typeof pyricGetFirestore>[0],
115
+ settings?: unknown,
116
+ ): ReturnType<typeof getFirestore> {
117
+ if (settings && Object.keys(settings as object).length > 0) acceptedNoOp('initializeFirestore');
118
+ return getFirestore(app as never);
119
+ }
120
+
121
+ export function persistentLocalCache(_settings?: unknown): { kind: string } {
122
+ acceptedNoOp('persistentLocalCache');
123
+ return { kind: 'persistent' };
124
+ }
125
+
126
+ export function memoryLocalCache(_settings?: unknown): { kind: string } {
127
+ return { kind: 'memory' };
128
+ }
129
+
130
+ export function persistentSingleTabManager(_settings?: unknown): { kind: string } {
131
+ return { kind: 'persistentSingleTab' };
132
+ }
133
+
134
+ export function persistentMultipleTabManager(): { kind: string } {
135
+ return { kind: 'persistentMultipleTab' };
136
+ }
137
+
138
+ export async function enableIndexedDbPersistence(_db?: unknown): Promise<void> {
139
+ acceptedNoOp('enableIndexedDbPersistence');
140
+ }
141
+
142
+ /** No-op success, same rationale as `enableIndexedDbPersistence` — the
143
+ * SharedWorker path already IS the one store every tab reads/writes, so
144
+ * there's no separate multi-tab mode to opt into over the worker; the
145
+ * in-page fallback has no multi-tab story to begin with. */
146
+ export async function enableMultiTabIndexedDbPersistence(_db?: unknown): Promise<void> {
147
+ acceptedNoOp('enableMultiTabIndexedDbPersistence');
148
+ }
149
+
150
+ export async function clearIndexedDbPersistence(_db?: unknown): Promise<void> {
151
+ acceptedNoOp('clearIndexedDbPersistence');
152
+ }
153
+
154
+ /** Resolves immediately — sandbox writes apply synchronously in-page; over the
155
+ * worker the RPC ack already settled (judgment zone 4, recorded). */
156
+ export async function waitForPendingWrites(_db?: unknown): Promise<void> {}
157
+
158
+ // ── network toggles — no-op (accepted, unused). No network exists in the
159
+ // sandbox (in-page OR worker): every op is a local call, never a request
160
+ // that could be offline. Writes issued after `disableNetwork()` still
161
+ // commit immediately — no offline queue is simulated, because the sandbox
162
+ // cannot honestly deliver "queued until reconnected" with no connection to
163
+ // lose in the first place. ───────────────────────────────────────────────
164
+ export async function disableNetwork(_db?: unknown): Promise<void> {
165
+ acceptedNoOp('disableNetwork');
166
+ }
167
+
168
+ export async function enableNetwork(_db?: unknown): Promise<void> {
169
+ acceptedNoOp('enableNetwork');
170
+ }
171
+
172
+ /**
173
+ * In-page fallback: forwards to `pyric/firestore`'s `terminate`, which
174
+ * genuinely tears the sandbox down via `Sandbox.dispose()`.
175
+ *
176
+ * Worker path: accepted no-op. The SharedWorker-hosted sandbox is
177
+ * shared across every tab on the page's origin — disposing it here
178
+ * would tear down listener registries out from under other open tabs,
179
+ * which the real `terminate()` contract (single-instance teardown)
180
+ * never implies. Documented divergence: over the worker, `terminate`
181
+ * settles without tearing anything down.
182
+ */
183
+ export async function terminate(db?: unknown): Promise<void> {
184
+ if (useWorker) {
185
+ console.info(
186
+ '[pyric dev] terminate(): the SharedWorker-hosted sandbox is shared across every tab; ' +
187
+ 'it is not torn down by a single tab calling terminate().',
188
+ );
189
+ return;
190
+ }
191
+ return ip.terminate(db as Parameters<typeof ip.terminate>[0]);
192
+ }
193
+
194
+ // ── tier-1 cache-init + get-from-* + log-level + snapshot-sync (issue #144,
195
+ // tier-1 pass). Aliases and honest no-op config tokens — see
196
+ // `packages/pyric/src/firestore/index.ts`'s tier-1 section for the full
197
+ // rationale. `memoryEagerGarbageCollector`/`memoryLruGarbageCollector` and
198
+ // `setLogLevel` are path-independent (no data routing), so they delegate
199
+ // straight to `pyric/firestore`. `getDocFromServer`/`getDocFromCache` and
200
+ // their plural forms MUST route through `D` (the worker-vs-in-page pick)
201
+ // like `getDoc`/`getDocs` above, not straight to `ip`, so they read from
202
+ // whichever backend this page actually uses. ─────────────────────────────
203
+
204
+ export const memoryEagerGarbageCollector = ip.memoryEagerGarbageCollector;
205
+ export const memoryLruGarbageCollector = ip.memoryLruGarbageCollector;
206
+ export const setLogLevel = ip.setLogLevel;
207
+
208
+ export const getDocFromServer = D.getDoc;
209
+ export const getDocsFromServer = D.getDocs;
210
+ export const getDocFromCache = D.getDoc;
211
+ export const getDocsFromCache = D.getDocs;
212
+
213
+ /**
214
+ * Local no-op reimplementation rather than delegating to `ip.onSnapshotsInSync`:
215
+ * on the worker path `db` is a `ClientDb`, not a `pyric/firestore` `Firestore`
216
+ * handle, so it doesn't carry the `TARGET_SYMBOL` brand `ip.onSnapshotsInSync`
217
+ * dispatches on. Fires the callback once the current microtask queue settles —
218
+ * same honest approximation as the in-page implementation — on both paths.
219
+ */
220
+ export function onSnapshotsInSync(
221
+ _db: unknown,
222
+ observerOrCallback: (() => void) | { next?: () => void },
223
+ ): () => void {
224
+ const cb = typeof observerOrCallback === 'function' ? observerOrCallback : observerOrCallback.next;
225
+ let cancelled = false;
226
+ queueMicrotask(() => {
227
+ if (!cancelled && cb) cb();
228
+ });
229
+ return () => {
230
+ cancelled = true;
231
+ };
232
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `/__pyric/sdk/init.js` — the script tag `pyric dev` injects into every
3
+ * served HTML page. Pulls the shared runtime and mounts the sign-in helper.
4
+ * In worker mode the helper reads the worker user directory and owns UI state
5
+ * only; in fallback mode it adapts the page sandbox's Auth store.
6
+ */
7
+ import { getAuth, sandbox as authSandbox } from 'pyric/auth';
8
+ import {
9
+ getAuth as getWorkerAuth,
10
+ listUsers,
11
+ } from '../worker/client.js';
12
+ import { sandbox } from './runtime.js';
13
+ import { useWorker, workerDb } from './worker-runtime.js';
14
+ import { ServeAuthHelper } from './auth-helper-core.js';
15
+ import { installServeAuthResolver } from './auth-helper-runtime.js';
16
+ import { mountAuthHelperDialog } from './auth-helper-dom.js';
17
+
18
+ const localAuth = useWorker ? null : getAuth(sandbox);
19
+ const workerAuth = useWorker && workerDb ? getWorkerAuth(workerDb) : null;
20
+ const helper = new ServeAuthHelper(
21
+ workerAuth
22
+ ? {
23
+ list: async () => (await listUsers(workerAuth)).map((user) => ({
24
+ uid: user.uid,
25
+ email: user.email,
26
+ displayName: user.displayName,
27
+ customClaims: user.customClaims,
28
+ })),
29
+ }
30
+ : {
31
+ list: () => authSandbox.listIdentities(localAuth!),
32
+ add: (identity) => authSandbox.seedUsers(localAuth!, [{
33
+ uid: identity.uid,
34
+ email: identity.email ?? '',
35
+ password: '__pyric_popup_no_password__',
36
+ displayName: identity.displayName ?? undefined,
37
+ customClaims: identity.customClaims,
38
+ }]),
39
+ },
40
+ );
41
+ const resolver = helper.resolver();
42
+ installServeAuthResolver(resolver);
43
+ if (localAuth) authSandbox.setAuthFlowResolver(localAuth, resolver);
44
+ mountAuthHelperDialog(helper);
45
+
46
+ export {};
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `keepalive` size gate for the persist flush (pre-mortem #1).
3
+ *
4
+ * The persistence controller's `beforeunload` flush fires while the page is
5
+ * unloading; a plain `fetch` is aborted on unload, so the final delta is
6
+ * lost (the original "crash-only loss window" claim was wrong). `fetch(...,
7
+ * {keepalive: true})` survives unload — but the browser caps the TOTAL body
8
+ * size of in-flight keepalive requests at ~64KB. Above that the request is
9
+ * rejected, so we only set keepalive when the body comfortably fits, and
10
+ * warn once when it doesn't (that page's final unsaved change can be lost on
11
+ * tab close; reload-triggered flushes are unaffected because they complete
12
+ * before navigation).
13
+ */
14
+
15
+ /** Below this, keepalive is safe; above, skip it (and warn once). 60KB
16
+ * leaves headroom under the ~64KB spec cap for headers/other requests. */
17
+ export const KEEPALIVE_MAX_BYTES = 60_000;
18
+
19
+ let warnedLargeState = false;
20
+
21
+ export function keepaliveSafe(
22
+ body: string,
23
+ warn: (msg: string) => void = (m) => console.warn(m),
24
+ ): boolean {
25
+ const bytes = byteLength(body);
26
+ if (bytes <= KEEPALIVE_MAX_BYTES) return true;
27
+ if (!warnedLargeState) {
28
+ warnedLargeState = true;
29
+ warn(
30
+ `[pyric dev] persisted state is ${Math.round(bytes / 1024)}KB — too large for an ` +
31
+ 'unload-time flush; the final unsaved change may be lost if you CLOSE the tab before ' +
32
+ 'the next auto-flush. Reloads and normal saves are unaffected.',
33
+ );
34
+ }
35
+ return false;
36
+ }
37
+
38
+ /** Reset module state — tests only. */
39
+ export function __resetKeepaliveWarning(): void {
40
+ warnedLargeState = false;
41
+ }
42
+
43
+ function byteLength(s: string): number {
44
+ // TextEncoder is in every browser + bun; avoids assuming Buffer.
45
+ return typeof TextEncoder !== 'undefined' ? new TextEncoder().encode(s).length : s.length;
46
+ }
@@ -0,0 +1,75 @@
1
+ /** The canonical `firebase/messaging/sw` served mirror. */
2
+ import * as inPage from 'pyric/messaging/sw';
3
+ import type {
4
+ MessagePayload,
5
+ Messaging,
6
+ NextFn,
7
+ Observer,
8
+ Unsubscribe,
9
+ } from 'pyric/messaging/sw';
10
+ import { getApp, type FirebaseApp } from 'pyric/app';
11
+ import { registerSandboxDelivery } from 'pyric/messaging/internal';
12
+ import {
13
+ messagingDeliver,
14
+ messagingGetMessaging,
15
+ messagingSubscribe,
16
+ type ClientMessaging,
17
+ } from '../worker/client/messaging.js';
18
+ import { workerClientForApp } from './app-client.js';
19
+ import { useWorker } from './worker-runtime.js';
20
+
21
+ export type {
22
+ FcmOptions,
23
+ GetTokenOptions,
24
+ MessagePayload,
25
+ Messaging,
26
+ NextFn,
27
+ NotificationPayload,
28
+ Observer,
29
+ Unsubscribe,
30
+ } from 'pyric/messaging/sw';
31
+
32
+ type WorkerMessaging = Messaging & ClientMessaging;
33
+ const workerMessagingByApp = new WeakMap<FirebaseApp, WorkerMessaging>();
34
+ const bigQueryExport = new WeakMap<Messaging, boolean>();
35
+
36
+ export function getMessaging(app?: FirebaseApp): Messaging {
37
+ const resolved = app ?? getApp();
38
+ if (!useWorker) return inPage.getMessaging(resolved);
39
+ const existing = workerMessagingByApp.get(resolved);
40
+ if (existing) return existing;
41
+ const handle = Object.assign(
42
+ messagingGetMessaging(workerClientForApp(resolved)),
43
+ { app: resolved },
44
+ ) as WorkerMessaging;
45
+ workerMessagingByApp.set(resolved, handle);
46
+ // Symmetric with the client entry: let `pyric/messaging/sw`'s `sandbox.deliver`
47
+ // drive this worker-backed handle over the transport (same broker, same op).
48
+ registerSandboxDelivery(handle, (spec) => messagingDeliver(handle, spec));
49
+ return handle;
50
+ }
51
+
52
+ export function onBackgroundMessage(
53
+ messaging: Messaging,
54
+ nextOrObserver: NextFn<MessagePayload> | Observer<MessagePayload>,
55
+ ): Unsubscribe {
56
+ return useWorker
57
+ ? messagingSubscribe(messaging as WorkerMessaging, 'messaging.background', nextOrObserver)
58
+ : inPage.onBackgroundMessage(messaging, nextOrObserver);
59
+ }
60
+
61
+ export function experimentalSetDeliveryMetricsExportedToBigQueryEnabled(
62
+ messaging: Messaging,
63
+ enable: boolean,
64
+ ): void {
65
+ if (!useWorker) {
66
+ inPage.experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, enable);
67
+ return;
68
+ }
69
+ if ((messaging as Partial<ClientMessaging>).__kind !== 'client-messaging') {
70
+ throw new Error('firebase/messaging/sw: unrecognized Messaging instance');
71
+ }
72
+ bigQueryExport.set(messaging, enable);
73
+ }
74
+
75
+ export const isSupported = inPage.isSupported;
@@ -0,0 +1,96 @@
1
+ /** The canonical `firebase/messaging` served mirror. */
2
+ import * as inPage from 'pyric/messaging';
3
+ import type {
4
+ GetTokenOptions,
5
+ MessagePayload,
6
+ Messaging,
7
+ NextFn,
8
+ Observer,
9
+ Unsubscribe,
10
+ } from 'pyric/messaging';
11
+ import { getApp, type FirebaseApp } from 'pyric/app';
12
+ import { registerAppCleanup } from 'pyric/app/internal';
13
+ import { registerSandboxDelivery } from 'pyric/messaging/internal';
14
+ import {
15
+ messagingDeleteToken,
16
+ messagingDeliver,
17
+ messagingGetMessaging,
18
+ messagingGetToken,
19
+ messagingSetVisibility,
20
+ messagingSubscribe,
21
+ type ClientMessaging,
22
+ } from '../worker/client/messaging.js';
23
+ import { workerClientForApp } from './app-client.js';
24
+ import { useWorker } from './worker-runtime.js';
25
+
26
+ export type {
27
+ FcmOptions,
28
+ GetTokenOptions,
29
+ MessagePayload,
30
+ Messaging,
31
+ NextFn,
32
+ NotificationPayload,
33
+ Observer,
34
+ Unsubscribe,
35
+ } from 'pyric/messaging';
36
+
37
+ type WorkerMessaging = Messaging & ClientMessaging;
38
+ const workerMessagingByApp = new WeakMap<FirebaseApp, WorkerMessaging>();
39
+ const visibilityWired = new WeakSet<FirebaseApp>();
40
+
41
+ function wireVisibility(app: FirebaseApp, messaging: WorkerMessaging): void {
42
+ if (visibilityWired.has(app) || typeof document === 'undefined') return;
43
+ visibilityWired.add(app);
44
+ const sync = (): void => {
45
+ const state = document.visibilityState === 'visible' ? 'visible' : 'hidden';
46
+ void messagingSetVisibility(messaging, state).catch(() => {});
47
+ };
48
+ document.addEventListener('visibilitychange', sync);
49
+ registerAppCleanup(app, () => {
50
+ visibilityWired.delete(app);
51
+ document.removeEventListener('visibilitychange', sync);
52
+ });
53
+ sync();
54
+ }
55
+
56
+ export function getMessaging(app?: FirebaseApp): Messaging {
57
+ const resolved = app ?? getApp();
58
+ if (!useWorker) return inPage.getMessaging(resolved);
59
+ const existing = workerMessagingByApp.get(resolved);
60
+ if (existing) return existing;
61
+ const handle = Object.assign(
62
+ messagingGetMessaging(workerClientForApp(resolved)),
63
+ { app: resolved },
64
+ ) as WorkerMessaging;
65
+ workerMessagingByApp.set(resolved, handle);
66
+ wireVisibility(resolved, handle);
67
+ // The worker-backed handle isn't in pyric's in-page instance registry, so
68
+ // teach `pyric/messaging`'s `sandbox.deliver` to drive it over the transport
69
+ // (visibility+routing resolved host-side). Keeps `firebase/messaging` itself
70
+ // free of any `sandbox` surface — production parity is untouched.
71
+ registerSandboxDelivery(handle, (spec) => messagingDeliver(handle, spec));
72
+ return handle;
73
+ }
74
+
75
+ export function getToken(messaging: Messaging, options?: GetTokenOptions): Promise<string> {
76
+ return useWorker
77
+ ? messagingGetToken(messaging as WorkerMessaging, options)
78
+ : inPage.getToken(messaging, options);
79
+ }
80
+
81
+ export function deleteToken(messaging: Messaging): Promise<boolean> {
82
+ return useWorker
83
+ ? messagingDeleteToken(messaging as WorkerMessaging)
84
+ : inPage.deleteToken(messaging);
85
+ }
86
+
87
+ export function onMessage(
88
+ messaging: Messaging,
89
+ nextOrObserver: NextFn<MessagePayload> | Observer<MessagePayload>,
90
+ ): Unsubscribe {
91
+ return useWorker
92
+ ? messagingSubscribe(messaging as WorkerMessaging, 'messaging.foreground', nextOrObserver)
93
+ : inPage.onMessage(messaging, nextOrObserver);
94
+ }
95
+
96
+ export const isSupported = inPage.isSupported;