svelte-firekit 0.1.9 → 0.2.0
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.
- package/README.md +550 -354
- package/dist/components/AuthGuard.svelte +64 -0
- package/dist/components/AuthGuard.svelte.d.ts +15 -0
- package/dist/components/Collection.svelte +62 -0
- package/dist/components/Collection.svelte.d.ts +39 -0
- package/dist/components/CustomGuard.svelte +87 -0
- package/dist/components/CustomGuard.svelte.d.ts +13 -0
- package/dist/components/Doc.svelte +56 -0
- package/dist/components/Doc.svelte.d.ts +36 -0
- package/dist/components/DownloadURL.svelte +48 -0
- package/dist/components/DownloadURL.svelte.d.ts +14 -0
- package/dist/components/FirebaseApp.svelte +81 -0
- package/dist/components/FirebaseApp.svelte.d.ts +12 -0
- package/dist/components/Node.svelte +54 -0
- package/dist/components/Node.svelte.d.ts +36 -0
- package/dist/components/SignedIn.svelte +22 -0
- package/dist/components/{firekit/signed-in.svelte.d.ts → SignedIn.svelte.d.ts} +1 -4
- package/dist/components/SignedOut.svelte +32 -0
- package/dist/components/{firekit/signed-out.svelte.d.ts → SignedOut.svelte.d.ts} +3 -5
- package/dist/components/UploadTask.svelte +75 -0
- package/dist/components/UploadTask.svelte.d.ts +33 -0
- package/dist/config.d.ts +29 -6
- package/dist/config.js +37 -74
- package/dist/context.d.ts +46 -0
- package/dist/context.js +56 -0
- package/dist/firebase.d.ts +25 -84
- package/dist/firebase.js +75 -125
- package/dist/index.d.ts +32 -20
- package/dist/index.js +49 -30
- package/dist/services/ai.svelte.d.ts +152 -0
- package/dist/services/ai.svelte.js +302 -0
- package/dist/services/analytics.d.ts +39 -231
- package/dist/services/analytics.js +89 -421
- package/dist/services/app-check.svelte.d.ts +82 -0
- package/dist/services/app-check.svelte.js +159 -0
- package/dist/services/auth.d.ts +63 -352
- package/dist/services/auth.js +353 -718
- package/dist/services/bundles.d.ts +42 -0
- package/dist/services/bundles.js +57 -0
- package/dist/services/callable.d.ts +57 -0
- package/dist/services/callable.js +115 -0
- package/dist/services/collection.svelte.d.ts +154 -221
- package/dist/services/collection.svelte.js +357 -663
- package/dist/services/document.svelte.d.ts +73 -254
- package/dist/services/document.svelte.js +196 -497
- package/dist/services/in-app-messaging.d.ts +46 -0
- package/dist/services/in-app-messaging.js +88 -0
- package/dist/services/messaging.svelte.d.ts +75 -0
- package/dist/services/messaging.svelte.js +190 -0
- package/dist/services/mutations.d.ts +59 -282
- package/dist/services/mutations.js +202 -951
- package/dist/services/performance.d.ts +60 -0
- package/dist/services/performance.js +118 -0
- package/dist/services/presence.svelte.d.ts +21 -89
- package/dist/services/presence.svelte.js +232 -469
- package/dist/services/realtime.svelte.d.ts +54 -125
- package/dist/services/realtime.svelte.js +111 -175
- package/dist/services/remote-config.svelte.d.ts +73 -0
- package/dist/services/remote-config.svelte.js +204 -0
- package/dist/services/storage.svelte.d.ts +81 -208
- package/dist/services/storage.svelte.js +190 -305
- package/dist/services/user.svelte.d.ts +23 -244
- package/dist/services/user.svelte.js +129 -439
- package/dist/types/analytics.d.ts +2 -36
- package/dist/types/analytics.js +0 -5
- package/dist/types/auth.d.ts +15 -85
- package/dist/types/auth.js +0 -17
- package/dist/types/collection.d.ts +31 -225
- package/dist/types/collection.js +5 -51
- package/dist/types/document.d.ts +11 -236
- package/dist/types/document.js +2 -47
- package/dist/types/firebase.d.ts +10 -13
- package/dist/types/firebase.js +3 -9
- package/dist/types/index.d.ts +5 -5
- package/dist/types/index.js +5 -4
- package/dist/types/mutations.d.ts +11 -225
- package/dist/types/mutations.js +6 -51
- package/dist/types/presence.d.ts +5 -158
- package/dist/types/presence.js +0 -20
- package/dist/utils/errors.d.ts +10 -14
- package/dist/utils/errors.js +11 -16
- package/dist/utils/firestore.d.ts +3 -4
- package/dist/utils/firestore.js +7 -10
- package/dist/utils/index.d.ts +4 -4
- package/dist/utils/index.js +4 -8
- package/dist/utils/providers.d.ts +4 -13
- package/dist/utils/providers.js +14 -13
- package/dist/utils/user.d.ts +1 -3
- package/dist/utils/user.js +1 -3
- package/package.json +41 -55
- package/dist/components/docs/doc-content.svelte +0 -19
- package/dist/components/docs/doc-content.svelte.d.ts +0 -6
- package/dist/components/docs/doc-header.svelte +0 -24
- package/dist/components/docs/doc-header.svelte.d.ts +0 -13
- package/dist/components/docs/doc-renderer.svelte +0 -27
- package/dist/components/docs/doc-renderer.svelte.d.ts +0 -8
- package/dist/components/docs/mobile-table-of-contents.svelte +0 -42
- package/dist/components/docs/mobile-table-of-contents.svelte.d.ts +0 -3
- package/dist/components/docs/table-of-contents.svelte +0 -33
- package/dist/components/docs/table-of-contents.svelte.d.ts +0 -4
- package/dist/components/docs/toc.svelte.d.ts +0 -16
- package/dist/components/docs/toc.svelte.js +0 -59
- package/dist/components/firekit/Collection.svelte +0 -122
- package/dist/components/firekit/Collection.svelte.d.ts +0 -27
- package/dist/components/firekit/Doc.svelte +0 -140
- package/dist/components/firekit/Doc.svelte.d.ts +0 -28
- package/dist/components/firekit/Node.svelte +0 -97
- package/dist/components/firekit/Node.svelte.d.ts +0 -23
- package/dist/components/firekit/auth-guard.svelte +0 -120
- package/dist/components/firekit/auth-guard.svelte.d.ts +0 -26
- package/dist/components/firekit/custom-guard.svelte +0 -163
- package/dist/components/firekit/custom-guard.svelte.d.ts +0 -31
- package/dist/components/firekit/download-url.svelte +0 -92
- package/dist/components/firekit/download-url.svelte.d.ts +0 -19
- package/dist/components/firekit/firebase-app.svelte +0 -33
- package/dist/components/firekit/firebase-app.svelte.d.ts +0 -7
- package/dist/components/firekit/node-list.svelte +0 -102
- package/dist/components/firekit/node-list.svelte.d.ts +0 -27
- package/dist/components/firekit/signed-in.svelte +0 -42
- package/dist/components/firekit/signed-out.svelte +0 -42
- package/dist/components/firekit/storage-list.svelte +0 -97
- package/dist/components/firekit/storage-list.svelte.d.ts +0 -26
- package/dist/components/firekit/upload-task.svelte +0 -108
- package/dist/components/firekit/upload-task.svelte.d.ts +0 -24
- package/dist/components/nav/app-sidebar.svelte +0 -175
- package/dist/components/nav/app-sidebar.svelte.d.ts +0 -9
- package/dist/components/nav/auto-breadcrumb.svelte +0 -41
- package/dist/components/nav/auto-breadcrumb.svelte.d.ts +0 -3
- package/dist/components/nav/dark-mode-toggle.svelte +0 -17
- package/dist/components/nav/dark-mode-toggle.svelte.d.ts +0 -18
- package/dist/components/nav/nav-components.svelte +0 -24
- package/dist/components/nav/nav-components.svelte.d.ts +0 -11
- package/dist/components/nav/nav-main.svelte +0 -45
- package/dist/components/nav/nav-main.svelte.d.ts +0 -11
- package/dist/components/nav/nav-secondary.svelte +0 -32
- package/dist/components/nav/nav-secondary.svelte.d.ts +0 -14
- package/dist/components/nav/site-header.svelte +0 -32
- package/dist/components/nav/site-header.svelte.d.ts +0 -18
- package/dist/components/ui/avatar/avatar-fallback.svelte +0 -17
- package/dist/components/ui/avatar/avatar-fallback.svelte.d.ts +0 -4
- package/dist/components/ui/avatar/avatar-image.svelte +0 -17
- package/dist/components/ui/avatar/avatar-image.svelte.d.ts +0 -4
- package/dist/components/ui/avatar/avatar.svelte +0 -19
- package/dist/components/ui/avatar/avatar.svelte.d.ts +0 -4
- package/dist/components/ui/avatar/index.d.ts +0 -4
- package/dist/components/ui/avatar/index.js +0 -6
- package/dist/components/ui/badge/badge.svelte +0 -50
- package/dist/components/ui/badge/badge.svelte.d.ts +0 -32
- package/dist/components/ui/badge/index.d.ts +0 -2
- package/dist/components/ui/badge/index.js +0 -2
- package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +0 -23
- package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte.d.ts +0 -5
- package/dist/components/ui/breadcrumb/breadcrumb-item.svelte +0 -20
- package/dist/components/ui/breadcrumb/breadcrumb-item.svelte.d.ts +0 -5
- package/dist/components/ui/breadcrumb/breadcrumb-link.svelte +0 -31
- package/dist/components/ui/breadcrumb/breadcrumb-link.svelte.d.ts +0 -11
- package/dist/components/ui/breadcrumb/breadcrumb-list.svelte +0 -23
- package/dist/components/ui/breadcrumb/breadcrumb-list.svelte.d.ts +0 -5
- package/dist/components/ui/breadcrumb/breadcrumb-page.svelte +0 -23
- package/dist/components/ui/breadcrumb/breadcrumb-page.svelte.d.ts +0 -5
- package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +0 -27
- package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte.d.ts +0 -5
- package/dist/components/ui/breadcrumb/breadcrumb.svelte +0 -21
- package/dist/components/ui/breadcrumb/breadcrumb.svelte.d.ts +0 -5
- package/dist/components/ui/breadcrumb/index.d.ts +0 -8
- package/dist/components/ui/breadcrumb/index.js +0 -10
- package/dist/components/ui/button/button.svelte +0 -80
- package/dist/components/ui/button/button.svelte.d.ts +0 -58
- package/dist/components/ui/button/index.d.ts +0 -2
- package/dist/components/ui/button/index.js +0 -4
- package/dist/components/ui/card/card-action.svelte +0 -20
- package/dist/components/ui/card/card-action.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-content.svelte +0 -15
- package/dist/components/ui/card/card-content.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-description.svelte +0 -20
- package/dist/components/ui/card/card-description.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-footer.svelte +0 -20
- package/dist/components/ui/card/card-footer.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-header.svelte +0 -23
- package/dist/components/ui/card/card-header.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-title.svelte +0 -20
- package/dist/components/ui/card/card-title.svelte.d.ts +0 -5
- package/dist/components/ui/card/card.svelte +0 -23
- package/dist/components/ui/card/card.svelte.d.ts +0 -5
- package/dist/components/ui/card/index.d.ts +0 -8
- package/dist/components/ui/card/index.js +0 -10
- package/dist/components/ui/chart/chart-container.svelte +0 -80
- package/dist/components/ui/chart/chart-container.svelte.d.ts +0 -9
- package/dist/components/ui/chart/chart-style.svelte +0 -36
- package/dist/components/ui/chart/chart-style.svelte.d.ts +0 -8
- package/dist/components/ui/chart/chart-tooltip.svelte +0 -159
- package/dist/components/ui/chart/chart-tooltip.svelte.d.ts +0 -27
- package/dist/components/ui/chart/chart-utils.d.ts +0 -36
- package/dist/components/ui/chart/chart-utils.js +0 -33
- package/dist/components/ui/chart/index.d.ts +0 -4
- package/dist/components/ui/chart/index.js +0 -4
- package/dist/components/ui/checkbox/checkbox.svelte +0 -36
- package/dist/components/ui/checkbox/checkbox.svelte.d.ts +0 -4
- package/dist/components/ui/checkbox/index.d.ts +0 -2
- package/dist/components/ui/checkbox/index.js +0 -4
- package/dist/components/ui/data-table/data-table.svelte.d.ts +0 -40
- package/dist/components/ui/data-table/data-table.svelte.js +0 -110
- package/dist/components/ui/data-table/flex-render.svelte +0 -36
- package/dist/components/ui/data-table/flex-render.svelte.d.ts +0 -30
- package/dist/components/ui/data-table/index.d.ts +0 -3
- package/dist/components/ui/data-table/index.js +0 -3
- package/dist/components/ui/data-table/render-helpers.d.ts +0 -90
- package/dist/components/ui/data-table/render-helpers.js +0 -99
- package/dist/components/ui/dialog/dialog-close.svelte +0 -7
- package/dist/components/ui/dialog/dialog-close.svelte.d.ts +0 -4
- package/dist/components/ui/dialog/dialog-content.svelte +0 -43
- package/dist/components/ui/dialog/dialog-content.svelte.d.ts +0 -11
- package/dist/components/ui/dialog/dialog-description.svelte +0 -17
- package/dist/components/ui/dialog/dialog-description.svelte.d.ts +0 -4
- package/dist/components/ui/dialog/dialog-footer.svelte +0 -20
- package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +0 -5
- package/dist/components/ui/dialog/dialog-header.svelte +0 -20
- package/dist/components/ui/dialog/dialog-header.svelte.d.ts +0 -5
- package/dist/components/ui/dialog/dialog-overlay.svelte +0 -20
- package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +0 -4
- package/dist/components/ui/dialog/dialog-title.svelte +0 -17
- package/dist/components/ui/dialog/dialog-title.svelte.d.ts +0 -4
- package/dist/components/ui/dialog/dialog-trigger.svelte +0 -7
- package/dist/components/ui/dialog/dialog-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/dialog/index.d.ts +0 -11
- package/dist/components/ui/dialog/index.js +0 -14
- package/dist/components/ui/drawer/drawer-close.svelte +0 -7
- package/dist/components/ui/drawer/drawer-close.svelte.d.ts +0 -4
- package/dist/components/ui/drawer/drawer-content.svelte +0 -37
- package/dist/components/ui/drawer/drawer-content.svelte.d.ts +0 -7
- package/dist/components/ui/drawer/drawer-description.svelte +0 -17
- package/dist/components/ui/drawer/drawer-description.svelte.d.ts +0 -4
- package/dist/components/ui/drawer/drawer-footer.svelte +0 -20
- package/dist/components/ui/drawer/drawer-footer.svelte.d.ts +0 -5
- package/dist/components/ui/drawer/drawer-header.svelte +0 -20
- package/dist/components/ui/drawer/drawer-header.svelte.d.ts +0 -5
- package/dist/components/ui/drawer/drawer-nested.svelte +0 -12
- package/dist/components/ui/drawer/drawer-nested.svelte.d.ts +0 -3
- package/dist/components/ui/drawer/drawer-overlay.svelte +0 -20
- package/dist/components/ui/drawer/drawer-overlay.svelte.d.ts +0 -4
- package/dist/components/ui/drawer/drawer-title.svelte +0 -17
- package/dist/components/ui/drawer/drawer-title.svelte.d.ts +0 -4
- package/dist/components/ui/drawer/drawer-trigger.svelte +0 -7
- package/dist/components/ui/drawer/drawer-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/drawer/drawer.svelte +0 -12
- package/dist/components/ui/drawer/drawer.svelte.d.ts +0 -3
- package/dist/components/ui/drawer/index.d.ts +0 -13
- package/dist/components/ui/drawer/index.js +0 -15
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -41
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +0 -9
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte.d.ts +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -22
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +0 -8
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -27
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +0 -8
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -24
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte.d.ts +0 -8
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -31
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -20
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +0 -5
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -20
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -29
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/index.d.ts +0 -25
- package/dist/components/ui/dropdown-menu/index.js +0 -17
- package/dist/components/ui/input/index.d.ts +0 -2
- package/dist/components/ui/input/index.js +0 -4
- package/dist/components/ui/input/input.svelte +0 -51
- package/dist/components/ui/input/input.svelte.d.ts +0 -13
- package/dist/components/ui/label/index.d.ts +0 -2
- package/dist/components/ui/label/index.js +0 -4
- package/dist/components/ui/label/label.svelte +0 -20
- package/dist/components/ui/label/label.svelte.d.ts +0 -4
- package/dist/components/ui/scroll-area/index.d.ts +0 -3
- package/dist/components/ui/scroll-area/index.js +0 -5
- package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +0 -31
- package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte.d.ts +0 -4
- package/dist/components/ui/scroll-area/scroll-area.svelte +0 -40
- package/dist/components/ui/scroll-area/scroll-area.svelte.d.ts +0 -10
- package/dist/components/ui/select/index.d.ts +0 -11
- package/dist/components/ui/select/index.js +0 -14
- package/dist/components/ui/select/select-content.svelte +0 -40
- package/dist/components/ui/select/select-content.svelte.d.ts +0 -8
- package/dist/components/ui/select/select-group-heading.svelte +0 -21
- package/dist/components/ui/select/select-group-heading.svelte.d.ts +0 -10
- package/dist/components/ui/select/select-group.svelte +0 -7
- package/dist/components/ui/select/select-group.svelte.d.ts +0 -4
- package/dist/components/ui/select/select-item.svelte +0 -38
- package/dist/components/ui/select/select-item.svelte.d.ts +0 -4
- package/dist/components/ui/select/select-label.svelte +0 -20
- package/dist/components/ui/select/select-label.svelte.d.ts +0 -6
- package/dist/components/ui/select/select-scroll-down-button.svelte +0 -20
- package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +0 -4
- package/dist/components/ui/select/select-scroll-up-button.svelte +0 -20
- package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +0 -4
- package/dist/components/ui/select/select-separator.svelte +0 -18
- package/dist/components/ui/select/select-separator.svelte.d.ts +0 -4
- package/dist/components/ui/select/select-trigger.svelte +0 -29
- package/dist/components/ui/select/select-trigger.svelte.d.ts +0 -8
- package/dist/components/ui/separator/index.d.ts +0 -2
- package/dist/components/ui/separator/index.js +0 -4
- package/dist/components/ui/separator/separator.svelte +0 -20
- package/dist/components/ui/separator/separator.svelte.d.ts +0 -4
- package/dist/components/ui/sheet/index.d.ts +0 -11
- package/dist/components/ui/sheet/index.js +0 -14
- package/dist/components/ui/sheet/sheet-close.svelte +0 -7
- package/dist/components/ui/sheet/sheet-close.svelte.d.ts +0 -4
- package/dist/components/ui/sheet/sheet-content.svelte +0 -58
- package/dist/components/ui/sheet/sheet-content.svelte.d.ts +0 -35
- package/dist/components/ui/sheet/sheet-description.svelte +0 -17
- package/dist/components/ui/sheet/sheet-description.svelte.d.ts +0 -4
- package/dist/components/ui/sheet/sheet-footer.svelte +0 -20
- package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +0 -5
- package/dist/components/ui/sheet/sheet-header.svelte +0 -20
- package/dist/components/ui/sheet/sheet-header.svelte.d.ts +0 -5
- package/dist/components/ui/sheet/sheet-overlay.svelte +0 -20
- package/dist/components/ui/sheet/sheet-overlay.svelte.d.ts +0 -4
- package/dist/components/ui/sheet/sheet-title.svelte +0 -17
- package/dist/components/ui/sheet/sheet-title.svelte.d.ts +0 -4
- package/dist/components/ui/sheet/sheet-trigger.svelte +0 -7
- package/dist/components/ui/sheet/sheet-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/sidebar/constants.d.ts +0 -6
- package/dist/components/ui/sidebar/constants.js +0 -6
- package/dist/components/ui/sidebar/context.svelte.d.ts +0 -42
- package/dist/components/ui/sidebar/context.svelte.js +0 -54
- package/dist/components/ui/sidebar/index.d.ts +0 -25
- package/dist/components/ui/sidebar/index.js +0 -27
- package/dist/components/ui/sidebar/sidebar-content.svelte +0 -24
- package/dist/components/ui/sidebar/sidebar-content.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-footer.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-footer.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-group-action.svelte +0 -36
- package/dist/components/ui/sidebar/sidebar-group-action.svelte.d.ts +0 -11
- package/dist/components/ui/sidebar/sidebar-group-content.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-group-content.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-group-label.svelte +0 -34
- package/dist/components/ui/sidebar/sidebar-group-label.svelte.d.ts +0 -11
- package/dist/components/ui/sidebar/sidebar-group.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-header.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-header.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-input.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +0 -11
- package/dist/components/ui/sidebar/sidebar-inset.svelte +0 -24
- package/dist/components/ui/sidebar/sidebar-inset.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-menu-action.svelte +0 -43
- package/dist/components/ui/sidebar/sidebar-menu-action.svelte.d.ts +0 -12
- package/dist/components/ui/sidebar/sidebar-menu-badge.svelte +0 -29
- package/dist/components/ui/sidebar/sidebar-menu-badge.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-menu-button.svelte +0 -103
- package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +0 -51
- package/dist/components/ui/sidebar/sidebar-menu-item.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-menu-item.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-menu-skeleton.svelte +0 -36
- package/dist/components/ui/sidebar/sidebar-menu-skeleton.svelte.d.ts +0 -8
- package/dist/components/ui/sidebar/sidebar-menu-sub-button.svelte +0 -43
- package/dist/components/ui/sidebar/sidebar-menu-sub-button.svelte.d.ts +0 -13
- package/dist/components/ui/sidebar/sidebar-menu-sub-item.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-menu-sub-item.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-menu-sub.svelte +0 -25
- package/dist/components/ui/sidebar/sidebar-menu-sub.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-menu.svelte +0 -21
- package/dist/components/ui/sidebar/sidebar-menu.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-provider.svelte +0 -53
- package/dist/components/ui/sidebar/sidebar-provider.svelte.d.ts +0 -9
- package/dist/components/ui/sidebar/sidebar-rail.svelte +0 -36
- package/dist/components/ui/sidebar/sidebar-rail.svelte.d.ts +0 -5
- package/dist/components/ui/sidebar/sidebar-separator.svelte +0 -19
- package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +0 -13
- package/dist/components/ui/sidebar/sidebar-trigger.svelte +0 -35
- package/dist/components/ui/sidebar/sidebar-trigger.svelte.d.ts +0 -8
- package/dist/components/ui/sidebar/sidebar.svelte +0 -104
- package/dist/components/ui/sidebar/sidebar.svelte.d.ts +0 -10
- package/dist/components/ui/skeleton/index.d.ts +0 -2
- package/dist/components/ui/skeleton/index.js +0 -4
- package/dist/components/ui/skeleton/skeleton.svelte +0 -17
- package/dist/components/ui/skeleton/skeleton.svelte.d.ts +0 -5
- package/dist/components/ui/table/index.d.ts +0 -9
- package/dist/components/ui/table/index.js +0 -11
- package/dist/components/ui/table/table-body.svelte +0 -20
- package/dist/components/ui/table/table-body.svelte.d.ts +0 -5
- package/dist/components/ui/table/table-caption.svelte +0 -20
- package/dist/components/ui/table/table-caption.svelte.d.ts +0 -5
- package/dist/components/ui/table/table-cell.svelte +0 -20
- package/dist/components/ui/table/table-cell.svelte.d.ts +0 -5
- package/dist/components/ui/table/table-footer.svelte +0 -20
- package/dist/components/ui/table/table-footer.svelte.d.ts +0 -5
- package/dist/components/ui/table/table-head.svelte +0 -23
- package/dist/components/ui/table/table-head.svelte.d.ts +0 -5
- package/dist/components/ui/table/table-header.svelte +0 -20
- package/dist/components/ui/table/table-header.svelte.d.ts +0 -5
- package/dist/components/ui/table/table-row.svelte +0 -23
- package/dist/components/ui/table/table-row.svelte.d.ts +0 -5
- package/dist/components/ui/table/table.svelte +0 -22
- package/dist/components/ui/table/table.svelte.d.ts +0 -5
- package/dist/components/ui/tabs/index.d.ts +0 -5
- package/dist/components/ui/tabs/index.js +0 -7
- package/dist/components/ui/tabs/tabs-content.svelte +0 -17
- package/dist/components/ui/tabs/tabs-content.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs-list.svelte +0 -20
- package/dist/components/ui/tabs/tabs-list.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs-trigger.svelte +0 -20
- package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs.svelte +0 -19
- package/dist/components/ui/tabs/tabs.svelte.d.ts +0 -4
- package/dist/components/ui/toggle/index.d.ts +0 -3
- package/dist/components/ui/toggle/index.js +0 -5
- package/dist/components/ui/toggle/toggle.svelte +0 -52
- package/dist/components/ui/toggle/toggle.svelte.d.ts +0 -43
- package/dist/components/ui/toggle-group/index.d.ts +0 -3
- package/dist/components/ui/toggle-group/index.js +0 -5
- package/dist/components/ui/toggle-group/toggle-group-item.svelte +0 -34
- package/dist/components/ui/toggle-group/toggle-group-item.svelte.d.ts +0 -6
- package/dist/components/ui/toggle-group/toggle-group.svelte +0 -47
- package/dist/components/ui/toggle-group/toggle-group.svelte.d.ts +0 -8
- package/dist/components/ui/tooltip/index.d.ts +0 -7
- package/dist/components/ui/tooltip/index.js +0 -9
- package/dist/components/ui/tooltip/tooltip-content.svelte +0 -47
- package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +0 -7
- package/dist/components/ui/tooltip/tooltip-trigger.svelte +0 -7
- package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +0 -4
- package/dist/hooks/is-mobile.svelte.d.ts +0 -4
- package/dist/hooks/is-mobile.svelte.js +0 -7
- package/dist/services/index.d.ts +0 -9
- package/dist/services/index.js +0 -10
- package/dist/types/docs.d.ts +0 -67
- package/dist/types/docs.js +0 -1
- package/dist/utils.d.ts +0 -15
- package/dist/utils.js +0 -44
|
@@ -1,137 +1,86 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview FirekitPresence - Clean presence tracking for Svelte applications
|
|
3
|
-
* @module FirekitPresence
|
|
4
|
-
* @version 1.0.0
|
|
5
|
-
*/
|
|
6
1
|
import { ref, onValue, onDisconnect, set, get, serverTimestamp } from 'firebase/database';
|
|
7
2
|
import { firebaseService } from '../firebase.js';
|
|
8
|
-
import { browser } from '$app/environment';
|
|
9
3
|
import { PresenceErrorCode, PresenceError } from '../types/presence.js';
|
|
10
|
-
|
|
11
|
-
* Handles geolocation tracking
|
|
12
|
-
*/
|
|
4
|
+
// ── Geolocation helper ────────────────────────────────────────────────────────
|
|
13
5
|
class GeolocationService {
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
_config;
|
|
7
|
+
_watchId = null;
|
|
16
8
|
_hasConsent = $state(false);
|
|
17
9
|
_location = $state(null);
|
|
18
|
-
_error = $state(null);
|
|
19
10
|
constructor(config) {
|
|
20
|
-
this.
|
|
21
|
-
}
|
|
22
|
-
get hasConsent() {
|
|
23
|
-
return this._hasConsent;
|
|
24
|
-
}
|
|
25
|
-
get location() {
|
|
26
|
-
return this._location;
|
|
11
|
+
this._config = config;
|
|
27
12
|
}
|
|
28
|
-
get
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Request user consent for location tracking
|
|
33
|
-
*/
|
|
13
|
+
get hasConsent() { return this._hasConsent; }
|
|
14
|
+
get location() { return this._location; }
|
|
34
15
|
async requestConsent() {
|
|
35
|
-
if (!this.
|
|
16
|
+
if (!this._config.enabled || typeof window === 'undefined')
|
|
36
17
|
return false;
|
|
37
|
-
|
|
38
|
-
if (this.config.type === 'browser') {
|
|
39
|
-
const success = await new Promise((resolve) => {
|
|
40
|
-
navigator.geolocation.getCurrentPosition(() => resolve(true), () => resolve(false), {
|
|
41
|
-
timeout: this.config.timeout || 10000,
|
|
42
|
-
enableHighAccuracy: this.config.enableHighAccuracy || false
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
this._hasConsent = success;
|
|
46
|
-
return success;
|
|
47
|
-
}
|
|
18
|
+
if (this._config.type !== 'browser') {
|
|
48
19
|
this._hasConsent = true;
|
|
49
20
|
return true;
|
|
50
21
|
}
|
|
51
|
-
|
|
52
|
-
this.
|
|
53
|
-
|
|
54
|
-
}
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
navigator.geolocation.getCurrentPosition(() => { this._hasConsent = true; resolve(true); }, () => resolve(false), { timeout: this._config.timeout ?? 10_000, enableHighAccuracy: this._config.enableHighAccuracy ?? false });
|
|
24
|
+
});
|
|
55
25
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Get current location
|
|
58
|
-
*/
|
|
59
26
|
async getCurrentLocation() {
|
|
60
|
-
if (!this.
|
|
27
|
+
if (!this._config.enabled)
|
|
61
28
|
return null;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
switch (this.config.type) {
|
|
65
|
-
case 'browser':
|
|
66
|
-
return this.getBrowserLocation();
|
|
67
|
-
case 'ip':
|
|
68
|
-
return this.getIPLocation();
|
|
69
|
-
case 'custom':
|
|
70
|
-
return this.getCustomLocation();
|
|
71
|
-
default:
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
this._error = error;
|
|
29
|
+
if (this._config.requireConsent && !this._hasConsent)
|
|
77
30
|
return null;
|
|
31
|
+
switch (this._config.type) {
|
|
32
|
+
case 'browser': return this._getBrowserLocation();
|
|
33
|
+
case 'ip': return this._getIPLocation();
|
|
34
|
+
case 'custom': return this._getCustomLocation();
|
|
35
|
+
default: return null;
|
|
78
36
|
}
|
|
79
37
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*/
|
|
83
|
-
startWatching(updateInterval) {
|
|
84
|
-
if (!this.config.enabled || this.watchId)
|
|
38
|
+
startWatching(intervalMs) {
|
|
39
|
+
if (!this._config.enabled || this._watchId)
|
|
85
40
|
return;
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
89
|
-
this._location =
|
|
90
|
-
}
|
|
41
|
+
const tick = async () => {
|
|
42
|
+
const loc = await this.getCurrentLocation();
|
|
43
|
+
if (loc)
|
|
44
|
+
this._location = loc;
|
|
91
45
|
};
|
|
92
|
-
|
|
93
|
-
this.
|
|
46
|
+
tick();
|
|
47
|
+
this._watchId = window.setInterval(tick, intervalMs);
|
|
94
48
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Stop watching location changes
|
|
97
|
-
*/
|
|
98
49
|
stopWatching() {
|
|
99
|
-
if (this.
|
|
100
|
-
clearInterval(this.
|
|
101
|
-
this.
|
|
50
|
+
if (this._watchId !== null) {
|
|
51
|
+
clearInterval(this._watchId);
|
|
52
|
+
this._watchId = null;
|
|
102
53
|
}
|
|
103
54
|
}
|
|
104
|
-
|
|
55
|
+
_getBrowserLocation() {
|
|
105
56
|
return new Promise((resolve) => {
|
|
106
|
-
navigator.geolocation.getCurrentPosition((
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
enableHighAccuracy: this.config.enableHighAccuracy || false,
|
|
121
|
-
maximumAge: this.config.maximumAge || 300000
|
|
57
|
+
navigator.geolocation.getCurrentPosition((pos) => resolve({
|
|
58
|
+
latitude: pos.coords.latitude,
|
|
59
|
+
longitude: pos.coords.longitude,
|
|
60
|
+
accuracy: pos.coords.accuracy,
|
|
61
|
+
altitude: pos.coords.altitude ?? undefined,
|
|
62
|
+
altitudeAccuracy: pos.coords.altitudeAccuracy ?? undefined,
|
|
63
|
+
heading: pos.coords.heading ?? undefined,
|
|
64
|
+
speed: pos.coords.speed ?? undefined,
|
|
65
|
+
lastUpdated: new Date().toISOString(),
|
|
66
|
+
source: 'browser'
|
|
67
|
+
}), () => resolve(null), {
|
|
68
|
+
timeout: this._config.timeout ?? 10_000,
|
|
69
|
+
enableHighAccuracy: this._config.enableHighAccuracy ?? false,
|
|
70
|
+
maximumAge: this._config.maximumAge ?? 300_000
|
|
122
71
|
});
|
|
123
72
|
});
|
|
124
73
|
}
|
|
125
|
-
async
|
|
126
|
-
if (!this.
|
|
74
|
+
async _getIPLocation() {
|
|
75
|
+
if (!this._config.ipServiceUrl)
|
|
127
76
|
return null;
|
|
128
77
|
try {
|
|
129
|
-
const
|
|
130
|
-
const data = await
|
|
78
|
+
const res = await fetch(this._config.ipServiceUrl);
|
|
79
|
+
const data = await res.json();
|
|
131
80
|
return {
|
|
132
81
|
latitude: data.latitude,
|
|
133
82
|
longitude: data.longitude,
|
|
134
|
-
accuracy: data.accuracy
|
|
83
|
+
accuracy: data.accuracy,
|
|
135
84
|
lastUpdated: new Date().toISOString(),
|
|
136
85
|
source: 'ip'
|
|
137
86
|
};
|
|
@@ -140,16 +89,12 @@ class GeolocationService {
|
|
|
140
89
|
return null;
|
|
141
90
|
}
|
|
142
91
|
}
|
|
143
|
-
async
|
|
144
|
-
if (!this.
|
|
92
|
+
async _getCustomLocation() {
|
|
93
|
+
if (!this._config.customGeolocationFn)
|
|
145
94
|
return null;
|
|
146
95
|
try {
|
|
147
|
-
const result = await this.
|
|
148
|
-
return {
|
|
149
|
-
...result,
|
|
150
|
-
lastUpdated: new Date().toISOString(),
|
|
151
|
-
source: 'custom'
|
|
152
|
-
};
|
|
96
|
+
const result = await this._config.customGeolocationFn();
|
|
97
|
+
return { ...result, lastUpdated: new Date().toISOString(), source: 'custom' };
|
|
153
98
|
}
|
|
154
99
|
catch {
|
|
155
100
|
return null;
|
|
@@ -159,469 +104,287 @@ class GeolocationService {
|
|
|
159
104
|
this.stopWatching();
|
|
160
105
|
this._hasConsent = false;
|
|
161
106
|
this._location = null;
|
|
162
|
-
this._error = null;
|
|
163
107
|
}
|
|
164
108
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
osVersion = androidMatch ? androidMatch[1] : '';
|
|
206
|
-
}
|
|
207
|
-
else if (userAgent.includes('iOS')) {
|
|
208
|
-
os = 'iOS';
|
|
209
|
-
const iosMatch = userAgent.match(/OS ([\d_]+)/);
|
|
210
|
-
osVersion = iosMatch ? iosMatch[1].replace(/_/g, '.') : '';
|
|
211
|
-
}
|
|
212
|
-
// Generate device ID
|
|
213
|
-
const deviceId = `${browser}-${os}-${platform}`.replace(/[^a-zA-Z0-9-]/g, '');
|
|
214
|
-
// Get screen resolution and timezone
|
|
215
|
-
const screenResolution = `${screen.width}x${screen.height}`;
|
|
216
|
-
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
217
|
-
return {
|
|
218
|
-
id: deviceId,
|
|
219
|
-
type: deviceType,
|
|
220
|
-
browser,
|
|
221
|
-
browserVersion,
|
|
222
|
-
os,
|
|
223
|
-
osVersion,
|
|
224
|
-
userAgent,
|
|
225
|
-
screenResolution,
|
|
226
|
-
timezone
|
|
227
|
-
};
|
|
228
|
-
}
|
|
109
|
+
// ── Device info helper ────────────────────────────────────────────────────────
|
|
110
|
+
function getDeviceInfo() {
|
|
111
|
+
const ua = navigator.userAgent;
|
|
112
|
+
const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
|
|
113
|
+
const isTablet = /iPad|Android(?=.*Tablet)|Windows NT.*Touch/i.test(ua);
|
|
114
|
+
const type = isTablet ? 'tablet' : isMobile ? 'mobile' : 'desktop';
|
|
115
|
+
const browserMatch = ua.match(/(firefox|chrome|safari|opera|edge|msie|trident(?=\/))\/?\s*(\d+)/i);
|
|
116
|
+
const browser = browserMatch ? browserMatch[1] : 'Unknown';
|
|
117
|
+
const browserVersion = browserMatch ? browserMatch[2] : '';
|
|
118
|
+
let os = 'Unknown', osVersion = '';
|
|
119
|
+
if (ua.includes('Windows NT')) {
|
|
120
|
+
os = 'Windows';
|
|
121
|
+
osVersion = ua.match(/Windows NT ([\d.]+)/)?.[1] ?? '';
|
|
122
|
+
}
|
|
123
|
+
else if (ua.includes('Mac OS X')) {
|
|
124
|
+
os = 'macOS';
|
|
125
|
+
osVersion = (ua.match(/Mac OS X ([\d_]+)/)?.[1] ?? '').replace(/_/g, '.');
|
|
126
|
+
}
|
|
127
|
+
else if (ua.includes('Android')) {
|
|
128
|
+
os = 'Android';
|
|
129
|
+
osVersion = ua.match(/Android ([\d.]+)/)?.[1] ?? '';
|
|
130
|
+
}
|
|
131
|
+
else if (ua.includes('Linux')) {
|
|
132
|
+
os = 'Linux';
|
|
133
|
+
}
|
|
134
|
+
else if (ua.includes('iOS')) {
|
|
135
|
+
os = 'iOS';
|
|
136
|
+
osVersion = (ua.match(/OS ([\d_]+)/)?.[1] ?? '').replace(/_/g, '.');
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
id: `${browser}-${os}`.replace(/[^a-zA-Z0-9-]/g, ''),
|
|
140
|
+
type,
|
|
141
|
+
browser,
|
|
142
|
+
browserVersion,
|
|
143
|
+
os,
|
|
144
|
+
osVersion,
|
|
145
|
+
userAgent: ua,
|
|
146
|
+
screenResolution: `${screen.width}x${screen.height}`,
|
|
147
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
148
|
+
};
|
|
229
149
|
}
|
|
150
|
+
// ── Main presence service ─────────────────────────────────────────────────────
|
|
230
151
|
/**
|
|
231
|
-
*
|
|
152
|
+
* Reactive user presence tracking via Firebase Realtime Database.
|
|
153
|
+
*
|
|
154
|
+
* Monitors RTDB `.info/connected`, writes session data on connect,
|
|
155
|
+
* registers `onDisconnect` cleanup, and tracks page visibility changes.
|
|
232
156
|
*
|
|
233
|
-
* @class FirekitPresence
|
|
234
157
|
* @example
|
|
235
|
-
* ```
|
|
158
|
+
* ```ts
|
|
236
159
|
* import { firekitPresence } from 'svelte-firekit';
|
|
237
|
-
*
|
|
238
|
-
* // Initialize
|
|
239
|
-
* await firekitPresence.initialize(user, {
|
|
240
|
-
* geolocation: { enabled: true, type: 'browser' },
|
|
241
|
-
* sessionTTL: 30 * 60 * 1000
|
|
242
|
-
* });
|
|
243
|
-
*
|
|
244
|
-
* // Access reactive state
|
|
245
|
-
* $: console.log('Status:', firekitPresence.status);
|
|
160
|
+
* await firekitPresence.initialize(user, { sessionTTL: 30 * 60 * 1000 });
|
|
246
161
|
* ```
|
|
247
162
|
*/
|
|
248
163
|
class FirekitPresence {
|
|
249
164
|
static instance;
|
|
250
|
-
|
|
251
|
-
sessionTTL: 30 * 60 * 1000,
|
|
252
|
-
updateInterval: 60 * 1000,
|
|
253
|
-
trackDeviceInfo: true
|
|
254
|
-
};
|
|
255
|
-
geolocationService = null;
|
|
256
|
-
connectedListener = null;
|
|
257
|
-
currentUser = null;
|
|
258
|
-
// Reactive state using Svelte 5 runes
|
|
165
|
+
// ── Reactive state ──────────────────────────────────────────────────────
|
|
259
166
|
_initialized = $state(false);
|
|
260
167
|
_status = $state('offline');
|
|
261
168
|
_loading = $state(false);
|
|
262
169
|
_error = $state(null);
|
|
263
170
|
_currentSession = $state(null);
|
|
264
171
|
_sessions = $state([]);
|
|
172
|
+
// ── Internal ────────────────────────────────────────────────────────────
|
|
173
|
+
_config = { sessionTTL: 30 * 60_000, updateInterval: 60_000, trackDeviceInfo: true };
|
|
174
|
+
_geo = null;
|
|
175
|
+
_connectedUnsub = null;
|
|
176
|
+
_currentUser = null;
|
|
265
177
|
constructor() {
|
|
266
|
-
if (
|
|
267
|
-
this.
|
|
178
|
+
if (typeof window !== 'undefined') {
|
|
179
|
+
document.addEventListener('visibilitychange', this._onVisibilityChange);
|
|
268
180
|
}
|
|
269
181
|
}
|
|
270
|
-
/**
|
|
271
|
-
* Gets singleton instance of FirekitPresence
|
|
272
|
-
*/
|
|
273
182
|
static getInstance() {
|
|
274
|
-
if (!FirekitPresence.instance)
|
|
183
|
+
if (!FirekitPresence.instance)
|
|
275
184
|
FirekitPresence.instance = new FirekitPresence();
|
|
276
|
-
}
|
|
277
185
|
return FirekitPresence.instance;
|
|
278
186
|
}
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
get
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
get
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return this._loading;
|
|
290
|
-
}
|
|
291
|
-
get error() {
|
|
292
|
-
return this._error;
|
|
293
|
-
}
|
|
294
|
-
get currentSession() {
|
|
295
|
-
return this._currentSession;
|
|
296
|
-
}
|
|
297
|
-
get sessions() {
|
|
298
|
-
return this._sessions;
|
|
299
|
-
}
|
|
300
|
-
get location() {
|
|
301
|
-
return this.geolocationService?.location || null;
|
|
302
|
-
}
|
|
303
|
-
get hasLocationConsent() {
|
|
304
|
-
return this.geolocationService?.hasConsent || false;
|
|
305
|
-
}
|
|
306
|
-
// ========================================
|
|
307
|
-
// INITIALIZATION
|
|
308
|
-
// ========================================
|
|
309
|
-
/**
|
|
310
|
-
* Initialize presence tracking
|
|
311
|
-
* @param user Current authenticated user
|
|
312
|
-
* @param config Presence configuration options
|
|
313
|
-
*/
|
|
187
|
+
// ── Getters ─────────────────────────────────────────────────────────────
|
|
188
|
+
get initialized() { return this._initialized; }
|
|
189
|
+
get status() { return this._status; }
|
|
190
|
+
get loading() { return this._loading; }
|
|
191
|
+
get error() { return this._error; }
|
|
192
|
+
get currentSession() { return this._currentSession; }
|
|
193
|
+
get sessions() { return this._sessions; }
|
|
194
|
+
get location() { return this._geo?.location ?? null; }
|
|
195
|
+
get hasLocationConsent() { return this._geo?.hasConsent ?? false; }
|
|
196
|
+
// ── Initialization ───────────────────────────────────────────────────────
|
|
314
197
|
async initialize(user, config) {
|
|
198
|
+
if (typeof window === 'undefined') {
|
|
199
|
+
throw new PresenceError(PresenceErrorCode.INITIALIZATION_FAILED, 'Presence can only be initialized in a browser environment.');
|
|
200
|
+
}
|
|
201
|
+
if (this._initialized)
|
|
202
|
+
return;
|
|
203
|
+
this._loading = true;
|
|
204
|
+
this._currentUser = user;
|
|
205
|
+
if (config)
|
|
206
|
+
this._config = { ...this._config, ...config };
|
|
315
207
|
try {
|
|
316
|
-
if (
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
console.warn('Presence service is already initialized');
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
this._loading = true;
|
|
324
|
-
this.currentUser = user;
|
|
325
|
-
this.config = { ...this.config, ...config };
|
|
326
|
-
// Initialize geolocation service if enabled
|
|
327
|
-
if (this.config.geolocation?.enabled) {
|
|
328
|
-
this.geolocationService = new GeolocationService(this.config.geolocation);
|
|
329
|
-
if (this.config.geolocation.requireConsent) {
|
|
330
|
-
const hasConsent = await this.geolocationService.requestConsent();
|
|
208
|
+
if (this._config.geolocation?.enabled) {
|
|
209
|
+
this._geo = new GeolocationService(this._config.geolocation);
|
|
210
|
+
if (this._config.geolocation.requireConsent) {
|
|
211
|
+
await this._geo.requestConsent();
|
|
331
212
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
this.geolocationService.startWatching(this.config.updateInterval);
|
|
213
|
+
if (!this._config.geolocation.requireConsent || this._geo.hasConsent) {
|
|
214
|
+
this._geo.startWatching(this._config.updateInterval);
|
|
335
215
|
}
|
|
336
216
|
}
|
|
337
|
-
|
|
338
|
-
await this.setupConnectionMonitoring();
|
|
217
|
+
await this._setupConnectionMonitoring();
|
|
339
218
|
this._initialized = true;
|
|
340
219
|
}
|
|
341
|
-
catch (
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
220
|
+
catch (err) {
|
|
221
|
+
// Clean up geolocation if it started before the error
|
|
222
|
+
this._geo?.dispose();
|
|
223
|
+
this._geo = null;
|
|
224
|
+
this._error = err instanceof PresenceError
|
|
225
|
+
? err
|
|
226
|
+
: new PresenceError(PresenceErrorCode.INITIALIZATION_FAILED, err.message, err);
|
|
346
227
|
throw this._error;
|
|
347
228
|
}
|
|
348
229
|
finally {
|
|
349
230
|
this._loading = false;
|
|
350
231
|
}
|
|
351
232
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
*/
|
|
355
|
-
async setupConnectionMonitoring() {
|
|
233
|
+
// ── Connection monitoring ────────────────────────────────────────────────
|
|
234
|
+
async _setupConnectionMonitoring() {
|
|
356
235
|
const db = firebaseService.getDatabaseInstance();
|
|
357
|
-
if (!db)
|
|
358
|
-
throw new PresenceError(PresenceErrorCode.DATABASE_ERROR, '
|
|
359
|
-
}
|
|
236
|
+
if (!db)
|
|
237
|
+
throw new PresenceError(PresenceErrorCode.DATABASE_ERROR, 'Realtime Database is not initialized.');
|
|
360
238
|
const connectedRef = ref(db, '.info/connected');
|
|
361
|
-
this.
|
|
362
|
-
if (
|
|
239
|
+
this._connectedUnsub = onValue(connectedRef, async (snap) => {
|
|
240
|
+
if (snap.val() === true) {
|
|
363
241
|
await this.setPresence('online');
|
|
364
|
-
await this.
|
|
242
|
+
await this._setupDisconnectHandler();
|
|
365
243
|
}
|
|
366
244
|
else {
|
|
367
|
-
|
|
245
|
+
this._status = 'offline';
|
|
368
246
|
}
|
|
369
247
|
});
|
|
370
248
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
*/
|
|
374
|
-
async setupDisconnectHandler() {
|
|
375
|
-
if (!this.currentUser || !this._currentSession)
|
|
249
|
+
async _setupDisconnectHandler() {
|
|
250
|
+
if (!this._currentUser || !this._currentSession)
|
|
376
251
|
return;
|
|
377
252
|
const db = firebaseService.getDatabaseInstance();
|
|
378
253
|
if (!db)
|
|
379
254
|
return;
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
await onDisconnect(sessionRef).update({
|
|
255
|
+
const path = `${this._config.sessionPath ?? 'presence'}/${this._currentUser.uid}/sessions/${this._currentSession.id}`;
|
|
256
|
+
await onDisconnect(ref(db, path)).update({
|
|
383
257
|
status: 'offline',
|
|
384
258
|
lastSeen: serverTimestamp()
|
|
385
259
|
});
|
|
386
260
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
*/
|
|
390
|
-
setupVisibilityListener() {
|
|
391
|
-
if (!browser)
|
|
261
|
+
_onVisibilityChange = async () => {
|
|
262
|
+
if (!this._initialized)
|
|
392
263
|
return;
|
|
393
|
-
document.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (document.visibilityState === 'hidden') {
|
|
397
|
-
await this.setPresence('away');
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
await this.setPresence('online');
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
// ========================================
|
|
405
|
-
// PRESENCE MANAGEMENT
|
|
406
|
-
// ========================================
|
|
407
|
-
/**
|
|
408
|
-
* Set presence status
|
|
409
|
-
*/
|
|
264
|
+
await this.setPresence(document.visibilityState === 'hidden' ? 'away' : 'online');
|
|
265
|
+
};
|
|
266
|
+
// ── Presence management ──────────────────────────────────────────────────
|
|
410
267
|
async setPresence(status) {
|
|
268
|
+
if (!this._currentUser) {
|
|
269
|
+
throw new PresenceError(PresenceErrorCode.USER_NOT_AUTHENTICATED, 'No authenticated user.');
|
|
270
|
+
}
|
|
271
|
+
const db = firebaseService.getDatabaseInstance();
|
|
272
|
+
if (!db)
|
|
273
|
+
throw new PresenceError(PresenceErrorCode.DATABASE_ERROR, 'Realtime Database is not initialized.');
|
|
411
274
|
try {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const location = await this.geolocationService?.getCurrentLocation();
|
|
421
|
-
// Get device info if enabled
|
|
422
|
-
const device = this.config.trackDeviceInfo ? DeviceInfoService.getDeviceInfo() : undefined;
|
|
423
|
-
let session;
|
|
424
|
-
if (!this._currentSession) {
|
|
425
|
-
// Create new session
|
|
426
|
-
session = {
|
|
427
|
-
id: `${this.currentUser.uid}_${device?.id || Date.now()}`,
|
|
428
|
-
userId: this.currentUser.uid,
|
|
275
|
+
const location = await this._geo?.getCurrentLocation() ?? undefined;
|
|
276
|
+
const device = this._config.trackDeviceInfo ? getDeviceInfo() : undefined;
|
|
277
|
+
const now = new Date().toISOString();
|
|
278
|
+
const session = this._currentSession
|
|
279
|
+
? { ...this._currentSession, status, lastSeen: now, lastActivity: now, ...(location && { location }) }
|
|
280
|
+
: {
|
|
281
|
+
id: `${this._currentUser.uid}_${device?.id ?? Date.now()}`,
|
|
282
|
+
userId: this._currentUser.uid,
|
|
429
283
|
status,
|
|
430
|
-
createdAt:
|
|
431
|
-
lastSeen:
|
|
432
|
-
lastActivity:
|
|
284
|
+
createdAt: now,
|
|
285
|
+
lastSeen: now,
|
|
286
|
+
lastActivity: now,
|
|
433
287
|
...(location && { location }),
|
|
434
288
|
...(device && { device }),
|
|
435
|
-
...(this.
|
|
289
|
+
...(this._config.customMetadata && { metadata: this._config.customMetadata })
|
|
436
290
|
};
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
// Update existing session
|
|
440
|
-
session = {
|
|
441
|
-
...this._currentSession,
|
|
442
|
-
status,
|
|
443
|
-
lastSeen: new Date().toISOString(),
|
|
444
|
-
lastActivity: new Date().toISOString(),
|
|
445
|
-
...(location && { location })
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
// Save session to Firebase
|
|
449
|
-
const sessionPath = this.config.sessionPath || 'presence';
|
|
450
|
-
const sessionRef = ref(db, `${sessionPath}/${this.currentUser.uid}/sessions/${session.id}`);
|
|
291
|
+
const sessionRef = ref(db, `${this._config.sessionPath ?? 'presence'}/${this._currentUser.uid}/sessions/${session.id}`);
|
|
451
292
|
await set(sessionRef, session);
|
|
452
|
-
// Update local state
|
|
453
293
|
this._currentSession = session;
|
|
454
294
|
this._status = status;
|
|
455
|
-
|
|
456
|
-
await this.loadSessions();
|
|
295
|
+
await this._loadSessions();
|
|
457
296
|
}
|
|
458
|
-
catch (
|
|
459
|
-
this._error =
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
: new PresenceError(PresenceErrorCode.DATABASE_ERROR, `Failed to set presence: ${error.message}`, error);
|
|
297
|
+
catch (err) {
|
|
298
|
+
this._error = err instanceof PresenceError
|
|
299
|
+
? err
|
|
300
|
+
: new PresenceError(PresenceErrorCode.DATABASE_ERROR, err.message, err);
|
|
463
301
|
throw this._error;
|
|
464
302
|
}
|
|
465
303
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if (!
|
|
304
|
+
async _loadSessions() {
|
|
305
|
+
if (!this._currentUser)
|
|
306
|
+
return;
|
|
307
|
+
const db = firebaseService.getDatabaseInstance();
|
|
308
|
+
if (!db)
|
|
309
|
+
return;
|
|
310
|
+
const basePath = `${this._config.sessionPath ?? 'presence'}/${this._currentUser.uid}/sessions`;
|
|
311
|
+
const snap = await get(ref(db, basePath));
|
|
312
|
+
if (!snap.exists()) {
|
|
313
|
+
this._sessions = [];
|
|
471
314
|
return;
|
|
472
|
-
try {
|
|
473
|
-
const db = firebaseService.getDatabaseInstance();
|
|
474
|
-
if (!db)
|
|
475
|
-
return;
|
|
476
|
-
const sessionPath = this.config.sessionPath || 'presence';
|
|
477
|
-
const sessionsRef = ref(db, `${sessionPath}/${this.currentUser.uid}/sessions`);
|
|
478
|
-
const snapshot = await get(sessionsRef);
|
|
479
|
-
if (snapshot.exists()) {
|
|
480
|
-
const sessionsData = snapshot.val();
|
|
481
|
-
let sessions = Object.values(sessionsData);
|
|
482
|
-
// Clean up stale sessions
|
|
483
|
-
if (this.config.sessionTTL) {
|
|
484
|
-
const cutoffTime = new Date(Date.now() - this.config.sessionTTL).toISOString();
|
|
485
|
-
const expiredSessions = sessions.filter((session) => session.lastSeen < cutoffTime);
|
|
486
|
-
sessions = sessions.filter((session) => session.lastSeen >= cutoffTime);
|
|
487
|
-
// Remove stale sessions from database
|
|
488
|
-
for (const expiredSession of expiredSessions) {
|
|
489
|
-
const staleSessionRef = ref(db, `${sessionPath}/${this.currentUser.uid}/sessions/${expiredSession.id}`);
|
|
490
|
-
await set(staleSessionRef, null);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
this._sessions = sessions;
|
|
494
|
-
}
|
|
495
|
-
else {
|
|
496
|
-
this._sessions = [];
|
|
497
|
-
}
|
|
498
315
|
}
|
|
499
|
-
|
|
500
|
-
|
|
316
|
+
let sessions = Object.values(snap.val());
|
|
317
|
+
if (this._config.sessionTTL) {
|
|
318
|
+
const cutoff = new Date(Date.now() - this._config.sessionTTL).toISOString();
|
|
319
|
+
const expired = sessions.filter((s) => s.lastSeen < cutoff);
|
|
320
|
+
sessions = sessions.filter((s) => s.lastSeen >= cutoff);
|
|
321
|
+
await Promise.all(expired.map((s) => set(ref(db, `${basePath}/${s.id}`), null)));
|
|
501
322
|
}
|
|
323
|
+
this._sessions = sessions;
|
|
502
324
|
}
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
// ========================================
|
|
506
|
-
/**
|
|
507
|
-
* Get presence statistics
|
|
508
|
-
*/
|
|
509
|
-
getPresenceStats() {
|
|
325
|
+
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
326
|
+
getStats() {
|
|
510
327
|
const sessions = this._sessions;
|
|
511
|
-
let
|
|
512
|
-
const
|
|
513
|
-
let
|
|
514
|
-
sessions
|
|
515
|
-
if (
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (session.lastActivity) {
|
|
522
|
-
const activityTime = new Date(session.lastActivity).getTime();
|
|
523
|
-
lastActivityTime = Math.max(lastActivityTime, activityTime);
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
const averageSessionDuration = sessions.length > 0 ? totalSessionTime / sessions.length : 0;
|
|
328
|
+
let totalMs = 0;
|
|
329
|
+
const devices = new Set();
|
|
330
|
+
let lastActivity = 0;
|
|
331
|
+
for (const s of sessions) {
|
|
332
|
+
if (s.device?.id)
|
|
333
|
+
devices.add(s.device.id);
|
|
334
|
+
totalMs += new Date(s.lastSeen).getTime() - new Date(s.createdAt).getTime();
|
|
335
|
+
if (s.lastActivity)
|
|
336
|
+
lastActivity = Math.max(lastActivity, new Date(s.lastActivity).getTime());
|
|
337
|
+
}
|
|
527
338
|
return {
|
|
528
339
|
totalSessions: sessions.length,
|
|
529
340
|
onlineSessions: sessions.filter((s) => s.status === 'online').length,
|
|
530
341
|
awaySessions: sessions.filter((s) => s.status === 'away').length,
|
|
531
342
|
offlineSessions: sessions.filter((s) => s.status === 'offline').length,
|
|
532
|
-
uniqueDevices:
|
|
533
|
-
averageSessionDuration,
|
|
534
|
-
lastActivity:
|
|
343
|
+
uniqueDevices: devices.size,
|
|
344
|
+
averageSessionDuration: sessions.length > 0 ? totalMs / sessions.length : 0,
|
|
345
|
+
lastActivity: lastActivity > 0 ? new Date(lastActivity).toISOString() : ''
|
|
535
346
|
};
|
|
536
347
|
}
|
|
537
|
-
|
|
538
|
-
* Request location consent manually
|
|
539
|
-
*/
|
|
540
|
-
async requestLocationConsent() {
|
|
541
|
-
if (!this.geolocationService) {
|
|
542
|
-
throw new PresenceError(PresenceErrorCode.GEOLOCATION_UNAVAILABLE, 'Geolocation service not available');
|
|
543
|
-
}
|
|
544
|
-
return await this.geolocationService.requestConsent();
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Get current user's online sessions count
|
|
548
|
-
*/
|
|
549
|
-
getOnlineSessionsCount() {
|
|
550
|
-
return this._sessions.filter((session) => session.status === 'online').length;
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Check if user is online on any device
|
|
554
|
-
*/
|
|
555
|
-
isUserOnline() {
|
|
556
|
-
return this._sessions.some((session) => session.status === 'online');
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
* Get sessions by status
|
|
560
|
-
*/
|
|
348
|
+
isOnline() { return this._sessions.some((s) => s.status === 'online'); }
|
|
561
349
|
getSessionsByStatus(status) {
|
|
562
|
-
return this._sessions.filter((
|
|
350
|
+
return this._sessions.filter((s) => s.status === status);
|
|
351
|
+
}
|
|
352
|
+
async requestLocationConsent() {
|
|
353
|
+
if (!this._geo)
|
|
354
|
+
throw new PresenceError(PresenceErrorCode.GEOLOCATION_UNAVAILABLE, 'Geolocation not configured.');
|
|
355
|
+
return this._geo.requestConsent();
|
|
563
356
|
}
|
|
564
|
-
/**
|
|
565
|
-
* Force refresh presence data
|
|
566
|
-
*/
|
|
567
357
|
async refresh() {
|
|
568
358
|
if (!this._initialized)
|
|
569
359
|
return;
|
|
570
360
|
this._loading = true;
|
|
571
361
|
try {
|
|
572
|
-
await this.
|
|
573
|
-
if (this._currentSession)
|
|
362
|
+
await this._loadSessions();
|
|
363
|
+
if (this._currentSession)
|
|
574
364
|
await this.setPresence(this._status);
|
|
575
|
-
}
|
|
576
365
|
}
|
|
577
366
|
finally {
|
|
578
367
|
this._loading = false;
|
|
579
368
|
}
|
|
580
369
|
}
|
|
581
|
-
// ========================================
|
|
582
|
-
// CLEANUP
|
|
583
|
-
// ========================================
|
|
584
|
-
/**
|
|
585
|
-
* Dispose of all resources and cleanup
|
|
586
|
-
*/
|
|
587
370
|
async dispose() {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
if (this._currentSession) {
|
|
371
|
+
if (this._currentSession) {
|
|
372
|
+
try {
|
|
591
373
|
await this.setPresence('offline');
|
|
592
374
|
}
|
|
375
|
+
catch { /* best-effort */ }
|
|
593
376
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
// Remove connection listener
|
|
600
|
-
if (this.connectedListener) {
|
|
601
|
-
this.connectedListener();
|
|
602
|
-
this.connectedListener = null;
|
|
377
|
+
this._geo?.dispose();
|
|
378
|
+
this._connectedUnsub?.();
|
|
379
|
+
this._connectedUnsub = null;
|
|
380
|
+
if (typeof document !== 'undefined') {
|
|
381
|
+
document.removeEventListener('visibilitychange', this._onVisibilityChange);
|
|
603
382
|
}
|
|
604
|
-
// Reset state
|
|
605
383
|
this._initialized = false;
|
|
606
384
|
this._status = 'offline';
|
|
607
|
-
this._loading = false;
|
|
608
385
|
this._error = null;
|
|
609
386
|
this._currentSession = null;
|
|
610
387
|
this._sessions = [];
|
|
611
388
|
}
|
|
612
389
|
}
|
|
613
|
-
/**
|
|
614
|
-
* Pre-initialized singleton instance of FirekitPresence.
|
|
615
|
-
*
|
|
616
|
-
* @example
|
|
617
|
-
* ```typescript
|
|
618
|
-
* import { firekitPresence } from 'svelte-firekit';
|
|
619
|
-
*
|
|
620
|
-
* // Initialize presence tracking
|
|
621
|
-
* await firekitPresence.initialize(user, {
|
|
622
|
-
* geolocation: { enabled: true, type: 'browser' },
|
|
623
|
-
* sessionTTL: 30 * 60 * 1000
|
|
624
|
-
* });
|
|
625
|
-
* ```
|
|
626
|
-
*/
|
|
627
390
|
export const firekitPresence = FirekitPresence.getInstance();
|