svelte-firekit 0.1.8 → 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 -708
- 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
package/dist/services/auth.js
CHANGED
|
@@ -1,934 +1,579 @@
|
|
|
1
|
-
|
|
2
|
-
* @fileoverview FirekitAuth - Complete Firebase Authentication Service for Svelte
|
|
3
|
-
* @module FirekitAuth
|
|
4
|
-
* @version 1.0.0
|
|
5
|
-
*/
|
|
6
|
-
import { EmailAuthProvider, PhoneAuthProvider, RecaptchaVerifier, signInWithEmailAndPassword, signInWithPopup, signInWithPhoneNumber as firebaseSignInWithPhoneNumber, signInWithCredential, signInAnonymously as firebaseSignInAnonymously, createUserWithEmailAndPassword, signOut, sendPasswordResetEmail, confirmPasswordReset, sendEmailVerification, updateProfile, updateEmail, updatePassword, reauthenticateWithCredential, deleteUser, reload, getIdToken, onAuthStateChanged, getAdditionalUserInfo } from 'firebase/auth';
|
|
1
|
+
import { EmailAuthProvider, PhoneAuthProvider, RecaptchaVerifier, SAMLAuthProvider, OAuthProvider, signInWithEmailAndPassword, signInWithPopup, signInWithRedirect, getRedirectResult, signInWithCustomToken as firebaseSignInWithCustomToken, signInWithPhoneNumber as firebaseSignInWithPhoneNumber, signInWithCredential, signInAnonymously as firebaseSignInAnonymously, createUserWithEmailAndPassword, signOut as firebaseSignOut, sendPasswordResetEmail, confirmPasswordReset as firebaseConfirmPasswordReset, sendEmailVerification, updateProfile, updateEmail, updatePassword, reauthenticateWithCredential, deleteUser, reload, getIdToken, getAdditionalUserInfo, multiFactor, PhoneMultiFactorGenerator, getMultiFactorResolver } from 'firebase/auth';
|
|
7
2
|
import { doc, setDoc, serverTimestamp } from 'firebase/firestore';
|
|
8
3
|
import { firebaseService } from '../firebase.js';
|
|
9
4
|
import { AuthErrorCode, FirekitAuthError } from '../types/auth.js';
|
|
10
|
-
import { mapFirebaseUserToProfile, updateUserInFirestore, createGoogleProvider, createFacebookProvider, createAppleProvider, handleAuthError } from '../utils/index.js';
|
|
5
|
+
import { mapFirebaseUserToProfile, updateUserInFirestore, createGoogleProvider, createFacebookProvider, createAppleProvider, createGithubProvider, createTwitterProvider, createMicrosoftProvider, handleAuthError } from '../utils/index.js';
|
|
11
6
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* Firebase Authentication service.
|
|
8
|
+
* Handles all auth operations — sign in, register, sign out, profile updates.
|
|
9
|
+
* Reactive state (loading, user, isAuthenticated) lives in `firekitUser`.
|
|
15
10
|
*
|
|
16
|
-
* @class FirekitAuth
|
|
17
11
|
* @example
|
|
18
|
-
* ```typescript
|
|
19
12
|
* import { firekitAuth } from 'svelte-firekit';
|
|
20
|
-
*
|
|
21
|
-
* // Sign in with Google
|
|
22
13
|
* await firekitAuth.signInWithGoogle();
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* await firekitAuth.registerWithEmail("user@example.com", "password123", "John Doe");
|
|
26
|
-
*
|
|
27
|
-
* // Listen to auth state changes
|
|
28
|
-
* const unsubscribe = firekitAuth.onAuthStateChanged((user) => {
|
|
29
|
-
* console.log('User:', user);
|
|
30
|
-
* });
|
|
31
|
-
* ```
|
|
14
|
+
* await firekitAuth.registerWithEmail('user@example.com', 'password', 'Jane Doe');
|
|
15
|
+
* await firekitAuth.signOut();
|
|
32
16
|
*/
|
|
33
17
|
class FirekitAuth {
|
|
34
18
|
static instance;
|
|
35
19
|
auth = null;
|
|
36
20
|
firestore = null;
|
|
37
|
-
_servicesInitialized = false;
|
|
38
|
-
authState = {
|
|
39
|
-
user: null,
|
|
40
|
-
loading: true,
|
|
41
|
-
initialized: false
|
|
42
|
-
};
|
|
43
|
-
stateListeners = new Set();
|
|
44
21
|
recaptchaVerifiers = new Map();
|
|
45
22
|
constructor() {
|
|
46
23
|
if (typeof window !== 'undefined') {
|
|
47
|
-
|
|
48
|
-
this.initializeServices();
|
|
24
|
+
this.bootstrap();
|
|
49
25
|
}
|
|
50
26
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Gets singleton instance of FirekitAuth
|
|
53
|
-
* @returns {FirekitAuth} The FirekitAuth instance
|
|
54
|
-
*/
|
|
55
27
|
static getInstance() {
|
|
56
28
|
if (!FirekitAuth.instance) {
|
|
57
29
|
FirekitAuth.instance = new FirekitAuth();
|
|
58
30
|
}
|
|
59
31
|
return FirekitAuth.instance;
|
|
60
32
|
}
|
|
61
|
-
|
|
62
|
-
* Initializes Firebase services and auth state listener
|
|
63
|
-
* @private
|
|
64
|
-
*/
|
|
65
|
-
initializeServices() {
|
|
66
|
-
if (this._servicesInitialized)
|
|
67
|
-
return;
|
|
33
|
+
bootstrap() {
|
|
68
34
|
try {
|
|
69
35
|
this.auth = firebaseService.getAuthInstance();
|
|
70
|
-
// Try to get Firestore instance, but don't fail if it's not available
|
|
71
36
|
try {
|
|
72
37
|
this.firestore = firebaseService.getDbInstance();
|
|
73
38
|
}
|
|
74
|
-
catch
|
|
75
|
-
console.warn('Firestore not available, continuing without Firestore integration:', firestoreError);
|
|
39
|
+
catch {
|
|
76
40
|
this.firestore = null;
|
|
77
41
|
}
|
|
78
|
-
this._servicesInitialized = true;
|
|
79
|
-
this.initializeAuthStateListener();
|
|
80
42
|
}
|
|
81
|
-
catch
|
|
82
|
-
|
|
83
|
-
this.authState = {
|
|
84
|
-
user: null,
|
|
85
|
-
loading: false,
|
|
86
|
-
initialized: true
|
|
87
|
-
};
|
|
88
|
-
this.notifyStateListeners();
|
|
43
|
+
catch {
|
|
44
|
+
// Firebase not yet configured — services will be accessed lazily
|
|
89
45
|
}
|
|
90
46
|
}
|
|
91
|
-
|
|
92
|
-
* Initializes the authentication state listener
|
|
93
|
-
* @private
|
|
94
|
-
*/
|
|
95
|
-
initializeAuthStateListener() {
|
|
47
|
+
getAuth() {
|
|
96
48
|
if (!this.auth) {
|
|
97
|
-
|
|
98
|
-
return;
|
|
49
|
+
this.auth = firebaseService.getAuthInstance();
|
|
99
50
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
initialized: true
|
|
105
|
-
};
|
|
106
|
-
this.notifyStateListeners();
|
|
107
|
-
}, (error) => {
|
|
108
|
-
console.error('Auth state change error:', error);
|
|
109
|
-
this.authState = {
|
|
110
|
-
user: null,
|
|
111
|
-
loading: false,
|
|
112
|
-
initialized: true
|
|
113
|
-
};
|
|
114
|
-
this.notifyStateListeners();
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Notifies all state listeners of auth state changes
|
|
119
|
-
* @private
|
|
120
|
-
*/
|
|
121
|
-
notifyStateListeners() {
|
|
122
|
-
this.stateListeners.forEach((listener) => listener(this.authState));
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Maps Firebase User to UserProfile interface
|
|
126
|
-
* @private
|
|
127
|
-
*/
|
|
128
|
-
mapFirebaseUserToProfile(user) {
|
|
129
|
-
return mapFirebaseUserToProfile(user);
|
|
51
|
+
if (!this.auth) {
|
|
52
|
+
throw new FirekitAuthError('auth/not-initialized', 'Firebase Auth is not initialized.');
|
|
53
|
+
}
|
|
54
|
+
return this.auth;
|
|
130
55
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
* @private
|
|
134
|
-
*/
|
|
135
|
-
async updateUserInFirestore(user) {
|
|
136
|
-
if (!this.firestore) {
|
|
137
|
-
console.warn('Firestore not available, skipping user update in Firestore');
|
|
56
|
+
async syncToFirestore(user) {
|
|
57
|
+
if (!this.firestore)
|
|
138
58
|
return;
|
|
139
|
-
}
|
|
140
59
|
await updateUserInFirestore(this.firestore, user);
|
|
141
60
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
* @private
|
|
145
|
-
*/
|
|
146
|
-
handleAuthError(error) {
|
|
147
|
-
handleAuthError(error);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Gets the current authentication state
|
|
151
|
-
* @returns {AuthState} Current authentication state
|
|
152
|
-
*/
|
|
153
|
-
getState() {
|
|
154
|
-
return { ...this.authState };
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Gets the current authenticated user
|
|
158
|
-
* @returns {User | null} Current Firebase user or null
|
|
159
|
-
*/
|
|
160
|
-
getCurrentUser() {
|
|
161
|
-
return this.auth?.currentUser ?? null;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Gets the current user profile
|
|
165
|
-
* @returns {UserProfile | null} Current user profile or null
|
|
166
|
-
*/
|
|
167
|
-
getCurrentUserProfile() {
|
|
168
|
-
return this.authState.user;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Waits for auth initialization to complete
|
|
172
|
-
* @returns {Promise<UserProfile | null>} Promise that resolves when auth is initialized
|
|
173
|
-
*/
|
|
174
|
-
async waitForAuth() {
|
|
175
|
-
return new Promise((resolve) => {
|
|
176
|
-
if (this.authState.initialized) {
|
|
177
|
-
resolve(this.authState.user);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
const unsubscribe = this.onAuthStateChanged((state) => {
|
|
181
|
-
if (state.initialized) {
|
|
182
|
-
unsubscribe();
|
|
183
|
-
resolve(state.user);
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Subscribes to authentication state changes
|
|
190
|
-
* @param {Function} callback Callback function to handle state changes
|
|
191
|
-
* @returns {Function} Unsubscribe function
|
|
192
|
-
*/
|
|
193
|
-
onAuthStateChanged(callback) {
|
|
194
|
-
this.stateListeners.add(callback);
|
|
195
|
-
// Immediately call with current state
|
|
196
|
-
callback(this.authState);
|
|
197
|
-
return () => {
|
|
198
|
-
this.stateListeners.delete(callback);
|
|
199
|
-
};
|
|
61
|
+
profile(user) {
|
|
62
|
+
return mapFirebaseUserToProfile(user);
|
|
200
63
|
}
|
|
201
|
-
//
|
|
202
|
-
// SIGN IN METHODS
|
|
203
|
-
// ========================================
|
|
204
|
-
/**
|
|
205
|
-
* Signs in user with email and password
|
|
206
|
-
* @param {string} email User's email address
|
|
207
|
-
* @param {string} password User's password
|
|
208
|
-
* @returns {Promise<SignInResult>} Promise resolving to sign-in result
|
|
209
|
-
* @throws {FirekitAuthError} If sign-in fails
|
|
210
|
-
*
|
|
211
|
-
* @example
|
|
212
|
-
* ```typescript
|
|
213
|
-
* try {
|
|
214
|
-
* const result = await firekitAuth.signInWithEmail("user@example.com", "password123");
|
|
215
|
-
* console.log("Signed in:", result.user.displayName);
|
|
216
|
-
* console.log("Is new user:", result.isNewUser);
|
|
217
|
-
* } catch (error) {
|
|
218
|
-
* console.error("Sign-in failed:", error.message);
|
|
219
|
-
* }
|
|
220
|
-
* ```
|
|
221
|
-
*/
|
|
64
|
+
// ─── Sign-in ────────────────────────────────────────────────────────────────
|
|
222
65
|
async signInWithEmail(email, password) {
|
|
223
|
-
if (!this.auth) {
|
|
224
|
-
throw new Error('Auth instance not available');
|
|
225
|
-
}
|
|
226
66
|
try {
|
|
227
|
-
this.
|
|
228
|
-
this.
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
const userProfile = this.mapFirebaseUserToProfile(userCredential.user);
|
|
232
|
-
const additionalUserInfo = getAdditionalUserInfo(userCredential);
|
|
233
|
-
const isNewUser = additionalUserInfo?.isNewUser ?? false;
|
|
67
|
+
const cred = await signInWithEmailAndPassword(this.getAuth(), email, password);
|
|
68
|
+
await this.syncToFirestore(cred.user);
|
|
69
|
+
const profile = this.profile(cred.user);
|
|
70
|
+
const isNewUser = getAdditionalUserInfo(cred)?.isNewUser ?? false;
|
|
234
71
|
return {
|
|
235
72
|
success: true,
|
|
236
|
-
user:
|
|
73
|
+
user: profile,
|
|
237
74
|
method: 'email',
|
|
238
75
|
timestamp: new Date(),
|
|
239
76
|
isNewUser,
|
|
240
|
-
requiresEmailVerification: !
|
|
77
|
+
requiresEmailVerification: !profile.emailVerified
|
|
241
78
|
};
|
|
242
79
|
}
|
|
243
80
|
catch (error) {
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
finally {
|
|
247
|
-
this.authState.loading = false;
|
|
248
|
-
this.notifyStateListeners();
|
|
81
|
+
handleAuthError(error);
|
|
249
82
|
}
|
|
250
83
|
}
|
|
251
|
-
/**
|
|
252
|
-
* Signs in user with Google popup
|
|
253
|
-
* @returns {Promise<OAuthSignInResult>} Promise resolving to OAuth sign-in result
|
|
254
|
-
* @throws {FirekitAuthError} If sign-in fails
|
|
255
|
-
*
|
|
256
|
-
* @example
|
|
257
|
-
* ```typescript
|
|
258
|
-
* try {
|
|
259
|
-
* const result = await firekitAuth.signInWithGoogle();
|
|
260
|
-
* console.log("Signed in with Google:", result.user.email);
|
|
261
|
-
* console.log("Is new user:", result.isNewUser);
|
|
262
|
-
* console.log("Access token:", result.accessToken);
|
|
263
|
-
* } catch (error) {
|
|
264
|
-
* if (error.code === 'auth/popup-closed-by-user') {
|
|
265
|
-
* console.log("User cancelled sign-in");
|
|
266
|
-
* }
|
|
267
|
-
* }
|
|
268
|
-
* ```
|
|
269
|
-
*/
|
|
270
84
|
async signInWithGoogle() {
|
|
271
|
-
|
|
272
|
-
throw new Error('Auth instance not available');
|
|
273
|
-
}
|
|
274
|
-
try {
|
|
275
|
-
this.authState.loading = true;
|
|
276
|
-
this.notifyStateListeners();
|
|
277
|
-
const provider = createGoogleProvider();
|
|
278
|
-
const result = await signInWithPopup(this.auth, provider);
|
|
279
|
-
await this.updateUserInFirestore(result.user);
|
|
280
|
-
const userProfile = this.mapFirebaseUserToProfile(result.user);
|
|
281
|
-
const additionalUserInfo = getAdditionalUserInfo(result);
|
|
282
|
-
const isNewUser = additionalUserInfo?.isNewUser ?? false;
|
|
283
|
-
return {
|
|
284
|
-
success: true,
|
|
285
|
-
user: userProfile,
|
|
286
|
-
method: 'google',
|
|
287
|
-
timestamp: new Date(),
|
|
288
|
-
isNewUser,
|
|
289
|
-
provider: 'google'
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
catch (error) {
|
|
293
|
-
this.handleAuthError(error);
|
|
294
|
-
}
|
|
295
|
-
finally {
|
|
296
|
-
this.authState.loading = false;
|
|
297
|
-
this.notifyStateListeners();
|
|
298
|
-
}
|
|
85
|
+
return this.signInWithOAuth('google', createGoogleProvider());
|
|
299
86
|
}
|
|
300
|
-
/**
|
|
301
|
-
* Signs in user with Facebook popup
|
|
302
|
-
* @returns {Promise<OAuthSignInResult>} Promise resolving to OAuth sign-in result
|
|
303
|
-
* @throws {FirekitAuthError} If sign-in fails
|
|
304
|
-
*/
|
|
305
87
|
async signInWithFacebook() {
|
|
306
|
-
|
|
307
|
-
throw new Error('Auth instance not available');
|
|
308
|
-
}
|
|
309
|
-
try {
|
|
310
|
-
this.authState.loading = true;
|
|
311
|
-
this.notifyStateListeners();
|
|
312
|
-
const provider = createFacebookProvider();
|
|
313
|
-
const result = await signInWithPopup(this.auth, provider);
|
|
314
|
-
await this.updateUserInFirestore(result.user);
|
|
315
|
-
const userProfile = this.mapFirebaseUserToProfile(result.user);
|
|
316
|
-
const additionalUserInfo = getAdditionalUserInfo(result);
|
|
317
|
-
const isNewUser = additionalUserInfo?.isNewUser ?? false;
|
|
318
|
-
return {
|
|
319
|
-
success: true,
|
|
320
|
-
user: userProfile,
|
|
321
|
-
method: 'facebook',
|
|
322
|
-
timestamp: new Date(),
|
|
323
|
-
isNewUser,
|
|
324
|
-
provider: 'facebook'
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
catch (error) {
|
|
328
|
-
this.handleAuthError(error);
|
|
329
|
-
}
|
|
330
|
-
finally {
|
|
331
|
-
this.authState.loading = false;
|
|
332
|
-
this.notifyStateListeners();
|
|
333
|
-
}
|
|
88
|
+
return this.signInWithOAuth('facebook', createFacebookProvider());
|
|
334
89
|
}
|
|
335
|
-
/**
|
|
336
|
-
* Signs in user with Apple popup
|
|
337
|
-
* @returns {Promise<OAuthSignInResult>} Promise resolving to OAuth sign-in result
|
|
338
|
-
* @throws {FirekitAuthError} If sign-in fails
|
|
339
|
-
*/
|
|
340
90
|
async signInWithApple() {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
91
|
+
return this.signInWithOAuth('apple', createAppleProvider());
|
|
92
|
+
}
|
|
93
|
+
async signInWithGithub() {
|
|
94
|
+
return this.signInWithOAuth('github', createGithubProvider());
|
|
95
|
+
}
|
|
96
|
+
async signInWithTwitter() {
|
|
97
|
+
return this.signInWithOAuth('twitter', createTwitterProvider());
|
|
98
|
+
}
|
|
99
|
+
async signInWithMicrosoft() {
|
|
100
|
+
return this.signInWithOAuth('microsoft', createMicrosoftProvider());
|
|
101
|
+
}
|
|
102
|
+
async signInWithOAuth(provider, providerInstance) {
|
|
344
103
|
try {
|
|
345
|
-
this.
|
|
346
|
-
this.
|
|
347
|
-
const
|
|
348
|
-
const
|
|
349
|
-
await this.updateUserInFirestore(result.user);
|
|
350
|
-
const userProfile = this.mapFirebaseUserToProfile(result.user);
|
|
351
|
-
const additionalUserInfo = getAdditionalUserInfo(result);
|
|
352
|
-
const isNewUser = additionalUserInfo?.isNewUser ?? false;
|
|
104
|
+
const result = await signInWithPopup(this.getAuth(), providerInstance);
|
|
105
|
+
await this.syncToFirestore(result.user);
|
|
106
|
+
const profile = this.profile(result.user);
|
|
107
|
+
const isNewUser = getAdditionalUserInfo(result)?.isNewUser ?? false;
|
|
353
108
|
return {
|
|
354
109
|
success: true,
|
|
355
|
-
user:
|
|
356
|
-
method:
|
|
110
|
+
user: profile,
|
|
111
|
+
method: provider,
|
|
357
112
|
timestamp: new Date(),
|
|
358
113
|
isNewUser,
|
|
359
|
-
provider
|
|
114
|
+
provider
|
|
360
115
|
};
|
|
361
116
|
}
|
|
362
117
|
catch (error) {
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
finally {
|
|
366
|
-
this.authState.loading = false;
|
|
367
|
-
this.notifyStateListeners();
|
|
118
|
+
handleAuthError(error);
|
|
368
119
|
}
|
|
369
120
|
}
|
|
370
|
-
/**
|
|
371
|
-
* Signs in user anonymously
|
|
372
|
-
* @returns {Promise<SignInResult>} Promise resolving to sign-in result
|
|
373
|
-
* @throws {FirekitAuthError} If sign-in fails
|
|
374
|
-
*
|
|
375
|
-
* @example
|
|
376
|
-
* ```typescript
|
|
377
|
-
* const result = await firekitAuth.signInAnonymously();
|
|
378
|
-
* console.log("Anonymous user:", result.user.uid);
|
|
379
|
-
* console.log("Is new user:", result.isNewUser);
|
|
380
|
-
* ```
|
|
381
|
-
*/
|
|
382
121
|
async signInAnonymously() {
|
|
383
|
-
if (!this.auth) {
|
|
384
|
-
throw new Error('Auth instance not available');
|
|
385
|
-
}
|
|
386
122
|
try {
|
|
387
|
-
|
|
388
|
-
this.
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
const userProfile = this.mapFirebaseUserToProfile(result.user);
|
|
392
|
-
const additionalUserInfo = getAdditionalUserInfo(result);
|
|
393
|
-
const isNewUser = additionalUserInfo?.isNewUser ?? false;
|
|
123
|
+
const result = await firebaseSignInAnonymously(this.getAuth());
|
|
124
|
+
await this.syncToFirestore(result.user);
|
|
125
|
+
const profile = this.profile(result.user);
|
|
126
|
+
const isNewUser = getAdditionalUserInfo(result)?.isNewUser ?? false;
|
|
394
127
|
return {
|
|
395
128
|
success: true,
|
|
396
|
-
user:
|
|
129
|
+
user: profile,
|
|
397
130
|
method: 'anonymous',
|
|
398
131
|
timestamp: new Date(),
|
|
399
132
|
isNewUser
|
|
400
133
|
};
|
|
401
134
|
}
|
|
402
135
|
catch (error) {
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
finally {
|
|
406
|
-
this.authState.loading = false;
|
|
407
|
-
this.notifyStateListeners();
|
|
136
|
+
handleAuthError(error);
|
|
408
137
|
}
|
|
409
138
|
}
|
|
410
|
-
/**
|
|
411
|
-
* Initiates phone number sign-in process
|
|
412
|
-
* @param {string} phoneNumber Phone number in international format
|
|
413
|
-
* @param {string} recaptchaContainerId ID of the reCAPTCHA container element
|
|
414
|
-
* @returns {Promise<PhoneVerificationResult>} Promise resolving to verification result
|
|
415
|
-
* @throws {FirekitAuthError} If verification initiation fails
|
|
416
|
-
*
|
|
417
|
-
* @example
|
|
418
|
-
* ```typescript
|
|
419
|
-
* const verification = await firekitAuth.signInWithPhoneNumber("+1234567890", "recaptcha-container");
|
|
420
|
-
* const user = await verification.confirm("123456");
|
|
421
|
-
* ```
|
|
422
|
-
*/
|
|
423
139
|
async signInWithPhoneNumber(phoneNumber, recaptchaContainerId) {
|
|
424
|
-
|
|
425
|
-
throw new Error('Auth instance not available');
|
|
426
|
-
}
|
|
140
|
+
const auth = this.getAuth();
|
|
427
141
|
try {
|
|
428
|
-
this
|
|
429
|
-
this.
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
if (existingVerifier) {
|
|
433
|
-
existingVerifier.clear();
|
|
142
|
+
// Reuse or create the reCAPTCHA verifier for this container
|
|
143
|
+
const existing = this.recaptchaVerifiers.get(recaptchaContainerId);
|
|
144
|
+
if (existing) {
|
|
145
|
+
existing.clear();
|
|
434
146
|
this.recaptchaVerifiers.delete(recaptchaContainerId);
|
|
435
147
|
}
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
console.log('reCAPTCHA solved');
|
|
440
|
-
},
|
|
441
|
-
'expired-callback': () => {
|
|
442
|
-
console.log('reCAPTCHA expired');
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
this.recaptchaVerifiers.set(recaptchaContainerId, recaptchaVerifier);
|
|
446
|
-
const confirmationResult = await firebaseSignInWithPhoneNumber(this.auth, phoneNumber, recaptchaVerifier);
|
|
148
|
+
const verifier = new RecaptchaVerifier(auth, recaptchaContainerId, { size: 'normal' });
|
|
149
|
+
this.recaptchaVerifiers.set(recaptchaContainerId, verifier);
|
|
150
|
+
const confirmation = await firebaseSignInWithPhoneNumber(auth, phoneNumber, verifier);
|
|
447
151
|
return {
|
|
448
|
-
verificationId:
|
|
449
|
-
confirm: async (
|
|
152
|
+
verificationId: confirmation.verificationId,
|
|
153
|
+
confirm: async (code) => {
|
|
450
154
|
try {
|
|
451
|
-
const
|
|
452
|
-
await this.
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
const isNewUser = additionalUserInfo?.isNewUser ?? false;
|
|
155
|
+
const cred = await confirmation.confirm(code);
|
|
156
|
+
await this.syncToFirestore(cred.user);
|
|
157
|
+
const profile = this.profile(cred.user);
|
|
158
|
+
const isNewUser = getAdditionalUserInfo(cred)?.isNewUser ?? false;
|
|
456
159
|
return {
|
|
457
160
|
success: true,
|
|
458
|
-
user:
|
|
161
|
+
user: profile,
|
|
459
162
|
method: 'phone',
|
|
460
163
|
timestamp: new Date(),
|
|
461
164
|
isNewUser
|
|
462
165
|
};
|
|
463
166
|
}
|
|
464
167
|
catch (error) {
|
|
465
|
-
|
|
168
|
+
handleAuthError(error);
|
|
466
169
|
}
|
|
467
170
|
finally {
|
|
468
|
-
|
|
469
|
-
recaptchaVerifier.clear();
|
|
171
|
+
verifier.clear();
|
|
470
172
|
this.recaptchaVerifiers.delete(recaptchaContainerId);
|
|
471
173
|
}
|
|
472
174
|
}
|
|
473
175
|
};
|
|
474
176
|
}
|
|
475
177
|
catch (error) {
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
finally {
|
|
479
|
-
this.authState.loading = false;
|
|
480
|
-
this.notifyStateListeners();
|
|
178
|
+
handleAuthError(error);
|
|
481
179
|
}
|
|
482
180
|
}
|
|
483
|
-
//
|
|
484
|
-
// REGISTRATION METHODS
|
|
485
|
-
// ========================================
|
|
486
|
-
/**
|
|
487
|
-
* Registers new user with email and password
|
|
488
|
-
* @param {string} email User's email address
|
|
489
|
-
* @param {string} password User's password
|
|
490
|
-
* @param {string} [displayName] User's display name
|
|
491
|
-
* @param {boolean} [sendVerification=true] Whether to send email verification
|
|
492
|
-
* @returns {Promise<RegistrationResult>} Promise resolving to registration result
|
|
493
|
-
* @throws {FirekitAuthError} If registration fails
|
|
494
|
-
*
|
|
495
|
-
* @example
|
|
496
|
-
* ```typescript
|
|
497
|
-
* const result = await firekitAuth.registerWithEmail(
|
|
498
|
-
* "user@example.com",
|
|
499
|
-
* "password123",
|
|
500
|
-
* "John Doe"
|
|
501
|
-
* );
|
|
502
|
-
* console.log("Registered:", result.user.displayName);
|
|
503
|
-
* console.log("Email verification sent:", result.emailVerificationSent);
|
|
504
|
-
* ```
|
|
505
|
-
*/
|
|
181
|
+
// ─── Registration ────────────────────────────────────────────────────────────
|
|
506
182
|
async registerWithEmail(email, password, displayName, sendVerification = true) {
|
|
507
|
-
if (!this.auth) {
|
|
508
|
-
throw new Error('Auth instance not available');
|
|
509
|
-
}
|
|
510
183
|
try {
|
|
511
|
-
this.
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
const user = userCredential.user;
|
|
515
|
-
// Update profile if displayName provided
|
|
516
|
-
if (displayName) {
|
|
184
|
+
const cred = await createUserWithEmailAndPassword(this.getAuth(), email, password);
|
|
185
|
+
const { user } = cred;
|
|
186
|
+
if (displayName)
|
|
517
187
|
await updateProfile(user, { displayName });
|
|
518
|
-
|
|
519
|
-
// Send email verification
|
|
520
|
-
if (sendVerification) {
|
|
188
|
+
if (sendVerification)
|
|
521
189
|
await sendEmailVerification(user);
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const userProfile = this.mapFirebaseUserToProfile(user);
|
|
190
|
+
await this.syncToFirestore(user);
|
|
191
|
+
const profile = this.profile(user);
|
|
525
192
|
return {
|
|
526
193
|
success: true,
|
|
527
|
-
user:
|
|
194
|
+
user: profile,
|
|
528
195
|
method: 'email',
|
|
529
196
|
timestamp: new Date(),
|
|
530
197
|
emailVerificationSent: sendVerification,
|
|
531
|
-
requiresEmailVerification: !
|
|
198
|
+
requiresEmailVerification: !profile.emailVerified
|
|
532
199
|
};
|
|
533
200
|
}
|
|
534
201
|
catch (error) {
|
|
535
|
-
|
|
202
|
+
handleAuthError(error);
|
|
536
203
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
204
|
+
}
|
|
205
|
+
// ─── Sign-out ────────────────────────────────────────────────────────────────
|
|
206
|
+
async signOut() {
|
|
207
|
+
try {
|
|
208
|
+
this.recaptchaVerifiers.forEach((v) => v.clear());
|
|
209
|
+
this.recaptchaVerifiers.clear();
|
|
210
|
+
await firebaseSignOut(this.getAuth());
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
handleAuthError(error);
|
|
540
214
|
}
|
|
541
215
|
}
|
|
542
|
-
//
|
|
543
|
-
// PASSWORD METHODS
|
|
544
|
-
// ========================================
|
|
545
|
-
/**
|
|
546
|
-
* Sends password reset email
|
|
547
|
-
* @param {string} email User's email address
|
|
548
|
-
* @returns {Promise<void>} Promise that resolves when email is sent
|
|
549
|
-
* @throws {FirekitAuthError} If sending fails
|
|
550
|
-
*
|
|
551
|
-
* @example
|
|
552
|
-
* ```typescript
|
|
553
|
-
* await firekitAuth.sendPasswordReset("user@example.com");
|
|
554
|
-
* console.log("Password reset email sent");
|
|
555
|
-
* ```
|
|
556
|
-
*/
|
|
216
|
+
// ─── Password ────────────────────────────────────────────────────────────────
|
|
557
217
|
async sendPasswordReset(email) {
|
|
558
|
-
if (!this.auth) {
|
|
559
|
-
throw new Error('Auth instance not available');
|
|
560
|
-
}
|
|
561
218
|
try {
|
|
562
|
-
await sendPasswordResetEmail(this.
|
|
219
|
+
await sendPasswordResetEmail(this.getAuth(), email);
|
|
563
220
|
}
|
|
564
221
|
catch (error) {
|
|
565
|
-
|
|
222
|
+
handleAuthError(error);
|
|
566
223
|
}
|
|
567
224
|
}
|
|
568
|
-
/**
|
|
569
|
-
* Confirms password reset with code
|
|
570
|
-
* @param {string} code Password reset code from email
|
|
571
|
-
* @param {string} newPassword New password
|
|
572
|
-
* @returns {Promise<void>} Promise that resolves when password is reset
|
|
573
|
-
* @throws {FirekitAuthError} If reset fails
|
|
574
|
-
*/
|
|
575
225
|
async confirmPasswordReset(code, newPassword) {
|
|
576
|
-
if (!this.auth) {
|
|
577
|
-
throw new Error('Auth instance not available');
|
|
578
|
-
}
|
|
579
226
|
try {
|
|
580
|
-
await
|
|
227
|
+
await firebaseConfirmPasswordReset(this.getAuth(), code, newPassword);
|
|
581
228
|
}
|
|
582
229
|
catch (error) {
|
|
583
|
-
|
|
230
|
+
handleAuthError(error);
|
|
584
231
|
}
|
|
585
232
|
}
|
|
586
|
-
/**
|
|
587
|
-
* Updates user password with reauthentication
|
|
588
|
-
* @param {string} newPassword New password
|
|
589
|
-
* @param {string} currentPassword Current password for reauthentication
|
|
590
|
-
* @returns {Promise<PasswordUpdateResult>} Promise resolving to update result
|
|
591
|
-
*
|
|
592
|
-
* @example
|
|
593
|
-
* ```typescript
|
|
594
|
-
* const result = await firekitAuth.updatePassword("newPassword123", "oldPassword123");
|
|
595
|
-
* if (result.success) {
|
|
596
|
-
* console.log("Password updated successfully");
|
|
597
|
-
* } else {
|
|
598
|
-
* console.error("Update failed:", result.message);
|
|
599
|
-
* }
|
|
600
|
-
* ```
|
|
601
|
-
*/
|
|
602
233
|
async updatePassword(newPassword, currentPassword) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
message: 'No authenticated user found.',
|
|
607
|
-
code: 'auth/no-current-user'
|
|
608
|
-
};
|
|
234
|
+
const auth = this.getAuth();
|
|
235
|
+
if (!auth.currentUser) {
|
|
236
|
+
return { success: false, message: 'No authenticated user found.', code: 'auth/no-current-user' };
|
|
609
237
|
}
|
|
610
238
|
try {
|
|
611
|
-
await this.
|
|
612
|
-
await updatePassword(
|
|
613
|
-
return {
|
|
614
|
-
success: true,
|
|
615
|
-
message: 'Password successfully updated.'
|
|
616
|
-
};
|
|
239
|
+
await this.reauthenticate(currentPassword);
|
|
240
|
+
await updatePassword(auth.currentUser, newPassword);
|
|
241
|
+
return { success: true, message: 'Password successfully updated.' };
|
|
617
242
|
}
|
|
618
243
|
catch (error) {
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
return {
|
|
622
|
-
success: false,
|
|
623
|
-
code,
|
|
624
|
-
message: 'Current password is incorrect.'
|
|
625
|
-
};
|
|
626
|
-
}
|
|
244
|
+
const err = error;
|
|
245
|
+
const code = err.code;
|
|
627
246
|
return {
|
|
628
247
|
success: false,
|
|
629
|
-
code: code || '
|
|
630
|
-
message:
|
|
248
|
+
code: code || 'unknown',
|
|
249
|
+
message: code === AuthErrorCode.WRONG_PASSWORD
|
|
250
|
+
? 'Current password is incorrect.'
|
|
251
|
+
: (err.message ?? 'Failed to update password.')
|
|
631
252
|
};
|
|
632
253
|
}
|
|
633
254
|
}
|
|
634
|
-
//
|
|
635
|
-
// PROFILE METHODS
|
|
636
|
-
// ========================================
|
|
637
|
-
/**
|
|
638
|
-
* Updates user profile
|
|
639
|
-
* @param {Object} profile Profile update data
|
|
640
|
-
* @param {string} [profile.displayName] New display name
|
|
641
|
-
* @param {string} [profile.photoURL] New photo URL
|
|
642
|
-
* @returns {Promise<void>} Promise that resolves when profile is updated
|
|
643
|
-
* @throws {FirekitAuthError} If update fails
|
|
644
|
-
*
|
|
645
|
-
* @example
|
|
646
|
-
* ```typescript
|
|
647
|
-
* await firekitAuth.updateUserProfile({
|
|
648
|
-
* displayName: "John Smith",
|
|
649
|
-
* photoURL: "https://example.com/photo.jpg"
|
|
650
|
-
* });
|
|
651
|
-
* ```
|
|
652
|
-
*/
|
|
255
|
+
// ─── Profile ─────────────────────────────────────────────────────────────────
|
|
653
256
|
async updateUserProfile(profile) {
|
|
654
|
-
|
|
257
|
+
const auth = this.getAuth();
|
|
258
|
+
if (!auth.currentUser) {
|
|
655
259
|
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
656
260
|
}
|
|
657
261
|
try {
|
|
658
|
-
await updateProfile(
|
|
659
|
-
await this.
|
|
262
|
+
await updateProfile(auth.currentUser, profile);
|
|
263
|
+
await this.syncToFirestore(auth.currentUser);
|
|
660
264
|
}
|
|
661
265
|
catch (error) {
|
|
662
|
-
|
|
266
|
+
handleAuthError(error);
|
|
663
267
|
}
|
|
664
268
|
}
|
|
665
|
-
/**
|
|
666
|
-
* Updates user email address
|
|
667
|
-
* @param {string} newEmail New email address
|
|
668
|
-
* @returns {Promise<void>} Promise that resolves when email is updated
|
|
669
|
-
* @throws {FirekitAuthError} If update fails
|
|
670
|
-
*
|
|
671
|
-
* @example
|
|
672
|
-
* ```typescript
|
|
673
|
-
* await firekitAuth.updateEmail("newemail@example.com");
|
|
674
|
-
* ```
|
|
675
|
-
*/
|
|
676
269
|
async updateEmail(newEmail) {
|
|
677
|
-
|
|
270
|
+
const auth = this.getAuth();
|
|
271
|
+
if (!auth.currentUser) {
|
|
678
272
|
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
679
273
|
}
|
|
680
274
|
try {
|
|
681
|
-
await updateEmail(
|
|
682
|
-
await this.
|
|
275
|
+
await updateEmail(auth.currentUser, newEmail);
|
|
276
|
+
await this.syncToFirestore(auth.currentUser);
|
|
683
277
|
}
|
|
684
278
|
catch (error) {
|
|
685
|
-
|
|
279
|
+
handleAuthError(error);
|
|
686
280
|
}
|
|
687
281
|
}
|
|
688
|
-
/**
|
|
689
|
-
* Sends email verification to current user
|
|
690
|
-
* @returns {Promise<void>} Promise that resolves when verification email is sent
|
|
691
|
-
* @throws {FirekitAuthError} If sending fails
|
|
692
|
-
*
|
|
693
|
-
* @example
|
|
694
|
-
* ```typescript
|
|
695
|
-
* await firekitAuth.sendEmailVerification();
|
|
696
|
-
* ```
|
|
697
|
-
*/
|
|
698
282
|
async sendEmailVerification() {
|
|
699
|
-
|
|
283
|
+
const auth = this.getAuth();
|
|
284
|
+
if (!auth.currentUser) {
|
|
700
285
|
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
701
286
|
}
|
|
702
287
|
try {
|
|
703
|
-
await sendEmailVerification(
|
|
288
|
+
await sendEmailVerification(auth.currentUser);
|
|
704
289
|
}
|
|
705
290
|
catch (error) {
|
|
706
|
-
|
|
291
|
+
handleAuthError(error);
|
|
707
292
|
}
|
|
708
293
|
}
|
|
709
|
-
/**
|
|
710
|
-
* Reloads user to get updated data
|
|
711
|
-
* @returns {Promise<void>} Promise that resolves when user is reloaded
|
|
712
|
-
* @throws {FirekitAuthError} If reload fails
|
|
713
|
-
*
|
|
714
|
-
* @example
|
|
715
|
-
* ```typescript
|
|
716
|
-
* await firekitAuth.reloadUser();
|
|
717
|
-
* ```
|
|
718
|
-
*/
|
|
719
294
|
async reloadUser() {
|
|
720
|
-
|
|
295
|
+
const auth = this.getAuth();
|
|
296
|
+
if (!auth.currentUser) {
|
|
721
297
|
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
722
298
|
}
|
|
723
299
|
try {
|
|
724
|
-
await reload(
|
|
725
|
-
await this.
|
|
300
|
+
await reload(auth.currentUser);
|
|
301
|
+
await this.syncToFirestore(auth.currentUser);
|
|
726
302
|
}
|
|
727
303
|
catch (error) {
|
|
728
|
-
|
|
304
|
+
handleAuthError(error);
|
|
729
305
|
}
|
|
730
306
|
}
|
|
731
|
-
/**
|
|
732
|
-
* Gets the current user's ID token
|
|
733
|
-
* @param {boolean} [forceRefresh=false] Whether to force token refresh
|
|
734
|
-
* @returns {Promise<string>} Promise resolving to ID token
|
|
735
|
-
* @throws {FirekitAuthError} If getting token fails
|
|
736
|
-
*
|
|
737
|
-
* @example
|
|
738
|
-
* ```typescript
|
|
739
|
-
* const token = await firekitAuth.getIdToken();
|
|
740
|
-
* ```
|
|
741
|
-
*/
|
|
742
307
|
async getIdToken(forceRefresh = false) {
|
|
743
|
-
|
|
308
|
+
const auth = this.getAuth();
|
|
309
|
+
if (!auth.currentUser) {
|
|
744
310
|
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
745
311
|
}
|
|
746
312
|
try {
|
|
747
|
-
return await getIdToken(
|
|
748
|
-
}
|
|
749
|
-
catch (error) {
|
|
750
|
-
this.handleAuthError(error);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Reauthenticates user with current password
|
|
755
|
-
* @private
|
|
756
|
-
*/
|
|
757
|
-
async reauthenticateUser(currentPassword) {
|
|
758
|
-
if (!this.auth?.currentUser || !this.auth.currentUser.email) {
|
|
759
|
-
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user with email found.');
|
|
760
|
-
}
|
|
761
|
-
try {
|
|
762
|
-
const credential = EmailAuthProvider.credential(this.auth.currentUser.email, currentPassword);
|
|
763
|
-
await reauthenticateWithCredential(this.auth.currentUser, credential);
|
|
313
|
+
return await getIdToken(auth.currentUser, forceRefresh);
|
|
764
314
|
}
|
|
765
315
|
catch (error) {
|
|
766
|
-
|
|
316
|
+
handleAuthError(error);
|
|
767
317
|
}
|
|
768
318
|
}
|
|
769
|
-
|
|
770
|
-
* Deletes user account
|
|
771
|
-
* @param {string} [currentPassword] Current password for reauthentication
|
|
772
|
-
* @returns {Promise<AccountDeletionResult>} Promise resolving to deletion result
|
|
773
|
-
*
|
|
774
|
-
* @example
|
|
775
|
-
* ```typescript
|
|
776
|
-
* const result = await firekitAuth.deleteAccount("currentPassword123");
|
|
777
|
-
* if (result.success) {
|
|
778
|
-
* console.log("Account deleted successfully");
|
|
779
|
-
* } else {
|
|
780
|
-
* console.error("Deletion failed:", result.message);
|
|
781
|
-
* }
|
|
782
|
-
* ```
|
|
783
|
-
*/
|
|
319
|
+
// ─── Account deletion ────────────────────────────────────────────────────────
|
|
784
320
|
async deleteAccount(currentPassword) {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
message: 'No authenticated user found.'
|
|
789
|
-
};
|
|
321
|
+
const auth = this.getAuth();
|
|
322
|
+
if (!auth.currentUser) {
|
|
323
|
+
return { success: false, message: 'No authenticated user found.' };
|
|
790
324
|
}
|
|
791
325
|
try {
|
|
792
|
-
const user =
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
// Delete user data from Firestore first (if available)
|
|
326
|
+
const user = auth.currentUser;
|
|
327
|
+
if (currentPassword)
|
|
328
|
+
await this.reauthenticate(currentPassword);
|
|
329
|
+
// Soft-delete record in Firestore before removing auth
|
|
798
330
|
if (this.firestore) {
|
|
799
331
|
try {
|
|
800
|
-
|
|
801
|
-
await setDoc(userRef, { deleted: true, deletedAt: serverTimestamp() }, { merge: true });
|
|
332
|
+
await setDoc(doc(this.firestore, 'users', user.uid), { deleted: true, deletedAt: serverTimestamp() }, { merge: true });
|
|
802
333
|
}
|
|
803
|
-
catch
|
|
804
|
-
|
|
334
|
+
catch {
|
|
335
|
+
// Non-blocking
|
|
805
336
|
}
|
|
806
337
|
}
|
|
807
|
-
// Delete the user account
|
|
808
338
|
await deleteUser(user);
|
|
809
|
-
return {
|
|
810
|
-
success: true,
|
|
811
|
-
message: 'Account successfully deleted.'
|
|
812
|
-
};
|
|
339
|
+
return { success: true, message: 'Account successfully deleted.' };
|
|
813
340
|
}
|
|
814
341
|
catch (error) {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
message: error.message || 'Failed to delete account.'
|
|
818
|
-
};
|
|
342
|
+
const err = error;
|
|
343
|
+
return { success: false, message: err.message ?? 'Failed to delete account.' };
|
|
819
344
|
}
|
|
820
345
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
* @example
|
|
827
|
-
* ```typescript
|
|
828
|
-
* await firekitAuth.signOut();
|
|
829
|
-
* console.log("User signed out");
|
|
830
|
-
* ```
|
|
831
|
-
*/
|
|
832
|
-
async signOut() {
|
|
833
|
-
if (!this.auth) {
|
|
834
|
-
throw new Error('Auth instance not available');
|
|
346
|
+
// ─── Reauthentication ────────────────────────────────────────────────────────
|
|
347
|
+
async reauthenticate(currentPassword) {
|
|
348
|
+
const auth = this.getAuth();
|
|
349
|
+
if (!auth.currentUser?.email) {
|
|
350
|
+
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user with email found.');
|
|
835
351
|
}
|
|
836
352
|
try {
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
this.recaptchaVerifiers.clear();
|
|
840
|
-
await signOut(this.auth);
|
|
353
|
+
const credential = EmailAuthProvider.credential(auth.currentUser.email, currentPassword);
|
|
354
|
+
await reauthenticateWithCredential(auth.currentUser, credential);
|
|
841
355
|
}
|
|
842
356
|
catch (error) {
|
|
843
|
-
|
|
357
|
+
handleAuthError(error);
|
|
844
358
|
}
|
|
845
359
|
}
|
|
846
|
-
//
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
360
|
+
// ─── Custom token ────────────────────────────────────────────────────────────
|
|
361
|
+
async signInWithCustomToken(token) {
|
|
362
|
+
try {
|
|
363
|
+
const cred = await firebaseSignInWithCustomToken(this.getAuth(), token);
|
|
364
|
+
await this.syncToFirestore(cred.user);
|
|
365
|
+
const profile = this.profile(cred.user);
|
|
366
|
+
const isNewUser = getAdditionalUserInfo(cred)?.isNewUser ?? false;
|
|
367
|
+
return {
|
|
368
|
+
success: true,
|
|
369
|
+
user: profile,
|
|
370
|
+
method: 'custom',
|
|
371
|
+
timestamp: new Date(),
|
|
372
|
+
isNewUser
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
handleAuthError(error);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// ─── SAML / OIDC ─────────────────────────────────────────────────────────────
|
|
380
|
+
/** Signs in with a SAML provider (popup). */
|
|
381
|
+
async signInWithSAML(providerId) {
|
|
382
|
+
return this.signInWithOAuth('saml', new SAMLAuthProvider(providerId));
|
|
383
|
+
}
|
|
384
|
+
/** Signs in with a SAML provider (redirect). Pair with `getRedirectResult()` on load. */
|
|
385
|
+
async signInWithSAMLRedirect(providerId) {
|
|
386
|
+
await signInWithRedirect(this.getAuth(), new SAMLAuthProvider(providerId));
|
|
855
387
|
}
|
|
856
388
|
/**
|
|
857
|
-
*
|
|
858
|
-
* @
|
|
389
|
+
* Signs in with a generic OIDC/OAuth2 provider (popup).
|
|
390
|
+
* @param providerId Firebase provider ID, e.g. `'oidc.my-provider'`
|
|
391
|
+
* @param scopes Additional OAuth scopes to request.
|
|
859
392
|
*/
|
|
860
|
-
|
|
861
|
-
|
|
393
|
+
async signInWithOIDC(providerId, scopes = []) {
|
|
394
|
+
const provider = new OAuthProvider(providerId);
|
|
395
|
+
scopes.forEach((s) => provider.addScope(s));
|
|
396
|
+
return this.signInWithOAuth('oidc', provider);
|
|
397
|
+
}
|
|
398
|
+
/** Signs in with a generic OIDC/OAuth2 provider (redirect). Pair with `getRedirectResult()` on load. */
|
|
399
|
+
async signInWithOIDCRedirect(providerId, scopes = []) {
|
|
400
|
+
const provider = new OAuthProvider(providerId);
|
|
401
|
+
scopes.forEach((s) => provider.addScope(s));
|
|
402
|
+
await signInWithRedirect(this.getAuth(), provider);
|
|
403
|
+
}
|
|
404
|
+
// ─── Redirect sign-in ────────────────────────────────────────────────────────
|
|
405
|
+
async signInWithGoogleRedirect() {
|
|
406
|
+
await signInWithRedirect(this.getAuth(), createGoogleProvider());
|
|
407
|
+
}
|
|
408
|
+
async signInWithFacebookRedirect() {
|
|
409
|
+
await signInWithRedirect(this.getAuth(), createFacebookProvider());
|
|
410
|
+
}
|
|
411
|
+
async signInWithAppleRedirect() {
|
|
412
|
+
await signInWithRedirect(this.getAuth(), createAppleProvider());
|
|
413
|
+
}
|
|
414
|
+
async signInWithGithubRedirect() {
|
|
415
|
+
await signInWithRedirect(this.getAuth(), createGithubProvider());
|
|
416
|
+
}
|
|
417
|
+
async signInWithTwitterRedirect() {
|
|
418
|
+
await signInWithRedirect(this.getAuth(), createTwitterProvider());
|
|
419
|
+
}
|
|
420
|
+
async signInWithMicrosoftRedirect() {
|
|
421
|
+
await signInWithRedirect(this.getAuth(), createMicrosoftProvider());
|
|
862
422
|
}
|
|
863
423
|
/**
|
|
864
|
-
*
|
|
865
|
-
*
|
|
424
|
+
* Completes a redirect sign-in flow.
|
|
425
|
+
* Call this once on app load to pick up the result of a `signInWith*Redirect()` call.
|
|
426
|
+
* Returns null if no redirect sign-in is pending.
|
|
866
427
|
*/
|
|
867
|
-
|
|
868
|
-
|
|
428
|
+
async getRedirectResult() {
|
|
429
|
+
// Firebase returns provider IDs in the form 'google.com', 'github.com', etc.
|
|
430
|
+
// Map them to our OAuthProviderType format.
|
|
431
|
+
const PROVIDER_ID_MAP = {
|
|
432
|
+
'google.com': 'google',
|
|
433
|
+
'facebook.com': 'facebook',
|
|
434
|
+
'apple.com': 'apple',
|
|
435
|
+
'microsoft.com': 'microsoft',
|
|
436
|
+
'github.com': 'github',
|
|
437
|
+
'twitter.com': 'twitter'
|
|
438
|
+
};
|
|
439
|
+
try {
|
|
440
|
+
const result = await getRedirectResult(this.getAuth());
|
|
441
|
+
if (!result)
|
|
442
|
+
return null;
|
|
443
|
+
await this.syncToFirestore(result.user);
|
|
444
|
+
const profile = this.profile(result.user);
|
|
445
|
+
const isNewUser = getAdditionalUserInfo(result)?.isNewUser ?? false;
|
|
446
|
+
const rawId = result.providerId ?? '';
|
|
447
|
+
const provider = PROVIDER_ID_MAP[rawId] ??
|
|
448
|
+
(rawId.startsWith('saml.') ? 'saml' : rawId.startsWith('oidc.') ? 'oidc' : 'google');
|
|
449
|
+
return {
|
|
450
|
+
success: true,
|
|
451
|
+
user: profile,
|
|
452
|
+
method: provider,
|
|
453
|
+
timestamp: new Date(),
|
|
454
|
+
isNewUser,
|
|
455
|
+
provider
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
handleAuthError(error);
|
|
460
|
+
}
|
|
869
461
|
}
|
|
462
|
+
// ─── Multi-factor authentication ─────────────────────────────────────────────
|
|
870
463
|
/**
|
|
871
|
-
*
|
|
872
|
-
*
|
|
464
|
+
* Starts phone MFA enrollment for the currently signed-in user.
|
|
465
|
+
* Returns a `verificationId` to pass to `completeMFAEnrollment()`.
|
|
873
466
|
*/
|
|
874
|
-
|
|
875
|
-
|
|
467
|
+
async startPhoneMFAEnrollment(phoneNumber, recaptchaContainerId) {
|
|
468
|
+
const auth = this.getAuth();
|
|
469
|
+
if (!auth.currentUser) {
|
|
470
|
+
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
471
|
+
}
|
|
472
|
+
const existing = this.recaptchaVerifiers.get(recaptchaContainerId);
|
|
473
|
+
if (existing) {
|
|
474
|
+
existing.clear();
|
|
475
|
+
this.recaptchaVerifiers.delete(recaptchaContainerId);
|
|
476
|
+
}
|
|
477
|
+
const verifier = new RecaptchaVerifier(auth, recaptchaContainerId, { size: 'invisible' });
|
|
478
|
+
this.recaptchaVerifiers.set(recaptchaContainerId, verifier);
|
|
479
|
+
const mfaUser = multiFactor(auth.currentUser);
|
|
480
|
+
const session = await mfaUser.getSession();
|
|
481
|
+
const phoneProvider = new PhoneAuthProvider(auth);
|
|
482
|
+
return phoneProvider.verifyPhoneNumber({ phoneNumber, session }, verifier);
|
|
876
483
|
}
|
|
877
484
|
/**
|
|
878
|
-
*
|
|
879
|
-
* @returns {string | null} User's display name or null
|
|
485
|
+
* Completes phone MFA enrollment using the SMS code.
|
|
880
486
|
*/
|
|
881
|
-
|
|
882
|
-
|
|
487
|
+
async completeMFAEnrollment(verificationId, code, displayName) {
|
|
488
|
+
const auth = this.getAuth();
|
|
489
|
+
if (!auth.currentUser) {
|
|
490
|
+
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
491
|
+
}
|
|
492
|
+
const credential = PhoneAuthProvider.credential(verificationId, code);
|
|
493
|
+
const assertion = PhoneMultiFactorGenerator.assertion(credential);
|
|
494
|
+
await multiFactor(auth.currentUser).enroll(assertion, displayName);
|
|
495
|
+
}
|
|
496
|
+
/** Returns all enrolled MFA factors for the currently signed-in user. */
|
|
497
|
+
getMFAEnrolledFactors() {
|
|
498
|
+
const auth = this.getAuth();
|
|
499
|
+
if (!auth.currentUser)
|
|
500
|
+
return [];
|
|
501
|
+
return multiFactor(auth.currentUser).enrolledFactors;
|
|
502
|
+
}
|
|
503
|
+
/** Unenrolls a specific MFA factor by its UID or `MultiFactorInfo` object. */
|
|
504
|
+
async unenrollMFA(factorUidOrInfo) {
|
|
505
|
+
const auth = this.getAuth();
|
|
506
|
+
if (!auth.currentUser) {
|
|
507
|
+
throw new FirekitAuthError('auth/no-current-user', 'No authenticated user found.');
|
|
508
|
+
}
|
|
509
|
+
await multiFactor(auth.currentUser).unenroll(factorUidOrInfo);
|
|
883
510
|
}
|
|
884
511
|
/**
|
|
885
|
-
* Gets
|
|
886
|
-
*
|
|
512
|
+
* Gets the `MultiFactorResolver` from a sign-in error that requires MFA.
|
|
513
|
+
* Catch this error from any `signIn*` method when MFA is required.
|
|
887
514
|
*/
|
|
888
|
-
|
|
889
|
-
return this.
|
|
515
|
+
getMFAResolver(error) {
|
|
516
|
+
return getMultiFactorResolver(this.getAuth(), error);
|
|
890
517
|
}
|
|
891
518
|
/**
|
|
892
|
-
*
|
|
893
|
-
*
|
|
519
|
+
* Sends an SMS code to complete an MFA sign-in challenge.
|
|
520
|
+
* Returns a `verificationId` to pass to `completeMFASignIn()`.
|
|
521
|
+
*
|
|
522
|
+
* @param resolver From `getMFAResolver(error)`.
|
|
523
|
+
* @param factorIndex Index into `resolver.hints` (default 0).
|
|
524
|
+
* @param recaptchaContainerId DOM container ID for reCAPTCHA (required for phone MFA).
|
|
894
525
|
*/
|
|
895
|
-
|
|
896
|
-
|
|
526
|
+
async startMFASignIn(resolver, factorIndex = 0, recaptchaContainerId) {
|
|
527
|
+
const auth = this.getAuth();
|
|
528
|
+
const existing = this.recaptchaVerifiers.get(recaptchaContainerId);
|
|
529
|
+
if (existing) {
|
|
530
|
+
existing.clear();
|
|
531
|
+
this.recaptchaVerifiers.delete(recaptchaContainerId);
|
|
532
|
+
}
|
|
533
|
+
const verifier = new RecaptchaVerifier(auth, recaptchaContainerId, { size: 'invisible' });
|
|
534
|
+
this.recaptchaVerifiers.set(recaptchaContainerId, verifier);
|
|
535
|
+
const hint = resolver.hints[factorIndex];
|
|
536
|
+
const phoneProvider = new PhoneAuthProvider(auth);
|
|
537
|
+
return phoneProvider.verifyPhoneNumber({ multiFactorHint: hint, session: resolver.session }, verifier);
|
|
897
538
|
}
|
|
898
539
|
/**
|
|
899
|
-
*
|
|
900
|
-
* @returns {Promise<void>} Promise that resolves when cleanup completes
|
|
540
|
+
* Completes MFA sign-in using the SMS code.
|
|
901
541
|
*/
|
|
542
|
+
async completeMFASignIn(resolver, verificationId, code) {
|
|
543
|
+
const credential = PhoneAuthProvider.credential(verificationId, code);
|
|
544
|
+
const assertion = PhoneMultiFactorGenerator.assertion(credential);
|
|
545
|
+
try {
|
|
546
|
+
const cred = await resolver.resolveSignIn(assertion);
|
|
547
|
+
await this.syncToFirestore(cred.user);
|
|
548
|
+
const profile = this.profile(cred.user);
|
|
549
|
+
return {
|
|
550
|
+
success: true,
|
|
551
|
+
user: profile,
|
|
552
|
+
method: 'phone',
|
|
553
|
+
timestamp: new Date(),
|
|
554
|
+
isNewUser: false
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
catch (error) {
|
|
558
|
+
handleAuthError(error);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// ─── Utility getters ─────────────────────────────────────────────────────────
|
|
562
|
+
getCurrentUser() {
|
|
563
|
+
return this.auth?.currentUser ?? null;
|
|
564
|
+
}
|
|
565
|
+
isAuthenticated() {
|
|
566
|
+
return this.auth?.currentUser !== null && !this.auth?.currentUser?.isAnonymous;
|
|
567
|
+
}
|
|
568
|
+
isAnonymous() {
|
|
569
|
+
return this.auth?.currentUser?.isAnonymous ?? false;
|
|
570
|
+
}
|
|
571
|
+
isEmailVerified() {
|
|
572
|
+
return this.auth?.currentUser?.emailVerified ?? false;
|
|
573
|
+
}
|
|
902
574
|
async cleanup() {
|
|
903
|
-
|
|
904
|
-
this.recaptchaVerifiers.forEach((verifier) => verifier.clear());
|
|
575
|
+
this.recaptchaVerifiers.forEach((v) => v.clear());
|
|
905
576
|
this.recaptchaVerifiers.clear();
|
|
906
|
-
// Clear state listeners
|
|
907
|
-
this.stateListeners.clear();
|
|
908
577
|
}
|
|
909
578
|
}
|
|
910
|
-
/**
|
|
911
|
-
* Pre-initialized singleton instance of FirekitAuth.
|
|
912
|
-
* This is the main export that should be used throughout your application.
|
|
913
|
-
*
|
|
914
|
-
* @example
|
|
915
|
-
* ```typescript
|
|
916
|
-
* import { firekitAuth } from 'svelte-firekit';
|
|
917
|
-
*
|
|
918
|
-
* // Sign in with email
|
|
919
|
-
* await firekitAuth.signInWithEmail("user@example.com", "password");
|
|
920
|
-
*
|
|
921
|
-
* // Listen to auth state
|
|
922
|
-
* const unsubscribe = firekitAuth.onAuthStateChanged((state) => {
|
|
923
|
-
* if (state.user) {
|
|
924
|
-
* console.log("User is signed in:", state.user.email);
|
|
925
|
-
* } else {
|
|
926
|
-
* console.log("User is signed out");
|
|
927
|
-
* }
|
|
928
|
-
* });
|
|
929
|
-
*
|
|
930
|
-
* // Clean up listener
|
|
931
|
-
* unsubscribe();
|
|
932
|
-
* ```
|
|
933
|
-
*/
|
|
934
579
|
export const firekitAuth = FirekitAuth.getInstance();
|