svelte-firekit 0.1.9 → 0.2.1

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 (439) hide show
  1. package/README.md +550 -354
  2. package/dist/components/AuthGuard.svelte +64 -0
  3. package/dist/components/AuthGuard.svelte.d.ts +15 -0
  4. package/dist/components/Collection.svelte +62 -0
  5. package/dist/components/Collection.svelte.d.ts +39 -0
  6. package/dist/components/CustomGuard.svelte +87 -0
  7. package/dist/components/CustomGuard.svelte.d.ts +13 -0
  8. package/dist/components/Doc.svelte +56 -0
  9. package/dist/components/Doc.svelte.d.ts +36 -0
  10. package/dist/components/DownloadURL.svelte +48 -0
  11. package/dist/components/DownloadURL.svelte.d.ts +14 -0
  12. package/dist/components/FirebaseApp.svelte +81 -0
  13. package/dist/components/FirebaseApp.svelte.d.ts +12 -0
  14. package/dist/components/Node.svelte +54 -0
  15. package/dist/components/Node.svelte.d.ts +36 -0
  16. package/dist/components/SignedIn.svelte +22 -0
  17. package/dist/components/{firekit/signed-in.svelte.d.ts → SignedIn.svelte.d.ts} +1 -4
  18. package/dist/components/SignedOut.svelte +32 -0
  19. package/dist/components/{firekit/signed-out.svelte.d.ts → SignedOut.svelte.d.ts} +3 -5
  20. package/dist/components/UploadTask.svelte +75 -0
  21. package/dist/components/UploadTask.svelte.d.ts +33 -0
  22. package/dist/config.d.ts +29 -6
  23. package/dist/config.js +37 -74
  24. package/dist/context.d.ts +46 -0
  25. package/dist/context.js +56 -0
  26. package/dist/firebase.d.ts +25 -84
  27. package/dist/firebase.js +75 -125
  28. package/dist/index.d.ts +31 -20
  29. package/dist/index.js +47 -30
  30. package/dist/services/ai.svelte.d.ts +152 -0
  31. package/dist/services/ai.svelte.js +302 -0
  32. package/dist/services/analytics.d.ts +39 -231
  33. package/dist/services/analytics.js +89 -421
  34. package/dist/services/app-check.svelte.d.ts +82 -0
  35. package/dist/services/app-check.svelte.js +159 -0
  36. package/dist/services/auth.d.ts +63 -352
  37. package/dist/services/auth.js +353 -718
  38. package/dist/services/bundles.d.ts +42 -0
  39. package/dist/services/bundles.js +57 -0
  40. package/dist/services/callable.d.ts +57 -0
  41. package/dist/services/callable.js +115 -0
  42. package/dist/services/collection.svelte.d.ts +154 -221
  43. package/dist/services/collection.svelte.js +357 -663
  44. package/dist/services/document.svelte.d.ts +73 -254
  45. package/dist/services/document.svelte.js +196 -497
  46. package/dist/services/in-app-messaging.js +4 -0
  47. package/dist/services/messaging.svelte.d.ts +75 -0
  48. package/dist/services/messaging.svelte.js +190 -0
  49. package/dist/services/mutations.d.ts +59 -282
  50. package/dist/services/mutations.js +202 -951
  51. package/dist/services/performance.d.ts +60 -0
  52. package/dist/services/performance.js +118 -0
  53. package/dist/services/presence.svelte.d.ts +21 -89
  54. package/dist/services/presence.svelte.js +232 -469
  55. package/dist/services/realtime.svelte.d.ts +54 -125
  56. package/dist/services/realtime.svelte.js +111 -175
  57. package/dist/services/remote-config.svelte.d.ts +73 -0
  58. package/dist/services/remote-config.svelte.js +204 -0
  59. package/dist/services/storage.svelte.d.ts +81 -208
  60. package/dist/services/storage.svelte.js +190 -305
  61. package/dist/services/user.svelte.d.ts +23 -244
  62. package/dist/services/user.svelte.js +129 -439
  63. package/dist/types/analytics.d.ts +2 -36
  64. package/dist/types/analytics.js +0 -5
  65. package/dist/types/auth.d.ts +15 -85
  66. package/dist/types/auth.js +0 -17
  67. package/dist/types/collection.d.ts +31 -225
  68. package/dist/types/collection.js +5 -51
  69. package/dist/types/document.d.ts +11 -236
  70. package/dist/types/document.js +2 -47
  71. package/dist/types/firebase.d.ts +10 -13
  72. package/dist/types/firebase.js +3 -9
  73. package/dist/types/index.d.ts +5 -5
  74. package/dist/types/index.js +5 -4
  75. package/dist/types/mutations.d.ts +11 -225
  76. package/dist/types/mutations.js +6 -51
  77. package/dist/types/presence.d.ts +5 -158
  78. package/dist/types/presence.js +0 -20
  79. package/dist/utils/errors.d.ts +10 -14
  80. package/dist/utils/errors.js +11 -16
  81. package/dist/utils/firestore.d.ts +3 -4
  82. package/dist/utils/firestore.js +7 -10
  83. package/dist/utils/index.d.ts +4 -4
  84. package/dist/utils/index.js +4 -8
  85. package/dist/utils/providers.d.ts +4 -13
  86. package/dist/utils/providers.js +14 -13
  87. package/dist/utils/user.d.ts +1 -3
  88. package/dist/utils/user.js +1 -3
  89. package/package.json +41 -55
  90. package/dist/components/docs/doc-content.svelte +0 -19
  91. package/dist/components/docs/doc-content.svelte.d.ts +0 -6
  92. package/dist/components/docs/doc-header.svelte +0 -24
  93. package/dist/components/docs/doc-header.svelte.d.ts +0 -13
  94. package/dist/components/docs/doc-renderer.svelte +0 -27
  95. package/dist/components/docs/doc-renderer.svelte.d.ts +0 -8
  96. package/dist/components/docs/mobile-table-of-contents.svelte +0 -42
  97. package/dist/components/docs/mobile-table-of-contents.svelte.d.ts +0 -3
  98. package/dist/components/docs/table-of-contents.svelte +0 -33
  99. package/dist/components/docs/table-of-contents.svelte.d.ts +0 -4
  100. package/dist/components/docs/toc.svelte.d.ts +0 -16
  101. package/dist/components/docs/toc.svelte.js +0 -59
  102. package/dist/components/firekit/Collection.svelte +0 -122
  103. package/dist/components/firekit/Collection.svelte.d.ts +0 -27
  104. package/dist/components/firekit/Doc.svelte +0 -140
  105. package/dist/components/firekit/Doc.svelte.d.ts +0 -28
  106. package/dist/components/firekit/Node.svelte +0 -97
  107. package/dist/components/firekit/Node.svelte.d.ts +0 -23
  108. package/dist/components/firekit/auth-guard.svelte +0 -120
  109. package/dist/components/firekit/auth-guard.svelte.d.ts +0 -26
  110. package/dist/components/firekit/custom-guard.svelte +0 -163
  111. package/dist/components/firekit/custom-guard.svelte.d.ts +0 -31
  112. package/dist/components/firekit/download-url.svelte +0 -92
  113. package/dist/components/firekit/download-url.svelte.d.ts +0 -19
  114. package/dist/components/firekit/firebase-app.svelte +0 -33
  115. package/dist/components/firekit/firebase-app.svelte.d.ts +0 -7
  116. package/dist/components/firekit/node-list.svelte +0 -102
  117. package/dist/components/firekit/node-list.svelte.d.ts +0 -27
  118. package/dist/components/firekit/signed-in.svelte +0 -42
  119. package/dist/components/firekit/signed-out.svelte +0 -42
  120. package/dist/components/firekit/storage-list.svelte +0 -97
  121. package/dist/components/firekit/storage-list.svelte.d.ts +0 -26
  122. package/dist/components/firekit/upload-task.svelte +0 -108
  123. package/dist/components/firekit/upload-task.svelte.d.ts +0 -24
  124. package/dist/components/nav/app-sidebar.svelte +0 -175
  125. package/dist/components/nav/app-sidebar.svelte.d.ts +0 -9
  126. package/dist/components/nav/auto-breadcrumb.svelte +0 -41
  127. package/dist/components/nav/auto-breadcrumb.svelte.d.ts +0 -3
  128. package/dist/components/nav/dark-mode-toggle.svelte +0 -17
  129. package/dist/components/nav/dark-mode-toggle.svelte.d.ts +0 -18
  130. package/dist/components/nav/nav-components.svelte +0 -24
  131. package/dist/components/nav/nav-components.svelte.d.ts +0 -11
  132. package/dist/components/nav/nav-main.svelte +0 -45
  133. package/dist/components/nav/nav-main.svelte.d.ts +0 -11
  134. package/dist/components/nav/nav-secondary.svelte +0 -32
  135. package/dist/components/nav/nav-secondary.svelte.d.ts +0 -14
  136. package/dist/components/nav/site-header.svelte +0 -32
  137. package/dist/components/nav/site-header.svelte.d.ts +0 -18
  138. package/dist/components/ui/avatar/avatar-fallback.svelte +0 -17
  139. package/dist/components/ui/avatar/avatar-fallback.svelte.d.ts +0 -4
  140. package/dist/components/ui/avatar/avatar-image.svelte +0 -17
  141. package/dist/components/ui/avatar/avatar-image.svelte.d.ts +0 -4
  142. package/dist/components/ui/avatar/avatar.svelte +0 -19
  143. package/dist/components/ui/avatar/avatar.svelte.d.ts +0 -4
  144. package/dist/components/ui/avatar/index.d.ts +0 -4
  145. package/dist/components/ui/avatar/index.js +0 -6
  146. package/dist/components/ui/badge/badge.svelte +0 -50
  147. package/dist/components/ui/badge/badge.svelte.d.ts +0 -32
  148. package/dist/components/ui/badge/index.d.ts +0 -2
  149. package/dist/components/ui/badge/index.js +0 -2
  150. package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +0 -23
  151. package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte.d.ts +0 -5
  152. package/dist/components/ui/breadcrumb/breadcrumb-item.svelte +0 -20
  153. package/dist/components/ui/breadcrumb/breadcrumb-item.svelte.d.ts +0 -5
  154. package/dist/components/ui/breadcrumb/breadcrumb-link.svelte +0 -31
  155. package/dist/components/ui/breadcrumb/breadcrumb-link.svelte.d.ts +0 -11
  156. package/dist/components/ui/breadcrumb/breadcrumb-list.svelte +0 -23
  157. package/dist/components/ui/breadcrumb/breadcrumb-list.svelte.d.ts +0 -5
  158. package/dist/components/ui/breadcrumb/breadcrumb-page.svelte +0 -23
  159. package/dist/components/ui/breadcrumb/breadcrumb-page.svelte.d.ts +0 -5
  160. package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +0 -27
  161. package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte.d.ts +0 -5
  162. package/dist/components/ui/breadcrumb/breadcrumb.svelte +0 -21
  163. package/dist/components/ui/breadcrumb/breadcrumb.svelte.d.ts +0 -5
  164. package/dist/components/ui/breadcrumb/index.d.ts +0 -8
  165. package/dist/components/ui/breadcrumb/index.js +0 -10
  166. package/dist/components/ui/button/button.svelte +0 -80
  167. package/dist/components/ui/button/button.svelte.d.ts +0 -58
  168. package/dist/components/ui/button/index.d.ts +0 -2
  169. package/dist/components/ui/button/index.js +0 -4
  170. package/dist/components/ui/card/card-action.svelte +0 -20
  171. package/dist/components/ui/card/card-action.svelte.d.ts +0 -5
  172. package/dist/components/ui/card/card-content.svelte +0 -15
  173. package/dist/components/ui/card/card-content.svelte.d.ts +0 -5
  174. package/dist/components/ui/card/card-description.svelte +0 -20
  175. package/dist/components/ui/card/card-description.svelte.d.ts +0 -5
  176. package/dist/components/ui/card/card-footer.svelte +0 -20
  177. package/dist/components/ui/card/card-footer.svelte.d.ts +0 -5
  178. package/dist/components/ui/card/card-header.svelte +0 -23
  179. package/dist/components/ui/card/card-header.svelte.d.ts +0 -5
  180. package/dist/components/ui/card/card-title.svelte +0 -20
  181. package/dist/components/ui/card/card-title.svelte.d.ts +0 -5
  182. package/dist/components/ui/card/card.svelte +0 -23
  183. package/dist/components/ui/card/card.svelte.d.ts +0 -5
  184. package/dist/components/ui/card/index.d.ts +0 -8
  185. package/dist/components/ui/card/index.js +0 -10
  186. package/dist/components/ui/chart/chart-container.svelte +0 -80
  187. package/dist/components/ui/chart/chart-container.svelte.d.ts +0 -9
  188. package/dist/components/ui/chart/chart-style.svelte +0 -36
  189. package/dist/components/ui/chart/chart-style.svelte.d.ts +0 -8
  190. package/dist/components/ui/chart/chart-tooltip.svelte +0 -159
  191. package/dist/components/ui/chart/chart-tooltip.svelte.d.ts +0 -27
  192. package/dist/components/ui/chart/chart-utils.d.ts +0 -36
  193. package/dist/components/ui/chart/chart-utils.js +0 -33
  194. package/dist/components/ui/chart/index.d.ts +0 -4
  195. package/dist/components/ui/chart/index.js +0 -4
  196. package/dist/components/ui/checkbox/checkbox.svelte +0 -36
  197. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +0 -4
  198. package/dist/components/ui/checkbox/index.d.ts +0 -2
  199. package/dist/components/ui/checkbox/index.js +0 -4
  200. package/dist/components/ui/data-table/data-table.svelte.d.ts +0 -40
  201. package/dist/components/ui/data-table/data-table.svelte.js +0 -110
  202. package/dist/components/ui/data-table/flex-render.svelte +0 -36
  203. package/dist/components/ui/data-table/flex-render.svelte.d.ts +0 -30
  204. package/dist/components/ui/data-table/index.d.ts +0 -3
  205. package/dist/components/ui/data-table/index.js +0 -3
  206. package/dist/components/ui/data-table/render-helpers.d.ts +0 -90
  207. package/dist/components/ui/data-table/render-helpers.js +0 -99
  208. package/dist/components/ui/dialog/dialog-close.svelte +0 -7
  209. package/dist/components/ui/dialog/dialog-close.svelte.d.ts +0 -4
  210. package/dist/components/ui/dialog/dialog-content.svelte +0 -43
  211. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +0 -11
  212. package/dist/components/ui/dialog/dialog-description.svelte +0 -17
  213. package/dist/components/ui/dialog/dialog-description.svelte.d.ts +0 -4
  214. package/dist/components/ui/dialog/dialog-footer.svelte +0 -20
  215. package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +0 -5
  216. package/dist/components/ui/dialog/dialog-header.svelte +0 -20
  217. package/dist/components/ui/dialog/dialog-header.svelte.d.ts +0 -5
  218. package/dist/components/ui/dialog/dialog-overlay.svelte +0 -20
  219. package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +0 -4
  220. package/dist/components/ui/dialog/dialog-title.svelte +0 -17
  221. package/dist/components/ui/dialog/dialog-title.svelte.d.ts +0 -4
  222. package/dist/components/ui/dialog/dialog-trigger.svelte +0 -7
  223. package/dist/components/ui/dialog/dialog-trigger.svelte.d.ts +0 -4
  224. package/dist/components/ui/dialog/index.d.ts +0 -11
  225. package/dist/components/ui/dialog/index.js +0 -14
  226. package/dist/components/ui/drawer/drawer-close.svelte +0 -7
  227. package/dist/components/ui/drawer/drawer-close.svelte.d.ts +0 -4
  228. package/dist/components/ui/drawer/drawer-content.svelte +0 -37
  229. package/dist/components/ui/drawer/drawer-content.svelte.d.ts +0 -7
  230. package/dist/components/ui/drawer/drawer-description.svelte +0 -17
  231. package/dist/components/ui/drawer/drawer-description.svelte.d.ts +0 -4
  232. package/dist/components/ui/drawer/drawer-footer.svelte +0 -20
  233. package/dist/components/ui/drawer/drawer-footer.svelte.d.ts +0 -5
  234. package/dist/components/ui/drawer/drawer-header.svelte +0 -20
  235. package/dist/components/ui/drawer/drawer-header.svelte.d.ts +0 -5
  236. package/dist/components/ui/drawer/drawer-nested.svelte +0 -12
  237. package/dist/components/ui/drawer/drawer-nested.svelte.d.ts +0 -3
  238. package/dist/components/ui/drawer/drawer-overlay.svelte +0 -20
  239. package/dist/components/ui/drawer/drawer-overlay.svelte.d.ts +0 -4
  240. package/dist/components/ui/drawer/drawer-title.svelte +0 -17
  241. package/dist/components/ui/drawer/drawer-title.svelte.d.ts +0 -4
  242. package/dist/components/ui/drawer/drawer-trigger.svelte +0 -7
  243. package/dist/components/ui/drawer/drawer-trigger.svelte.d.ts +0 -4
  244. package/dist/components/ui/drawer/drawer.svelte +0 -12
  245. package/dist/components/ui/drawer/drawer.svelte.d.ts +0 -3
  246. package/dist/components/ui/drawer/index.d.ts +0 -13
  247. package/dist/components/ui/drawer/index.js +0 -15
  248. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -41
  249. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +0 -9
  250. package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
  251. package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte.d.ts +0 -7
  252. package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -22
  253. package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +0 -8
  254. package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
  255. package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte.d.ts +0 -4
  256. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -27
  257. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +0 -8
  258. package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -24
  259. package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte.d.ts +0 -8
  260. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
  261. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +0 -4
  262. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -31
  263. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +0 -4
  264. package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
  265. package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte.d.ts +0 -4
  266. package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -20
  267. package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +0 -5
  268. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -20
  269. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +0 -4
  270. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -29
  271. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +0 -7
  272. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
  273. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +0 -4
  274. package/dist/components/ui/dropdown-menu/index.d.ts +0 -25
  275. package/dist/components/ui/dropdown-menu/index.js +0 -17
  276. package/dist/components/ui/input/index.d.ts +0 -2
  277. package/dist/components/ui/input/index.js +0 -4
  278. package/dist/components/ui/input/input.svelte +0 -51
  279. package/dist/components/ui/input/input.svelte.d.ts +0 -13
  280. package/dist/components/ui/label/index.d.ts +0 -2
  281. package/dist/components/ui/label/index.js +0 -4
  282. package/dist/components/ui/label/label.svelte +0 -20
  283. package/dist/components/ui/label/label.svelte.d.ts +0 -4
  284. package/dist/components/ui/scroll-area/index.d.ts +0 -3
  285. package/dist/components/ui/scroll-area/index.js +0 -5
  286. package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +0 -31
  287. package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte.d.ts +0 -4
  288. package/dist/components/ui/scroll-area/scroll-area.svelte +0 -40
  289. package/dist/components/ui/scroll-area/scroll-area.svelte.d.ts +0 -10
  290. package/dist/components/ui/select/index.d.ts +0 -11
  291. package/dist/components/ui/select/index.js +0 -14
  292. package/dist/components/ui/select/select-content.svelte +0 -40
  293. package/dist/components/ui/select/select-content.svelte.d.ts +0 -8
  294. package/dist/components/ui/select/select-group-heading.svelte +0 -21
  295. package/dist/components/ui/select/select-group-heading.svelte.d.ts +0 -10
  296. package/dist/components/ui/select/select-group.svelte +0 -7
  297. package/dist/components/ui/select/select-group.svelte.d.ts +0 -4
  298. package/dist/components/ui/select/select-item.svelte +0 -38
  299. package/dist/components/ui/select/select-item.svelte.d.ts +0 -4
  300. package/dist/components/ui/select/select-label.svelte +0 -20
  301. package/dist/components/ui/select/select-label.svelte.d.ts +0 -6
  302. package/dist/components/ui/select/select-scroll-down-button.svelte +0 -20
  303. package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +0 -4
  304. package/dist/components/ui/select/select-scroll-up-button.svelte +0 -20
  305. package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +0 -4
  306. package/dist/components/ui/select/select-separator.svelte +0 -18
  307. package/dist/components/ui/select/select-separator.svelte.d.ts +0 -4
  308. package/dist/components/ui/select/select-trigger.svelte +0 -29
  309. package/dist/components/ui/select/select-trigger.svelte.d.ts +0 -8
  310. package/dist/components/ui/separator/index.d.ts +0 -2
  311. package/dist/components/ui/separator/index.js +0 -4
  312. package/dist/components/ui/separator/separator.svelte +0 -20
  313. package/dist/components/ui/separator/separator.svelte.d.ts +0 -4
  314. package/dist/components/ui/sheet/index.d.ts +0 -11
  315. package/dist/components/ui/sheet/index.js +0 -14
  316. package/dist/components/ui/sheet/sheet-close.svelte +0 -7
  317. package/dist/components/ui/sheet/sheet-close.svelte.d.ts +0 -4
  318. package/dist/components/ui/sheet/sheet-content.svelte +0 -58
  319. package/dist/components/ui/sheet/sheet-content.svelte.d.ts +0 -35
  320. package/dist/components/ui/sheet/sheet-description.svelte +0 -17
  321. package/dist/components/ui/sheet/sheet-description.svelte.d.ts +0 -4
  322. package/dist/components/ui/sheet/sheet-footer.svelte +0 -20
  323. package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +0 -5
  324. package/dist/components/ui/sheet/sheet-header.svelte +0 -20
  325. package/dist/components/ui/sheet/sheet-header.svelte.d.ts +0 -5
  326. package/dist/components/ui/sheet/sheet-overlay.svelte +0 -20
  327. package/dist/components/ui/sheet/sheet-overlay.svelte.d.ts +0 -4
  328. package/dist/components/ui/sheet/sheet-title.svelte +0 -17
  329. package/dist/components/ui/sheet/sheet-title.svelte.d.ts +0 -4
  330. package/dist/components/ui/sheet/sheet-trigger.svelte +0 -7
  331. package/dist/components/ui/sheet/sheet-trigger.svelte.d.ts +0 -4
  332. package/dist/components/ui/sidebar/constants.d.ts +0 -6
  333. package/dist/components/ui/sidebar/constants.js +0 -6
  334. package/dist/components/ui/sidebar/context.svelte.d.ts +0 -42
  335. package/dist/components/ui/sidebar/context.svelte.js +0 -54
  336. package/dist/components/ui/sidebar/index.d.ts +0 -25
  337. package/dist/components/ui/sidebar/index.js +0 -27
  338. package/dist/components/ui/sidebar/sidebar-content.svelte +0 -24
  339. package/dist/components/ui/sidebar/sidebar-content.svelte.d.ts +0 -5
  340. package/dist/components/ui/sidebar/sidebar-footer.svelte +0 -21
  341. package/dist/components/ui/sidebar/sidebar-footer.svelte.d.ts +0 -5
  342. package/dist/components/ui/sidebar/sidebar-group-action.svelte +0 -36
  343. package/dist/components/ui/sidebar/sidebar-group-action.svelte.d.ts +0 -11
  344. package/dist/components/ui/sidebar/sidebar-group-content.svelte +0 -21
  345. package/dist/components/ui/sidebar/sidebar-group-content.svelte.d.ts +0 -5
  346. package/dist/components/ui/sidebar/sidebar-group-label.svelte +0 -34
  347. package/dist/components/ui/sidebar/sidebar-group-label.svelte.d.ts +0 -11
  348. package/dist/components/ui/sidebar/sidebar-group.svelte +0 -21
  349. package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +0 -5
  350. package/dist/components/ui/sidebar/sidebar-header.svelte +0 -21
  351. package/dist/components/ui/sidebar/sidebar-header.svelte.d.ts +0 -5
  352. package/dist/components/ui/sidebar/sidebar-input.svelte +0 -21
  353. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +0 -11
  354. package/dist/components/ui/sidebar/sidebar-inset.svelte +0 -24
  355. package/dist/components/ui/sidebar/sidebar-inset.svelte.d.ts +0 -5
  356. package/dist/components/ui/sidebar/sidebar-menu-action.svelte +0 -43
  357. package/dist/components/ui/sidebar/sidebar-menu-action.svelte.d.ts +0 -12
  358. package/dist/components/ui/sidebar/sidebar-menu-badge.svelte +0 -29
  359. package/dist/components/ui/sidebar/sidebar-menu-badge.svelte.d.ts +0 -5
  360. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +0 -103
  361. package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +0 -51
  362. package/dist/components/ui/sidebar/sidebar-menu-item.svelte +0 -21
  363. package/dist/components/ui/sidebar/sidebar-menu-item.svelte.d.ts +0 -5
  364. package/dist/components/ui/sidebar/sidebar-menu-skeleton.svelte +0 -36
  365. package/dist/components/ui/sidebar/sidebar-menu-skeleton.svelte.d.ts +0 -8
  366. package/dist/components/ui/sidebar/sidebar-menu-sub-button.svelte +0 -43
  367. package/dist/components/ui/sidebar/sidebar-menu-sub-button.svelte.d.ts +0 -13
  368. package/dist/components/ui/sidebar/sidebar-menu-sub-item.svelte +0 -21
  369. package/dist/components/ui/sidebar/sidebar-menu-sub-item.svelte.d.ts +0 -5
  370. package/dist/components/ui/sidebar/sidebar-menu-sub.svelte +0 -25
  371. package/dist/components/ui/sidebar/sidebar-menu-sub.svelte.d.ts +0 -5
  372. package/dist/components/ui/sidebar/sidebar-menu.svelte +0 -21
  373. package/dist/components/ui/sidebar/sidebar-menu.svelte.d.ts +0 -5
  374. package/dist/components/ui/sidebar/sidebar-provider.svelte +0 -53
  375. package/dist/components/ui/sidebar/sidebar-provider.svelte.d.ts +0 -9
  376. package/dist/components/ui/sidebar/sidebar-rail.svelte +0 -36
  377. package/dist/components/ui/sidebar/sidebar-rail.svelte.d.ts +0 -5
  378. package/dist/components/ui/sidebar/sidebar-separator.svelte +0 -19
  379. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +0 -13
  380. package/dist/components/ui/sidebar/sidebar-trigger.svelte +0 -35
  381. package/dist/components/ui/sidebar/sidebar-trigger.svelte.d.ts +0 -8
  382. package/dist/components/ui/sidebar/sidebar.svelte +0 -104
  383. package/dist/components/ui/sidebar/sidebar.svelte.d.ts +0 -10
  384. package/dist/components/ui/skeleton/index.d.ts +0 -2
  385. package/dist/components/ui/skeleton/index.js +0 -4
  386. package/dist/components/ui/skeleton/skeleton.svelte +0 -17
  387. package/dist/components/ui/skeleton/skeleton.svelte.d.ts +0 -5
  388. package/dist/components/ui/table/index.d.ts +0 -9
  389. package/dist/components/ui/table/index.js +0 -11
  390. package/dist/components/ui/table/table-body.svelte +0 -20
  391. package/dist/components/ui/table/table-body.svelte.d.ts +0 -5
  392. package/dist/components/ui/table/table-caption.svelte +0 -20
  393. package/dist/components/ui/table/table-caption.svelte.d.ts +0 -5
  394. package/dist/components/ui/table/table-cell.svelte +0 -20
  395. package/dist/components/ui/table/table-cell.svelte.d.ts +0 -5
  396. package/dist/components/ui/table/table-footer.svelte +0 -20
  397. package/dist/components/ui/table/table-footer.svelte.d.ts +0 -5
  398. package/dist/components/ui/table/table-head.svelte +0 -23
  399. package/dist/components/ui/table/table-head.svelte.d.ts +0 -5
  400. package/dist/components/ui/table/table-header.svelte +0 -20
  401. package/dist/components/ui/table/table-header.svelte.d.ts +0 -5
  402. package/dist/components/ui/table/table-row.svelte +0 -23
  403. package/dist/components/ui/table/table-row.svelte.d.ts +0 -5
  404. package/dist/components/ui/table/table.svelte +0 -22
  405. package/dist/components/ui/table/table.svelte.d.ts +0 -5
  406. package/dist/components/ui/tabs/index.d.ts +0 -5
  407. package/dist/components/ui/tabs/index.js +0 -7
  408. package/dist/components/ui/tabs/tabs-content.svelte +0 -17
  409. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +0 -4
  410. package/dist/components/ui/tabs/tabs-list.svelte +0 -20
  411. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +0 -4
  412. package/dist/components/ui/tabs/tabs-trigger.svelte +0 -20
  413. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +0 -4
  414. package/dist/components/ui/tabs/tabs.svelte +0 -19
  415. package/dist/components/ui/tabs/tabs.svelte.d.ts +0 -4
  416. package/dist/components/ui/toggle/index.d.ts +0 -3
  417. package/dist/components/ui/toggle/index.js +0 -5
  418. package/dist/components/ui/toggle/toggle.svelte +0 -52
  419. package/dist/components/ui/toggle/toggle.svelte.d.ts +0 -43
  420. package/dist/components/ui/toggle-group/index.d.ts +0 -3
  421. package/dist/components/ui/toggle-group/index.js +0 -5
  422. package/dist/components/ui/toggle-group/toggle-group-item.svelte +0 -34
  423. package/dist/components/ui/toggle-group/toggle-group-item.svelte.d.ts +0 -6
  424. package/dist/components/ui/toggle-group/toggle-group.svelte +0 -47
  425. package/dist/components/ui/toggle-group/toggle-group.svelte.d.ts +0 -8
  426. package/dist/components/ui/tooltip/index.d.ts +0 -7
  427. package/dist/components/ui/tooltip/index.js +0 -9
  428. package/dist/components/ui/tooltip/tooltip-content.svelte +0 -47
  429. package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +0 -7
  430. package/dist/components/ui/tooltip/tooltip-trigger.svelte +0 -7
  431. package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +0 -4
  432. package/dist/hooks/is-mobile.svelte.d.ts +0 -4
  433. package/dist/hooks/is-mobile.svelte.js +0 -7
  434. package/dist/services/index.d.ts +0 -9
  435. package/dist/services/index.js +0 -10
  436. package/dist/types/docs.d.ts +0 -67
  437. package/dist/utils.d.ts +0 -15
  438. package/dist/utils.js +0 -44
  439. /package/dist/{types/docs.js → services/in-app-messaging.d.ts} +0 -0
@@ -1,982 +1,233 @@
1
- /**
2
- * @fileoverview FirekitDocumentMutations - Optimized document mutation service for Svelte
3
- * @module FirekitDocumentMutations
4
- * @version 1.0.0
5
- */
6
- import { addDoc, setDoc, updateDoc, deleteDoc, doc, getDoc, collection, serverTimestamp, increment, arrayUnion, arrayRemove, deleteField, writeBatch, runTransaction } from 'firebase/firestore';
1
+ import { doc, collection, addDoc, setDoc, updateDoc, deleteDoc, getDoc, writeBatch, runTransaction, serverTimestamp as firestoreServerTimestamp, increment as firestoreIncrement, arrayUnion as firestoreArrayUnion, arrayRemove as firestoreArrayRemove, deleteField as firestoreDeleteField } from 'firebase/firestore';
7
2
  import { firebaseService } from '../firebase.js';
8
- import { firekitUser } from './user.svelte.js';
9
- import { MutationOperationType, MutationErrorCode, MutationError } from '../types/mutations.js';
10
- import { CacheSource } from '../types/document.js';
11
- /**
12
- * Comprehensive Firestore document mutation service with advanced features.
13
- * Handles CRUD operations, batch processing, validation, error handling, and analytics.
14
- *
15
- * @class FirekitDocumentMutations
16
- * @example
17
- * ```typescript
18
- * import { firekitDocMutations } from 'svelte-firekit';
19
- *
20
- * // Add a new document
21
- * const result = await firekitDocMutations.add('users', {
22
- * name: 'John Doe',
23
- * email: 'john@example.com'
24
- * }, {
25
- * timestamps: true,
26
- * validate: true
27
- * });
28
- *
29
- * // Batch operations
30
- * const batchResult = await firekitDocMutations.batch([
31
- * { type: 'create', path: 'users', data: userData },
32
- * { type: 'update', path: 'profiles/123', data: profileUpdate }
33
- * ]);
34
- * ```
35
- */
36
- class FirekitDocumentMutations {
37
- analytics = this.initializeAnalytics();
38
- defaultOptions = {
39
- timestamps: true,
40
- merge: false,
41
- validate: false,
42
- optimistic: false,
43
- retry: {
44
- enabled: true,
45
- maxAttempts: 3,
46
- baseDelay: 1000,
47
- strategy: 'exponential'
48
- }
49
- };
50
- /**
51
- * Initialize analytics object
52
- */
53
- initializeAnalytics() {
54
- return {
55
- totalMutations: 0,
56
- successfulMutations: 0,
57
- failedMutations: 0,
58
- successRate: 0,
59
- averageDuration: 0,
60
- commonErrors: [],
61
- performanceByOperation: {},
62
- retryStats: {
63
- totalRetries: 0,
64
- retriesPerMutation: 0,
65
- retrySuccessRate: 0
66
- }
67
- };
68
- }
69
- /**
70
- * Generate timestamp data for document mutations
71
- */
72
- getTimestampData(isNew = true) {
73
- const timestamps = {
74
- updatedAt: serverTimestamp(),
75
- updatedBy: firekitUser.uid || 'anonymous'
76
- };
77
- if (isNew) {
78
- timestamps.createdAt = serverTimestamp();
79
- timestamps.createdBy = firekitUser.uid || 'anonymous';
80
- }
81
- return timestamps;
82
- }
83
- /**
84
- * Validate data using custom validator or basic validation
85
- */
86
- validateData(data, validator) {
87
- if (validator) {
88
- return validator(data);
89
- }
90
- // Basic validation
91
- if (!data || typeof data !== 'object') {
92
- return {
93
- valid: false,
94
- message: 'Data must be a valid object'
95
- };
96
- }
97
- // Check for null/undefined values in top-level fields
98
- const invalidFields = {};
99
- for (const [key, value] of Object.entries(data)) {
100
- if (value === null || value === undefined) {
101
- invalidFields[key] = 'Field cannot be null or undefined';
102
- }
103
- }
104
- if (Object.keys(invalidFields).length > 0) {
105
- return {
106
- valid: false,
107
- message: 'Some fields contain invalid values',
108
- fieldErrors: invalidFields
109
- };
110
- }
111
- return { valid: true };
112
- }
113
- /**
114
- * Handle and format mutation errors
115
- */
116
- handleError(error, operation, path) {
117
- let mutationError;
118
- if (error instanceof MutationError) {
119
- mutationError = error;
120
- }
121
- else {
122
- // Map Firestore errors to MutationError
123
- const code = this.mapFirestoreErrorCode(error.code);
124
- mutationError = new MutationError(code, error.message || 'An unknown error occurred', operation, path, error);
125
- }
126
- // Update analytics
127
- this.analytics.failedMutations++;
128
- this.updateErrorAnalytics(mutationError);
129
- console.error('FirekitDocumentMutations error:', mutationError);
130
- return mutationError;
131
- }
132
- /**
133
- * Map Firestore error codes to MutationErrorCode
134
- */
135
- mapFirestoreErrorCode(firestoreCode) {
136
- switch (firestoreCode) {
137
- case 'permission-denied':
138
- return MutationErrorCode.PERMISSION_DENIED;
139
- case 'not-found':
140
- return MutationErrorCode.NOT_FOUND;
141
- case 'already-exists':
142
- return MutationErrorCode.ALREADY_EXISTS;
143
- case 'failed-precondition':
144
- return MutationErrorCode.FAILED_PRECONDITION;
145
- case 'aborted':
146
- return MutationErrorCode.ABORTED;
147
- case 'out-of-range':
148
- return MutationErrorCode.OUT_OF_RANGE;
149
- case 'unimplemented':
150
- return MutationErrorCode.UNIMPLEMENTED;
151
- case 'internal':
152
- return MutationErrorCode.INTERNAL_ERROR;
153
- case 'unavailable':
154
- return MutationErrorCode.UNAVAILABLE;
155
- case 'deadline-exceeded':
156
- return MutationErrorCode.DEADLINE_EXCEEDED;
157
- case 'unauthenticated':
158
- return MutationErrorCode.UNAUTHENTICATED;
159
- case 'resource-exhausted':
160
- return MutationErrorCode.RESOURCE_EXHAUSTED;
161
- case 'cancelled':
162
- return MutationErrorCode.CANCELLED;
163
- default:
164
- return MutationErrorCode.UNKNOWN;
165
- }
166
- }
167
- /**
168
- * Update error analytics
169
- */
170
- updateErrorAnalytics(error) {
171
- const existingError = this.analytics.commonErrors.find((e) => e.code === error.code);
172
- if (existingError) {
173
- existingError.count++;
174
- }
175
- else {
176
- this.analytics.commonErrors.push({
177
- code: error.code,
178
- count: 1,
179
- percentage: 0
180
- });
181
- }
182
- // Recalculate percentages
183
- const totalErrors = this.analytics.commonErrors.reduce((sum, e) => sum + e.count, 0);
184
- this.analytics.commonErrors.forEach((e) => {
185
- e.percentage = (e.count / totalErrors) * 100;
186
- });
187
- // Sort by count
188
- this.analytics.commonErrors.sort((a, b) => b.count - a.count);
189
- }
190
- /**
191
- * Execute operation with retry logic
192
- */
193
- async executeWithRetry(operation, options, operationName, path) {
194
- const retryConfig = { ...this.defaultOptions.retry, ...options.retry };
195
- let lastError;
196
- let attempt = 0;
197
- while (attempt < retryConfig.maxAttempts) {
198
- try {
199
- if (attempt > 0) {
200
- this.analytics.retryStats.totalRetries++;
201
- }
202
- const result = await operation();
203
- if (attempt > 0) {
204
- // Successful retry
205
- this.analytics.retryStats.retrySuccessRate =
206
- (this.analytics.retryStats.retrySuccessRate + 1) / 2;
207
- }
208
- return result;
209
- }
210
- catch (error) {
211
- lastError = this.handleError(error, operationName, path);
212
- if (!lastError.isRetryable() ||
213
- (retryConfig.shouldRetry && !retryConfig.shouldRetry(lastError, attempt))) {
214
- break;
215
- }
216
- attempt++;
217
- if (attempt < retryConfig.maxAttempts) {
218
- const delay = retryConfig.strategy === 'exponential'
219
- ? Math.min(retryConfig.baseDelay * Math.pow(2, attempt), retryConfig.maxDelay || 30000)
220
- : retryConfig.baseDelay;
221
- await new Promise((resolve) => setTimeout(resolve, delay));
222
- }
223
- }
224
- }
225
- throw lastError;
226
- }
227
- // ========================================
228
- // CRUD OPERATIONS
229
- // ========================================
230
- /**
231
- * Add a new document to a collection
232
- *
233
- * @template T Document data type
234
- * @param collectionPath Collection path
235
- * @param data Document data
236
- * @param options Mutation options
237
- * @returns Promise resolving to mutation response
238
- *
239
- * @example
240
- * ```typescript
241
- * const result = await firekitDocMutations.add('users', {
242
- * name: 'John Doe',
243
- * email: 'john@example.com'
244
- * }, {
245
- * timestamps: true,
246
- * customId: 'custom-user-id',
247
- * validate: true
248
- * });
249
- *
250
- * if (result.success) {
251
- * console.log('Created document:', result.id);
252
- * }
253
- * ```
254
- */
255
- async add(collectionPath, data, options = {}) {
256
- const startTime = Date.now();
257
- const mergedOptions = { ...this.defaultOptions, ...options };
258
- try {
259
- // Validate data if requested
260
- if (mergedOptions.validate) {
261
- const validation = this.validateData(data, mergedOptions.validator);
262
- if (!validation.valid) {
263
- throw new MutationError(MutationErrorCode.VALIDATION_FAILED, validation.message || 'Validation failed', MutationOperationType.CREATE, collectionPath, null, { fieldErrors: validation.fieldErrors });
264
- }
265
- }
266
- const result = await this.executeWithRetry(async () => {
267
- const firestore = firebaseService.getDbInstance();
268
- if (!firestore) {
269
- throw new MutationError(MutationErrorCode.SERVICE_UNAVAILABLE, 'Firestore service not available');
270
- }
271
- const colRef = collection(firestore, collectionPath);
272
- let dataToAdd = {
273
- ...data,
274
- ...(mergedOptions.timestamps && this.getTimestampData())
275
- };
276
- let docRef;
277
- if (mergedOptions.customId) {
278
- docRef = doc(colRef, mergedOptions.customId);
279
- dataToAdd = { ...dataToAdd, id: docRef.id };
280
- await setDoc(docRef, dataToAdd);
281
- }
282
- else {
283
- docRef = (await addDoc(colRef, dataToAdd));
284
- dataToAdd = { ...dataToAdd, id: docRef.id };
285
- await setDoc(docRef, dataToAdd);
286
- }
287
- return {
288
- success: true,
289
- id: docRef.id,
290
- data: { ...dataToAdd, id: docRef.id },
291
- metadata: {
292
- timestamp: new Date(),
293
- operation: MutationOperationType.CREATE,
294
- source: CacheSource.CLIENT,
295
- performedBy: firekitUser.uid ?? 'anonymous',
296
- duration: Date.now() - startTime
297
- }
298
- };
299
- }, mergedOptions, MutationOperationType.CREATE, collectionPath);
300
- // Update analytics
301
- this.analytics.totalMutations++;
302
- this.analytics.successfulMutations++;
303
- this.updateOperationAnalytics(MutationOperationType.CREATE, Date.now() - startTime, true);
304
- return result;
305
- }
306
- catch (error) {
307
- this.analytics.totalMutations++;
308
- const mutationError = error instanceof MutationError
309
- ? error
310
- : this.handleError(error, MutationOperationType.CREATE, collectionPath);
311
- this.updateOperationAnalytics(MutationOperationType.CREATE, Date.now() - startTime, false);
312
- return {
313
- success: false,
314
- error: mutationError,
315
- metadata: {
316
- timestamp: new Date(),
317
- operation: MutationOperationType.CREATE,
318
- source: CacheSource.CLIENT,
319
- performedBy: firekitUser.uid ?? 'anonymous' ?? 'anonymous',
320
- duration: Date.now() - startTime
321
- }
322
- };
3
+ const DEFAULT_OPTIONS = {
4
+ timestamps: true,
5
+ userId: '',
6
+ retry: { enabled: false, maxAttempts: 3, baseDelay: 200, strategy: 'exponential' }
7
+ };
8
+ function getDb() {
9
+ const db = firebaseService.getDbInstance();
10
+ if (!db)
11
+ throw new Error('Firestore is not initialized.');
12
+ return db;
13
+ }
14
+ /** Resolves merged options and runs the validator if enabled. */
15
+ async function resolveOpts(options, data) {
16
+ const opts = { ...DEFAULT_OPTIONS, ...options };
17
+ if (opts.validate && opts.validator && data !== undefined) {
18
+ const result = opts.validator(data);
19
+ if (!result.valid) {
20
+ throw new Error(result.message ?? 'Validation failed');
323
21
  }
324
22
  }
325
- /**
326
- * Set document data at specified path
327
- *
328
- * @template T Document data type
329
- * @param path Document path
330
- * @param data Document data
331
- * @param options Mutation options
332
- * @returns Promise resolving to mutation response
333
- *
334
- * @example
335
- * ```typescript
336
- * const result = await firekitDocMutations.set('users/123', {
337
- * name: 'John Doe',
338
- * email: 'john@example.com'
339
- * }, {
340
- * merge: true,
341
- * timestamps: true
342
- * });
343
- * ```
344
- */
345
- async set(path, data, options = {}) {
346
- const startTime = Date.now();
347
- const mergedOptions = { ...this.defaultOptions, ...options };
23
+ return opts;
24
+ }
25
+ /** Runs fn, retrying on failure according to retryConfig. */
26
+ async function maybeRetry(fn, opts) {
27
+ const retry = opts.retry;
28
+ if (!retry?.enabled)
29
+ return fn();
30
+ return withRetry(fn, retry);
31
+ }
32
+ /** Wait helper for retry backoff. */
33
+ function wait(ms) {
34
+ return new Promise((resolve) => setTimeout(resolve, ms));
35
+ }
36
+ async function withRetry(fn, retryConfig) {
37
+ let lastError;
38
+ for (let attempt = 1; attempt <= retryConfig.maxAttempts; attempt++) {
348
39
  try {
349
- if (mergedOptions.validate) {
350
- const validation = this.validateData(data, mergedOptions.validator);
351
- if (!validation.valid) {
352
- throw new MutationError(MutationErrorCode.VALIDATION_FAILED, validation.message || 'Validation failed', MutationOperationType.SET, path, null, { fieldErrors: validation.fieldErrors });
353
- }
354
- }
355
- const result = await this.executeWithRetry(async () => {
356
- const firestore = firebaseService.getDbInstance();
357
- if (!firestore) {
358
- throw new MutationError(MutationErrorCode.SERVICE_UNAVAILABLE, 'Firestore service not available');
359
- }
360
- const docRef = doc(firestore, path);
361
- const dataToSet = {
362
- ...data,
363
- ...(mergedOptions.timestamps && this.getTimestampData()),
364
- id: docRef.id
365
- };
366
- await setDoc(docRef, dataToSet, { merge: mergedOptions.merge });
367
- return {
368
- success: true,
369
- id: docRef.id,
370
- data: dataToSet,
371
- metadata: {
372
- timestamp: new Date(),
373
- operation: MutationOperationType.SET,
374
- source: CacheSource.CLIENT,
375
- performedBy: firekitUser.uid ?? 'anonymous' ?? 'anonymous',
376
- duration: Date.now() - startTime
377
- }
378
- };
379
- }, mergedOptions, MutationOperationType.SET, path);
380
- this.analytics.totalMutations++;
381
- this.analytics.successfulMutations++;
382
- this.updateOperationAnalytics(MutationOperationType.SET, Date.now() - startTime, true);
383
- return result;
384
- }
385
- catch (error) {
386
- this.analytics.totalMutations++;
387
- const mutationError = error instanceof MutationError
388
- ? error
389
- : this.handleError(error, MutationOperationType.SET, path);
390
- this.updateOperationAnalytics(MutationOperationType.SET, Date.now() - startTime, false);
391
- return {
392
- success: false,
393
- error: mutationError,
394
- metadata: {
395
- timestamp: new Date(),
396
- operation: MutationOperationType.SET,
397
- source: CacheSource.CLIENT,
398
- performedBy: firekitUser.uid ?? 'anonymous' ?? 'anonymous',
399
- duration: Date.now() - startTime
400
- }
401
- };
40
+ return await fn();
402
41
  }
403
- }
404
- /**
405
- * Update a document at specified path
406
- *
407
- * @template T Document data type
408
- * @param path Document path
409
- * @param data Update data
410
- * @param options Mutation options
411
- * @returns Promise resolving to mutation response
412
- *
413
- * @example
414
- * ```typescript
415
- * const result = await firekitDocMutations.update('users/123', {
416
- * name: 'Jane Doe',
417
- * lastLogin: serverTimestamp()
418
- * });
419
- * ```
420
- */
421
- async update(path, data, options = {}) {
422
- const startTime = Date.now();
423
- const mergedOptions = { ...this.defaultOptions, ...options };
424
- try {
425
- if (mergedOptions.validate) {
426
- const validation = this.validateData(data, mergedOptions.validator);
427
- if (!validation.valid) {
428
- throw new MutationError(MutationErrorCode.VALIDATION_FAILED, validation.message || 'Validation failed', MutationOperationType.UPDATE, path, null, { fieldErrors: validation.fieldErrors });
429
- }
42
+ catch (err) {
43
+ lastError = err;
44
+ if (attempt < retryConfig.maxAttempts) {
45
+ await wait(retryConfig.baseDelay * 2 ** (attempt - 1));
430
46
  }
431
- const result = await this.executeWithRetry(async () => {
432
- const firestore = firebaseService.getDbInstance();
433
- if (!firestore) {
434
- throw new MutationError(MutationErrorCode.SERVICE_UNAVAILABLE, 'Firestore service not available');
435
- }
436
- const docRef = doc(firestore, path);
437
- const dataToUpdate = {
438
- ...data,
439
- ...(mergedOptions.timestamps && this.getTimestampData(false))
440
- };
441
- // @ts-ignore
442
- await updateDoc(docRef, dataToUpdate);
443
- return {
444
- success: true,
445
- id: docRef.id,
446
- data: dataToUpdate,
447
- metadata: {
448
- timestamp: new Date(),
449
- operation: MutationOperationType.UPDATE,
450
- source: CacheSource.CLIENT,
451
- performedBy: firekitUser.uid ?? 'anonymous' ?? 'anonymous',
452
- duration: Date.now() - startTime
453
- }
454
- };
455
- }, mergedOptions, MutationOperationType.UPDATE, path);
456
- this.analytics.totalMutations++;
457
- this.analytics.successfulMutations++;
458
- this.updateOperationAnalytics(MutationOperationType.UPDATE, Date.now() - startTime, true);
459
- return result;
460
- }
461
- catch (error) {
462
- this.analytics.totalMutations++;
463
- const mutationError = error instanceof MutationError
464
- ? error
465
- : this.handleError(error, MutationOperationType.UPDATE, path);
466
- this.updateOperationAnalytics(MutationOperationType.UPDATE, Date.now() - startTime, false);
467
- return {
468
- success: false,
469
- error: mutationError,
470
- metadata: {
471
- timestamp: new Date(),
472
- operation: MutationOperationType.UPDATE,
473
- source: CacheSource.CLIENT,
474
- performedBy: firekitUser.uid ?? 'anonymous' ?? 'anonymous',
475
- duration: Date.now() - startTime
476
- }
477
- };
478
- }
479
- }
480
- /**
481
- * Delete a document at specified path
482
- *
483
- * @param path Document path
484
- * @param options Mutation options
485
- * @returns Promise resolving to mutation response
486
- *
487
- * @example
488
- * ```typescript
489
- * const result = await firekitDocMutations.delete('users/123');
490
- * if (result.success) {
491
- * console.log('Document deleted');
492
- * }
493
- * ```
494
- */
495
- async delete(path, options = {}) {
496
- const startTime = Date.now();
497
- const mergedOptions = { ...this.defaultOptions, ...options };
498
- try {
499
- const result = await this.executeWithRetry(async () => {
500
- const firestore = firebaseService.getDbInstance();
501
- if (!firestore) {
502
- throw new MutationError(MutationErrorCode.SERVICE_UNAVAILABLE, 'Firestore service not available');
503
- }
504
- const docRef = doc(firestore, path);
505
- await deleteDoc(docRef);
506
- return {
507
- success: true,
508
- id: docRef.id,
509
- metadata: {
510
- timestamp: new Date(),
511
- operation: MutationOperationType.DELETE,
512
- source: CacheSource.CLIENT,
513
- performedBy: firekitUser.uid ?? 'anonymous' ?? 'anonymous',
514
- duration: Date.now() - startTime
515
- }
516
- };
517
- }, mergedOptions, MutationOperationType.DELETE, path);
518
- this.analytics.totalMutations++;
519
- this.analytics.successfulMutations++;
520
- this.updateOperationAnalytics(MutationOperationType.DELETE, Date.now() - startTime, true);
521
- return result;
522
47
  }
523
- catch (error) {
524
- this.analytics.totalMutations++;
525
- const mutationError = error instanceof MutationError
526
- ? error
527
- : this.handleError(error, MutationOperationType.DELETE, path);
528
- this.updateOperationAnalytics(MutationOperationType.DELETE, Date.now() - startTime, false);
529
- return {
530
- success: false,
531
- error: mutationError,
532
- metadata: {
533
- timestamp: new Date(),
534
- operation: MutationOperationType.DELETE,
535
- source: CacheSource.CLIENT,
536
- performedBy: firekitUser.uid ?? 'anonymous' ?? 'anonymous',
537
- duration: Date.now() - startTime
538
- }
539
- };
540
- }
541
- }
542
- // ========================================
543
- // FIELD VALUE OPERATIONS
544
- // ========================================
545
- /**
546
- * Increment a numeric field
547
- *
548
- * @param path Document path
549
- * @param field Field name
550
- * @param value Increment value
551
- * @param options Mutation options
552
- * @returns Promise resolving to mutation response
553
- */
554
- async increment(path, field, value, options = {}) {
555
- return this.update(path, { [field]: increment(value) }, options);
556
- }
557
- /**
558
- * Add elements to an array field
559
- *
560
- * @param path Document path
561
- * @param field Field name
562
- * @param elements Elements to add
563
- * @param options Mutation options
564
- * @returns Promise resolving to mutation response
565
- */
566
- async arrayUnion(path, field, elements, options = {}) {
567
- return this.update(path, { [field]: arrayUnion(...elements) }, options);
568
- }
569
- /**
570
- * Remove elements from an array field
571
- *
572
- * @param path Document path
573
- * @param field Field name
574
- * @param elements Elements to remove
575
- * @param options Mutation options
576
- * @returns Promise resolving to mutation response
577
- */
578
- async arrayRemove(path, field, elements, options = {}) {
579
- return this.update(path, { [field]: arrayRemove(...elements) }, options);
580
- }
581
- /**
582
- * Delete a field from document
583
- *
584
- * @param path Document path
585
- * @param field Field name
586
- * @param options Mutation options
587
- * @returns Promise resolving to mutation response
588
- */
589
- async deleteField(path, field, options = {}) {
590
- return this.update(path, { [field]: deleteField() }, options);
591
48
  }
592
- // ========================================
593
- // BATCH OPERATIONS
594
- // ========================================
595
- /**
596
- * Execute multiple operations in a batch
597
- *
598
- * @param operations Array of batch operations
599
- * @param config Bulk mutation configuration
600
- * @returns Promise resolving to batch result
601
- *
602
- * @example
603
- * ```typescript
604
- * const result = await firekitDocMutations.batch([
605
- * { type: 'create', path: 'users', data: userData },
606
- * { type: 'update', path: 'profiles/123', data: profileUpdate },
607
- * { type: 'delete', path: 'temp/456' }
608
- * ], {
609
- * batchSize: 500,
610
- * failFast: false,
611
- * onProgress: (completed, total) => console.log(`${completed}/${total}`)
612
- * });
613
- * ```
49
+ throw lastError;
50
+ }
51
+ /**
52
+ * Firestore document mutations — add, set, update, delete, batch, transaction.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { firekitMutations } from 'svelte-firekit';
57
+ * await firekitMutations.add('users', { name: 'Alice' });
58
+ * await firekitMutations.update('users/uid123', { name: 'Bob' });
59
+ * ```
60
+ */
61
+ class FirekitDocumentMutations {
62
+ static instance;
63
+ constructor() { }
64
+ static getInstance() {
65
+ if (!FirekitDocumentMutations.instance) {
66
+ FirekitDocumentMutations.instance = new FirekitDocumentMutations();
67
+ }
68
+ return FirekitDocumentMutations.instance;
69
+ }
70
+ // ── Helpers ──────────────────────────────────────────────────────────────────
71
+ buildTimestamps(isCreate, userId) {
72
+ const ts = { updatedAt: firestoreServerTimestamp() };
73
+ if (isCreate)
74
+ ts.createdAt = firestoreServerTimestamp();
75
+ if (userId) {
76
+ ts.updatedBy = userId;
77
+ if (isCreate)
78
+ ts.createdBy = userId;
79
+ }
80
+ return ts;
81
+ }
82
+ resolveRef(pathOrRef) {
83
+ if (typeof pathOrRef !== 'string')
84
+ return pathOrRef;
85
+ const db = getDb();
86
+ const segments = pathOrRef.split('/').filter(Boolean);
87
+ if (segments.length % 2 !== 0)
88
+ throw new Error(`Invalid document path: "${pathOrRef}"`);
89
+ return doc(db, pathOrRef);
90
+ }
91
+ /** Generates a new Firestore document ID for a given collection path. */
92
+ generateId(collectionPath) {
93
+ const db = getDb();
94
+ return doc(collection(db, collectionPath)).id;
95
+ }
96
+ // ── CRUD ─────────────────────────────────────────────────────────────────────
97
+ /**
98
+ * Adds a new document to a collection with an auto-generated ID.
99
+ * Returns the new document reference.
614
100
  */
615
- async batch(operations, config = {}) {
616
- const startTime = Date.now();
617
- const batchConfig = {
618
- parallel: false,
619
- failFast: true,
620
- ...config,
621
- // Enforce Firestore limit of 500 operations per batch
622
- batchSize: Math.min(config.batchSize || 500, 500)
623
- };
101
+ async add(collectionPath, data, options = {}) {
102
+ const opts = await resolveOpts(options, data);
103
+ const payload = opts.timestamps
104
+ ? { ...data, ...this.buildTimestamps(true, opts.userId) }
105
+ : data;
106
+ const db = getDb();
107
+ const colRef = collection(db, collectionPath);
108
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
109
+ return maybeRetry(() => addDoc(colRef, payload), opts);
110
+ }
111
+ /**
112
+ * Sets (overwrites or merges) a document at the given path.
113
+ */
114
+ async set(pathOrRef, data, options = {}) {
115
+ const opts = await resolveOpts(options, data);
116
+ const payload = opts.timestamps
117
+ ? { ...data, ...this.buildTimestamps(true, opts.userId) }
118
+ : data;
119
+ const ref = this.resolveRef(pathOrRef);
120
+ const merge = opts.merge ?? false;
121
+ return maybeRetry(() => merge
122
+ ? setDoc(ref, payload, { merge: true })
123
+ : setDoc(ref, payload), opts);
124
+ }
125
+ /**
126
+ * Updates specific fields of an existing document.
127
+ */
128
+ async update(pathOrRef, data, options = {}) {
129
+ const opts = await resolveOpts(options, data);
130
+ const payload = opts.timestamps
131
+ ? { ...data, ...this.buildTimestamps(false, opts.userId) }
132
+ : data;
133
+ const ref = this.resolveRef(pathOrRef);
134
+ return maybeRetry(() => updateDoc(ref, payload), opts);
135
+ }
136
+ /**
137
+ * Deletes a document.
138
+ */
139
+ async delete(pathOrRef, options = {}) {
140
+ const opts = await resolveOpts(options);
141
+ const ref = this.resolveRef(pathOrRef);
142
+ return maybeRetry(() => deleteDoc(ref), opts);
143
+ }
144
+ // ── Existence ────────────────────────────────────────────────────────────────
145
+ /** Returns true if a document exists at the given path. */
146
+ async exists(pathOrRef) {
147
+ const ref = this.resolveRef(pathOrRef);
148
+ const snap = await getDoc(ref);
149
+ return snap.exists();
150
+ }
151
+ /** Fetches a document snapshot and returns its data, or null if it doesn't exist. */
152
+ async fetch(pathOrRef) {
153
+ const ref = this.resolveRef(pathOrRef);
154
+ const snap = await getDoc(ref);
155
+ return snap.exists() ? snap.data() : null;
156
+ }
157
+ // ── Batch ────────────────────────────────────────────────────────────────────
158
+ /**
159
+ * Executes a batch of mutations, automatically chunked into groups of 500.
160
+ */
161
+ async batchOps(operations, options = {}) {
162
+ if (operations.length === 0)
163
+ return { success: true, count: 0 };
164
+ const opts = await resolveOpts(options);
165
+ const db = getDb();
166
+ const CHUNK = 500;
624
167
  try {
625
- const firestore = firebaseService.getDbInstance();
626
- if (!firestore) {
627
- throw new MutationError(MutationErrorCode.SERVICE_UNAVAILABLE, 'Firestore service not available');
628
- }
629
- const results = [];
630
- const batches = this.chunkArray(operations, batchConfig.batchSize);
631
- let successCount = 0;
632
- let failureCount = 0;
633
- for (let i = 0; i < batches.length; i++) {
634
- const batch = batches[i];
635
- const batchWriter = writeBatch(firestore);
636
- const batchResults = [];
637
- for (const operation of batch) {
638
- try {
639
- await this.addOperationToBatch(batchWriter, operation);
640
- batchResults.push({
641
- operation,
642
- success: true,
643
- duration: 0 // Will be updated after batch commit
644
- });
645
- }
646
- catch (error) {
647
- const mutationError = this.handleError(error, operation.type, operation.path);
648
- batchResults.push({
649
- operation,
650
- success: false,
651
- error: mutationError,
652
- duration: 0
653
- });
654
- failureCount++;
655
- if (batchConfig.failFast) {
656
- throw mutationError;
657
- }
658
- }
659
- }
660
- // Commit batch
661
- const batchStartTime = Date.now();
662
- await batchWriter.commit();
663
- const batchDuration = Date.now() - batchStartTime;
664
- // Update durations
665
- batchResults.forEach((result) => {
666
- result.duration = batchDuration / batch.length;
667
- if (result.success)
668
- successCount++;
669
- });
670
- results.push(...batchResults);
671
- batchConfig.onProgress?.(Math.min((i + 1) * batchConfig.batchSize, operations.length), operations.length);
672
- }
673
- const batchResult = {
674
- success: failureCount === 0,
675
- successCount,
676
- failureCount,
677
- results,
678
- metadata: {
679
- startTime: new Date(startTime),
680
- endTime: new Date(),
681
- duration: Date.now() - startTime,
682
- operationCount: operations.length,
683
- executedBy: firekitUser.uid ?? 'anonymous',
684
- strategy: batchConfig.parallel ? 'parallel' : 'sequential'
685
- }
686
- };
687
- return batchResult;
688
- }
689
- catch (error) {
690
- const mutationError = error instanceof MutationError ? error : this.handleError(error, 'batch');
691
- throw mutationError;
692
- }
693
- }
694
- /**
695
- * Add operation to batch writer
696
- */
697
- async addOperationToBatch(batch, operation) {
698
- const firestore = firebaseService.getDbInstance();
699
- if (!firestore)
700
- throw new Error('Firestore not available');
701
- const options = { ...this.defaultOptions, ...operation.options };
702
- switch (operation.type) {
703
- case 'create': {
704
- let data = operation.data || {};
705
- if (options.timestamps) {
706
- data = { ...data, ...this.getTimestampData() };
707
- }
708
- if (options.validate && operation.data) {
709
- const validation = this.validateData(operation.data, options.validator);
710
- if (!validation.valid) {
711
- throw new MutationError(MutationErrorCode.VALIDATION_FAILED, validation.message || 'Validation failed', operation.type, operation.path);
168
+ for (let i = 0; i < operations.length; i += CHUNK) {
169
+ const chunk = operations.slice(i, i + CHUNK);
170
+ const batch = writeBatch(db);
171
+ for (const op of chunk) {
172
+ const ref = op.id
173
+ ? doc(db, op.path, op.id)
174
+ : doc(db, op.path);
175
+ if (op.type === 'delete') {
176
+ batch.delete(ref);
712
177
  }
713
- }
714
- // For CREATE operations, use addDoc if no custom ID, otherwise use setDoc
715
- if (options.customId) {
716
- // Use setDoc with custom ID
717
- const docRef = doc(firestore, operation.path, options.customId);
718
- batch.set(docRef, { ...data, id: options.customId }, { merge: options.merge });
719
- }
720
- else {
721
- // Use addDoc to let Firestore generate the ID
722
- // Note: We can't use addDoc in a batch, so we need to generate an ID
723
- const docId = this.generateDocumentId();
724
- const docRef = doc(firestore, operation.path, docId);
725
- batch.set(docRef, { ...data, id: docId }, { merge: options.merge });
726
- }
727
- break;
728
- }
729
- case 'set': {
730
- const docRef = doc(firestore, operation.path);
731
- let data = operation.data || {};
732
- if (options.timestamps) {
733
- data = { ...data, ...this.getTimestampData() };
734
- }
735
- if (options.validate && operation.data) {
736
- const validation = this.validateData(operation.data, options.validator);
737
- if (!validation.valid) {
738
- throw new MutationError(MutationErrorCode.VALIDATION_FAILED, validation.message || 'Validation failed', operation.type, operation.path);
178
+ else if (op.type === 'set' && op.data) {
179
+ const payload = opts.timestamps
180
+ ? { ...op.data, ...this.buildTimestamps(true, opts.userId) }
181
+ : op.data;
182
+ op.merge ? batch.set(ref, payload, { merge: true }) : batch.set(ref, payload);
739
183
  }
740
- }
741
- batch.set(docRef, { ...data, id: docRef.id }, { merge: options.merge });
742
- break;
743
- }
744
- case 'update': {
745
- const docRef = doc(firestore, operation.path);
746
- let data = operation.data || {};
747
- if (options.timestamps) {
748
- data = { ...data, ...this.getTimestampData(false) };
749
- }
750
- if (options.validate && operation.data) {
751
- const validation = this.validateData(operation.data, options.validator);
752
- if (!validation.valid) {
753
- throw new MutationError(MutationErrorCode.VALIDATION_FAILED, validation.message || 'Validation failed', operation.type, operation.path);
184
+ else if (op.type === 'update' && op.data) {
185
+ const payload = opts.timestamps
186
+ ? { ...op.data, ...this.buildTimestamps(false, opts.userId) }
187
+ : op.data;
188
+ batch.update(ref, payload);
754
189
  }
755
190
  }
756
- batch.update(docRef, data);
757
- break;
758
- }
759
- case 'delete': {
760
- const docRef = doc(firestore, operation.path);
761
- batch.delete(docRef);
762
- break;
763
- }
764
- default:
765
- throw new MutationError(MutationErrorCode.UNIMPLEMENTED, `Operation type ${operation.type} not supported in batch`);
766
- }
767
- }
768
- /**
769
- * Generate a unique document ID (Firestore-style)
770
- */
771
- generateDocumentId() {
772
- // Generate a Firestore-style document ID (20 characters, alphanumeric)
773
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
774
- let result = '';
775
- for (let i = 0; i < 20; i++) {
776
- result += chars.charAt(Math.floor(Math.random() * chars.length));
777
- }
778
- return result;
779
- }
780
- /**
781
- * Chunk array into smaller arrays
782
- */
783
- chunkArray(array, chunkSize) {
784
- const chunks = [];
785
- for (let i = 0; i < array.length; i += chunkSize) {
786
- chunks.push(array.slice(i, i + chunkSize));
787
- }
788
- return chunks;
789
- }
790
- // ========================================
791
- // UTILITY METHODS
792
- // ========================================
793
- /**
794
- * Check if a document exists at specified path
795
- *
796
- * @param path Document path
797
- * @returns Promise resolving to existence check result
798
- *
799
- * @example
800
- * ```typescript
801
- * const checkResult = await firekitDocMutations.exists('users/123');
802
- * if (checkResult.exists) {
803
- * console.log('Document exists');
804
- * }
805
- * ```
806
- */
807
- async exists(path) {
808
- try {
809
- const firestore = firebaseService.getDbInstance();
810
- if (!firestore) {
811
- throw new MutationError(MutationErrorCode.SERVICE_UNAVAILABLE, 'Firestore service not available');
812
- }
813
- const docRef = doc(firestore, path);
814
- const docSnap = await getDoc(docRef);
815
- return {
816
- exists: docSnap.exists(),
817
- id: docSnap.exists() ? docSnap.id : undefined,
818
- lastModified: docSnap.exists()
819
- ? docSnap.metadata.fromCache
820
- ? undefined
821
- : new Date()
822
- : undefined,
823
- metadata: docSnap.exists()
824
- ? {
825
- size: JSON.stringify(docSnap.data()).length,
826
- updateTime: docSnap.metadata.fromCache ? new Date() : new Date(),
827
- createTime: docSnap.metadata.fromCache ? new Date() : new Date()
828
- }
829
- : undefined
830
- };
831
- }
832
- catch (error) {
833
- console.error('Error checking document existence:', error);
834
- return { exists: false };
835
- }
836
- }
837
- /**
838
- * Get a document at specified path
839
- *
840
- * @template T Document data type
841
- * @param path Document path
842
- * @returns Promise resolving to mutation response with document data
843
- *
844
- * @example
845
- * ```typescript
846
- * const result = await firekitDocMutations.getDoc<UserData>('users/123');
847
- * if (result.success && result.data) {
848
- * console.log('User data:', result.data);
849
- * }
850
- * ```
851
- */
852
- async getDoc(path) {
853
- try {
854
- const firestore = firebaseService.getDbInstance();
855
- if (!firestore) {
856
- throw new MutationError(MutationErrorCode.SERVICE_UNAVAILABLE, 'Firestore service not available');
191
+ await batch.commit();
857
192
  }
858
- const docRef = doc(firestore, path);
859
- const docSnap = await getDoc(docRef);
860
- if (!docSnap.exists()) {
861
- return {
862
- success: false,
863
- error: new MutationError(MutationErrorCode.NOT_FOUND, 'Document does not exist', undefined, path)
864
- };
865
- }
866
- return {
867
- success: true,
868
- id: docSnap.id,
869
- data: { id: docSnap.id, ...docSnap.data() },
870
- metadata: {
871
- timestamp: new Date(),
872
- operation: MutationOperationType.READ,
873
- source: docSnap.metadata.fromCache ? CacheSource.CACHE : CacheSource.SERVER,
874
- performedBy: firekitUser.uid ?? 'anonymous',
875
- fromCache: docSnap.metadata.fromCache
876
- }
877
- };
193
+ return { success: true, count: operations.length };
878
194
  }
879
- catch (error) {
880
- const mutationError = this.handleError(error, 'read', path);
195
+ catch (err) {
881
196
  return {
882
197
  success: false,
883
- error: mutationError
884
- };
885
- }
886
- }
887
- /**
888
- * Update operation analytics
889
- */
890
- updateOperationAnalytics(operation, duration, success) {
891
- if (!this.analytics.performanceByOperation[operation]) {
892
- this.analytics.performanceByOperation[operation] = {
893
198
  count: 0,
894
- averageDuration: 0,
895
- successRate: 0
199
+ error: err instanceof Error ? err : new Error(String(err))
896
200
  };
897
201
  }
898
- const stats = this.analytics.performanceByOperation[operation];
899
- stats.count++;
900
- stats.averageDuration = (stats.averageDuration * (stats.count - 1) + duration) / stats.count;
901
- if (success) {
902
- stats.successRate = (stats.successRate * (stats.count - 1) + 100) / stats.count;
903
- }
904
- else {
905
- stats.successRate = (stats.successRate * (stats.count - 1)) / stats.count;
906
- }
907
- // Update overall analytics
908
- this.analytics.successRate =
909
- (this.analytics.successfulMutations / this.analytics.totalMutations) * 100;
910
- this.analytics.averageDuration =
911
- (this.analytics.averageDuration * (this.analytics.totalMutations - 1) + duration) /
912
- this.analytics.totalMutations;
913
202
  }
203
+ // ── Transaction ──────────────────────────────────────────────────────────────
914
204
  /**
915
- * Get current mutation analytics
916
- *
917
- * @returns Current analytics data
205
+ * Runs a Firestore transaction.
918
206
  */
919
- getAnalytics() {
920
- return { ...this.analytics };
207
+ async transaction(fn) {
208
+ const db = getDb();
209
+ return runTransaction(db, fn);
921
210
  }
922
- /**
923
- * Reset analytics data
924
- */
925
- resetAnalytics() {
926
- this.analytics = this.initializeAnalytics();
211
+ // ── Field value helpers ──────────────────────────────────────────────────────
212
+ /** Firestore server timestamp sentinel. */
213
+ serverTimestamp() {
214
+ return firestoreServerTimestamp();
927
215
  }
928
- // ========================================
929
- // STATIC FIELD VALUE HELPERS
930
- // ========================================
931
- /**
932
- * Create server timestamp field value
933
- */
934
- static serverTimestamp() {
935
- return serverTimestamp();
936
- }
937
- /**
938
- * Create increment field value
939
- */
940
- static increment(value) {
941
- return increment(value);
216
+ /** Firestore increment sentinel. */
217
+ increment(n) {
218
+ return firestoreIncrement(n);
942
219
  }
943
- /**
944
- * Create array union field value
945
- */
946
- static arrayUnion(...elements) {
947
- return arrayUnion(...elements);
220
+ /** Firestore arrayUnion sentinel. */
221
+ arrayUnion(...elements) {
222
+ return firestoreArrayUnion(...elements);
948
223
  }
949
- /**
950
- * Create array remove field value
951
- */
952
- static arrayRemove(...elements) {
953
- return arrayRemove(...elements);
224
+ /** Firestore arrayRemove sentinel. */
225
+ arrayRemove(...elements) {
226
+ return firestoreArrayRemove(...elements);
954
227
  }
955
- /**
956
- * Create delete field value
957
- */
958
- static deleteField() {
959
- return deleteField();
228
+ /** Firestore deleteField sentinel. */
229
+ deleteField() {
230
+ return firestoreDeleteField();
960
231
  }
961
232
  }
962
- /**
963
- * Pre-initialized singleton instance of FirekitDocumentMutations.
964
- *
965
- * @example
966
- * ```typescript
967
- * import { firekitDocMutations } from 'svelte-firekit';
968
- *
969
- * // Add document
970
- * const result = await firekitDocMutations.add('users', userData);
971
- *
972
- * // Update document
973
- * await firekitDocMutations.update('users/123', { name: 'New Name' });
974
- *
975
- * // Batch operations
976
- * const batchResult = await firekitDocMutations.batch([
977
- * { type: 'create', path: 'users', data: userData },
978
- * { type: 'update', path: 'profiles/123', data: updateData }
979
- * ]);
980
- * ```
981
- */
982
- export const firekitDocMutations = new FirekitDocumentMutations();
233
+ export const firekitMutations = FirekitDocumentMutations.getInstance();