diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 831a399..f77e873 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -5,7 +5,7 @@ on: branches: [master, main] pull_request: branches: [master, main] - + jobs: build: runs-on: ubuntu-latest diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..33affff --- /dev/null +++ b/.prettierignore @@ -0,0 +1,14 @@ +.DS_Store +node_modules +/build +/dist +/.svelte-kit +/package +.env +.env.* +!.env.example + +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..337af69 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "pluginSearchDirs": ["."], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/README.md b/README.md index bf78046..b684152 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SvelteFire -A minimal, yet powerful library that puts realtime Firebase data into Svelte stores. +A minimal, yet powerful library that puts realtime Firebase data into Svelte stores. [Documentation](https://sveltefire.fireship.io) @@ -15,7 +15,7 @@ A minimal, yet powerful library that puts realtime Firebase data into Svelte sto - +

{post.title}

@@ -30,7 +30,7 @@ A minimal, yet powerful library that puts realtime Firebase data into Svelte sto Svelte makes it possible to dramatically simplify the way developers work with Firebase. Here are some problems the project solves: -- Access users and realtime Firestore data as Svelte stores +- Access users and realtime Firestore data as Svelte stores - Automatic subscription disposal to prevent memory/cost leaks - Better TypeScript experience for Firebase - Handle complex relational data between Auth and Firestore @@ -45,9 +45,9 @@ npm i sveltefire firebase ``` ```ts -import { initializeApp } from 'firebase/app'; -import { getFirestore } from 'firebase/firestore'; -import { getAuth } from 'firebase/auth'; +import { initializeApp } from "firebase/app"; +import { getFirestore } from "firebase/firestore"; +import { getAuth } from "firebase/auth"; // Initialize Firebase const app = initializeApp(/* your firebase config */); @@ -59,32 +59,31 @@ export const auth = getAuth(app); ```svelte Hello {$user?.uid} ``` -3. Listen to realtime data. +3. Listen to realtime data. -Use the `$` as much as you want - it will only result in one Firebase read request. When all the subscriptions are removed, it will automatically unsubscribe. +Use the `$` as much as you want - it will only result in one Firebase read request. When all the subscriptions are removed, it will automatically unsubscribe. ```svelte {$post?.content} {$post?.title} ``` -Or better yet, use the built in `Doc` and `Collection` components. See below. - +Or better yet, use the built in `Doc` and `Collection` components. See below. ## Stores @@ -96,50 +95,48 @@ Listen to the current user. Render UI conditionally based on the auth state: ```svelte {#if $user} -

Hi {$user.uid}

+

Hi {$user.uid}

{:else} -

Sign in...

+

Sign in...

{/if} ``` ### Firestore Stores -Subscribe to realtime data. The store will unsubscribe automatically to avoid unnecessary Firestore reads. +Subscribe to realtime data. The store will unsubscribe automatically to avoid unnecessary Firestore reads. ```svelte {$post?.content} -{#each $posts as post} - -{/each} +{#each $posts as post}{/each} ``` Cast Firebase data to a TS interface: ```ts interface Post { - id: string; - title: string; - content: string; + id: string; + title: string; + content: string; } -const post = docStore(firestore, 'posts/test'); -const posts = collectionStore(firestore, 'posts'); +const post = docStore(firestore, "posts/test"); +const posts = collectionStore(firestore, "posts"); ``` ## SSR @@ -166,8 +163,8 @@ Second, pass the server data as the `startWith` value to a store. This will bypa // Data fetched via server export let data: PageData; -// Just give the store a startWith value -const post = docStore(firestore, 'posts/test', data.post); +// Just give the store a startWith value +const post = docStore(firestore, "posts/test", data.post); ``` ## Realtime Components @@ -187,10 +184,8 @@ The `FirebaseApp` component puts the FirebaseSDK into Svelte context. This avoid - - - - + + ``` @@ -205,16 +200,14 @@ You can use Svelte's context API to access the Firebase SDK in any component. ### User -Get the current user. +Get the current user. ```svelte - Hello {user.uid} + Hello {user.uid} - - You need to sign in! - +You need to sign in! ``` ### Doc @@ -223,8 +216,8 @@ Fetch a single document and listen to data in realtime. The `data` slot prop pro ```svelte - {data.content} - {ref.path} + {data.content} + {ref.path} ``` @@ -232,17 +225,17 @@ Slot props can be renamed: ```svelte - {post.content} - {postRef.path} + {post.content} + {postRef.path} ``` Firestore components can also handle loading states: - + ```svelte - -
Loading.... This will disappear when data is defined
+ +
Loading.... This will disappear when data is defined
``` @@ -252,10 +245,9 @@ Pass a `startWith` value to bypass the loading state. This is useful in SvelteKi ``` - ### Collection -Collections provides array of objects containing the document data, as well as the `id` and `ref` for each result. It also provides a `count` slot prop for number of docs in the query. +Collections provides array of objects containing the document data, as well as the `id` and `ref` for each result. It also provides a `count` slot prop for number of docs in the query. ```svelte @@ -272,49 +264,48 @@ Collections can also take a Firestore Query instead of a path: ```svelte - - + ``` ### DownloadURL -DownloadURL provides a `link` to download a file from Firebase Storage and its `reference`. +DownloadURL provides a `link` to download a file from Firebase Storage and its `reference`. ```svelte - Download {ref?.name} + Download {ref?.name} ``` ### StorageList -StorageList provides a list of `items` and `prefixes` corresponding to the list of objects and sub-folders at a given Firebase Storage path. +StorageList provides a list of `items` and `prefixes` corresponding to the list of objects and sub-folders at a given Firebase Storage path. ```svelte -
    - {#if list === null} -
  • Loading...
  • - {:else if list.prefixes.length === 0 && list.items.length === 0} -
  • Empty
  • - {:else} - - {#each list.prefixes as prefix} -
  • - {prefix.name} -
  • - {/each} - - {#each list.items as item} -
  • - {item.name} -
  • - {/each} - {/if} -
+
    + {#if list === null} +
  • Loading...
  • + {:else if list.prefixes.length === 0 && list.items.length === 0} +
  • Empty
  • + {:else} + + {#each list.prefixes as prefix} +
  • + {prefix.name} +
  • + {/each} + + {#each list.items as item} +
  • + {item.name} +
  • + {/each} + {/if} +
``` @@ -336,43 +327,38 @@ Upload a file with progress tracking ``` - ## Using Components Together These components can be combined to build complex realtime apps. It's especially powerful when fetching data that requires the current user's UID or a related document's path. - ```svelte -

UID: {user.uid}

- -

Profile

- - - {profile.content} +

UID: {user.uid}

+

Profile

+ + {profile.content} -

Comments

- - {#each comments as comment} - {comment.content} - {/each} +

Comments

+ + {#each comments as comment} + {comment.content} + {/each} -
Loading Comments...
-
+
Loading Comments...
+
-
Loading Profile...
-
+
Loading Profile...
+
-

Sign in to see your profile

+

Sign in to see your profile

``` - ## Roadmap - Add support for Firebase Storage diff --git a/docs/README.md b/docs/README.md index d723cb2..f67f23a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,2 +1 @@ # SvelteFire Docs Site - diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 1dcec2d..04e9e67 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -1,11 +1,11 @@ -import { defineConfig } from 'astro/config'; +import { defineConfig } from "astro/config"; import tailwind from "@astrojs/tailwind"; // https://astro.build/config export default defineConfig({ experimental: { - viewTransitions: true + viewTransitions: true, }, - integrations: [tailwind()] -}); \ No newline at end of file + integrations: [tailwind()], +}); diff --git a/docs/src/pages/api/index.md b/docs/src/pages/api/index.md index 0bdfdaa..5a6d646 100644 --- a/docs/src/pages/api/index.md +++ b/docs/src/pages/api/index.md @@ -5,4 +5,4 @@ description: SvelteFire API Docs layout: ../../layouts/MainLayout.astro --- -## TODO \ No newline at end of file +## TODO diff --git a/docs/src/pages/app/context.md b/docs/src/pages/app/context.md index 8c145f7..80e4433 100644 --- a/docs/src/pages/app/context.md +++ b/docs/src/pages/app/context.md @@ -7,13 +7,13 @@ layout: ../../layouts/MainLayout.astro # getFirebaseContext -Get the Firebase SDK context from a component. +Get the Firebase SDK context from a component. ### Example ```svelte -``` \ No newline at end of file +``` diff --git a/docs/src/pages/app/firebase-app.md b/docs/src/pages/app/firebase-app.md index 32aa65c..653e996 100644 --- a/docs/src/pages/app/firebase-app.md +++ b/docs/src/pages/app/firebase-app.md @@ -19,18 +19,18 @@ Puts the Firebase app into Svelte's context. It should be used as a parent to al ```svelte - + -``` \ No newline at end of file +``` diff --git a/docs/src/pages/auth/signed-in.md b/docs/src/pages/auth/signed-in.md index b303191..389f98c 100644 --- a/docs/src/pages/auth/signed-in.md +++ b/docs/src/pages/auth/signed-in.md @@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro # SignedIn -The `SignedIn` component renders content for the current user. It is a wrapper around the `userStore`. If the user is not signed in, the children will not be rendered. +The `SignedIn` component renders content for the current user. It is a wrapper around the `userStore`. If the user is not signed in, the children will not be rendered. ### Slot Props @@ -19,15 +19,14 @@ The `SignedIn` component renders content for the current user. It is a wrapper a ```svelte -

Howdy, {user.uid}

+

Howdy, {user.uid}

- - + -``` \ No newline at end of file +``` diff --git a/docs/src/pages/auth/signed-out.md b/docs/src/pages/auth/signed-out.md index 7b92a2a..7093046 100644 --- a/docs/src/pages/auth/signed-out.md +++ b/docs/src/pages/auth/signed-out.md @@ -17,16 +17,13 @@ The `SignedOut` component renders content when the current user is `null`. It is ```svelte - - You must be signed in to see this! - - +You must be signed in to see this! - + ``` diff --git a/docs/src/pages/auth/user-store.md b/docs/src/pages/auth/user-store.md index 628a9c7..0818088 100644 --- a/docs/src/pages/auth/user-store.md +++ b/docs/src/pages/auth/user-store.md @@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro # userStore -Listens the current Firebase user. +Listens the current Firebase user. ### Parameters @@ -17,11 +17,11 @@ Listens the current Firebase user. ```svelte Hello {$user.uid} -``` \ No newline at end of file +``` diff --git a/docs/src/pages/firestore/collection-component.md b/docs/src/pages/firestore/collection-component.md index 35be91b..c0a029b 100644 --- a/docs/src/pages/firestore/collection-component.md +++ b/docs/src/pages/firestore/collection-component.md @@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro # Collection -The `Collection` component is a wrapper around the `collectionStore`. It renders the collection data and handles the loading state. +The `Collection` component is a wrapper around the `collectionStore`. It renders the collection data and handles the loading state. ### Props @@ -30,17 +30,16 @@ The `Collection` component is a wrapper around the `collectionStore`. It renders ```svelte - + +

Found {count} posts

-

Found {count} posts

- - {#each data as post} -

{post.title}

- {/each} + {#each data as post} +

{post.title}

+ {/each} -

Loading...

+

Loading...

-``` \ No newline at end of file +``` diff --git a/docs/src/pages/firestore/collection-store.md b/docs/src/pages/firestore/collection-store.md index 313ccb9..ed2e85e 100644 --- a/docs/src/pages/firestore/collection-store.md +++ b/docs/src/pages/firestore/collection-store.md @@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro # collectionStore -Subscribes to Firestore collection data and listens to real-time updates. +Subscribes to Firestore collection data and listens to real-time updates. ### Parameters @@ -19,30 +19,29 @@ Subscribes to Firestore collection data and listens to real-time updates. ```svelte {#each $posts as post} -

{post.title}

+

{post.title}

{/each} ``` - With a query reference: ```svelte ``` @@ -50,16 +49,15 @@ With TypeScript: ```svelte {#each $posts as post} -

{post.title}

+

{post.title}

{/each} ``` diff --git a/docs/src/pages/firestore/doc-component.md b/docs/src/pages/firestore/doc-component.md index 4860040..46ae68c 100644 --- a/docs/src/pages/firestore/doc-component.md +++ b/docs/src/pages/firestore/doc-component.md @@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro # Doc -The `Doc` component is a wrapper around the `docStore`. It renders the document data and handles the loading state. +The `Doc` component is a wrapper around the `docStore`. It renders the document data and handles the loading state. ### Props @@ -29,12 +29,12 @@ The `Doc` component is a wrapper around the `docStore`. It renders the document ```svelte - -

{data?.title}

+ +

{data?.title}

-

Loading...

+

Loading...

-``` \ No newline at end of file +``` diff --git a/docs/src/pages/firestore/doc-store.md b/docs/src/pages/firestore/doc-store.md index caf2c30..f2959bf 100644 --- a/docs/src/pages/firestore/doc-store.md +++ b/docs/src/pages/firestore/doc-store.md @@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro # docStore -Subscribes to Firestore document data and listens to realtime updates. +Subscribes to Firestore document data and listens to realtime updates. ### Parameters @@ -19,10 +19,10 @@ Subscribes to Firestore document data and listens to realtime updates. ```svelte {$post?.title} @@ -32,12 +32,12 @@ With a document reference: ```svelte ``` @@ -45,14 +45,13 @@ With TypeScript: ```svelte {$post?.title} -``` \ No newline at end of file +``` diff --git a/docs/src/pages/guide/start.md b/docs/src/pages/guide/start.md index 3ede576..960283d 100644 --- a/docs/src/pages/guide/start.md +++ b/docs/src/pages/guide/start.md @@ -7,8 +7,7 @@ layout: ../../layouts/MainLayout.astro # QuickStart -SvelteFire works in both SvelteKit and standalone Svelte apps. This guide assumes you're using SvelteKit. - +SvelteFire works in both SvelteKit and standalone Svelte apps. This guide assumes you're using SvelteKit. ### 1. Install @@ -18,24 +17,25 @@ npm i sveltefire firebase ### 2. Initialize -Initialize Firebase and add the `FirebaseApp` component to the component tree. Typically, this is done in the root `+layout.svelte` file to access Firebase on all pages. +Initialize Firebase and add the `FirebaseApp` component to the component tree. Typically, this is done in the root `+layout.svelte` file to access Firebase on all pages. #### +layout.svelte + ```svelte - + ``` @@ -45,43 +45,42 @@ You can use stores to access the current user and Firestore. ```svelte {$user?.displayName} {$post?.content} ``` -Or you can use components to more easily pass data around. Notice how slot props like `let:user` and `let:data` allow us to access data from the backend with minimal effort. Here are some common examples. +Or you can use components to more easily pass data around. Notice how slot props like `let:user` and `let:data` allow us to access data from the backend with minimal effort. Here are some common examples. ```svelte -

Hello {user.uid}

- +

Hello {user.uid}

+
- + -

{data.title}

-

{data.content}

+

{data.title}

+

{data.content}

- {#each posts as post} -

{post.title}

-

{post.content}

- {/each} + {#each posts as post} +

{post.title}

+

{post.content}

+ {/each}
``` diff --git a/docs/src/pages/guide/todo.md b/docs/src/pages/guide/todo.md index 1499729..e06e097 100644 --- a/docs/src/pages/guide/todo.md +++ b/docs/src/pages/guide/todo.md @@ -7,4 +7,4 @@ layout: ../../layouts/MainLayout.astro # Coming Soon -This feature is under development. Please check back later. \ No newline at end of file +This feature is under development. Please check back later. diff --git a/docs/src/pages/index.md b/docs/src/pages/index.md index d959af1..1612339 100644 --- a/docs/src/pages/index.md +++ b/docs/src/pages/index.md @@ -1,19 +1,19 @@ --- title: SvelteFire? pubDate: 2023-07-23 -description: 'Why use SvelteFire over vanilla Firebase?' +description: "Why use SvelteFire over vanilla Firebase?" layout: ../layouts/MainLayout.astro --- # 🔥 SvelteFire -SvelteFire is a minimal, yet powerful library that puts realtime Firebase data into Svelte stores. +SvelteFire is a minimal, yet powerful library that puts realtime Firebase data into Svelte stores. ## Why? -Firebase realtime APIs are callback-based, but we can dramatically improve the developer experience by leveraging Svelte's reactive stores. +Firebase realtime APIs are callback-based, but we can dramatically improve the developer experience by leveraging Svelte's reactive stores. -- Access users and realtime Firestore data as Svelte stores +- Access users and realtime Firestore data as Svelte stores - Automatic subscription disposal to prevent duplicate reads - Better TypeScript experience for Firebase - Handle complex relational data between Auth and Firestore @@ -23,9 +23,9 @@ Firebase realtime APIs are callback-based, but we can dramatically improve the d Get the current user: -```svelte +```svelte Hello {$user.uid} @@ -35,7 +35,7 @@ Get a Firestore document. Any changes to the document will be reflected instantl ```svelte {$post.title} @@ -44,7 +44,7 @@ Get a Firestore document. Any changes to the document will be reflected instantl ## Component Example -We can take this a step further with components and slot props. Under the hood, these components use the same stores as above, but make common patterns dead simple. The example below renders content for the signed-in user while fetching multiple levels of relational data `user->post->comments`. +We can take this a step further with components and slot props. Under the hood, these components use the same stores as above, but make common patterns dead simple. The example below renders content for the signed-in user while fetching multiple levels of relational data `user->post->comments`. ```svelte @@ -57,7 +57,7 @@ We can take this a step further with components and slot props. Under the hood, - +

{post.title}

@@ -66,4 +66,4 @@ We can take this a step further with components and slot props. Under the hood, {/each} ... -``` \ No newline at end of file +``` diff --git a/docs/src/pages/storage/download-url.md b/docs/src/pages/storage/download-url.md index 6d84bec..2de109e 100644 --- a/docs/src/pages/storage/download-url.md +++ b/docs/src/pages/storage/download-url.md @@ -28,15 +28,14 @@ Returns the download URL for a file in Firebase Storage. ```svelte - - - + + - - {ref?.name} + + {ref?.name} -``` \ No newline at end of file +``` diff --git a/docs/src/pages/storage/storage-list.md b/docs/src/pages/storage/storage-list.md index e71a7eb..6950953 100644 --- a/docs/src/pages/storage/storage-list.md +++ b/docs/src/pages/storage/storage-list.md @@ -28,30 +28,29 @@ Returns a list of files stored in Firebase Storage. ```svelte - -
    - {#if list === null} -
  • Loading...
  • - {:else if list.prefixes.length === 0 && list.items.length === 0} -
  • Empty
  • - {:else} - - {#each list.prefixes as prefix} -
  • - {prefix.name} -
  • - {/each} - - {#each list.items as item} -
  • - {item.name} -
  • - {/each} - {/if} -
+
    + {#if list === null} +
  • Loading...
  • + {:else if list.prefixes.length === 0 && list.items.length === 0} +
  • Empty
  • + {:else} + + {#each list.prefixes as prefix} +
  • + {prefix.name} +
  • + {/each} + + {#each list.items as item} +
  • + {item.name} +
  • + {/each} + {/if} +
-``` \ No newline at end of file +``` diff --git a/docs/src/pages/storage/upload-task.md b/docs/src/pages/storage/upload-task.md index 8f511a5..d0291bd 100644 --- a/docs/src/pages/storage/upload-task.md +++ b/docs/src/pages/storage/upload-task.md @@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro # UploadTask -Uploads a file to a Firebase storage bucket. +Uploads a file to a Firebase storage bucket. ### Props @@ -15,10 +15,9 @@ Uploads a file to a Firebase storage bucket. - `data` - the file data to be uploaded as `Blob | Uint8Array | ArrayBuffer` - `metadata` - (optional) file metadata - ### Slots -- `default` +- `default` ### Slot Props @@ -31,7 +30,7 @@ Uploads a file to a Firebase storage bucket. ```svelte {#if $store !== undefined} - + {:else} - + {/if} - diff --git a/src/lib/components/SignedIn.svelte b/src/lib/components/SignedIn.svelte index d16eb6d..feaffee 100644 --- a/src/lib/components/SignedIn.svelte +++ b/src/lib/components/SignedIn.svelte @@ -1,17 +1,16 @@ - - {#if $user} - signOut(auth)} /> - {/if} \ No newline at end of file + const auth = getFirebaseContext().auth!; + const user = userStore(auth); + + interface $$Slots { + default: { user: User; auth: Auth; signOut: () => Promise }; + } + + +{#if $user} + signOut(auth)} /> +{/if} diff --git a/src/lib/components/SignedOut.svelte b/src/lib/components/SignedOut.svelte index 06febf6..eac12a5 100644 --- a/src/lib/components/SignedOut.svelte +++ b/src/lib/components/SignedOut.svelte @@ -1,17 +1,16 @@ - - - {#if !$user} - - {/if} \ No newline at end of file +{#if !$user} + +{/if} diff --git a/src/lib/components/StorageList.svelte b/src/lib/components/StorageList.svelte index 5b1966f..a15989b 100644 --- a/src/lib/components/StorageList.svelte +++ b/src/lib/components/StorageList.svelte @@ -1,22 +1,21 @@ {#if $listStore !== undefined} - + {:else} - + {/if} - diff --git a/src/lib/components/User.svelte b/src/lib/components/User.svelte index 8e06469..f7271d3 100644 --- a/src/lib/components/User.svelte +++ b/src/lib/components/User.svelte @@ -4,11 +4,11 @@ import { getFirebaseContext } from "$lib/index.js"; const auth = getFirebaseContext().auth!; - const user = userStore(auth) + const user = userStore(auth); interface $$Slots { - default: { user: User } - signedOut: {} + default: { user: User }; + signedOut: {}; } @@ -16,4 +16,4 @@ {:else} -{/if} \ No newline at end of file +{/if} diff --git a/src/lib/index.js b/src/lib/index.js index 1b93c26..6216462 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -1,33 +1,33 @@ // Reexport your entry components here -import User from './components/User.svelte'; -import Collection from './components/Collection.svelte'; -import Doc from './components/Doc.svelte'; -import FirebaseApp from './components/FirebaseApp.svelte'; -import SignedIn from './components/SignedIn.svelte'; -import SignedOut from './components/SignedOut.svelte'; -import DownloadURL from './components/DownloadURL.svelte'; -import StorageList from './components/StorageList.svelte'; -import UploadTask from './components/UploadTask.svelte'; -import { userStore } from './stores/auth.js'; -import { docStore, collectionStore } from './stores/firestore.js'; -import { getFirebaseContext } from './stores/sdk.js'; -import { downloadUrlStore, storageListStore, uploadTaskStore } from './stores/storage.js'; +import User from "./components/User.svelte"; +import Collection from "./components/Collection.svelte"; +import Doc from "./components/Doc.svelte"; +import FirebaseApp from "./components/FirebaseApp.svelte"; +import SignedIn from "./components/SignedIn.svelte"; +import SignedOut from "./components/SignedOut.svelte"; +import DownloadURL from "./components/DownloadURL.svelte"; +import StorageList from "./components/StorageList.svelte"; +import UploadTask from "./components/UploadTask.svelte"; +import { userStore } from "./stores/auth.js"; +import { docStore, collectionStore } from "./stores/firestore.js"; +import { getFirebaseContext } from "./stores/sdk.js"; +import { downloadUrlStore, storageListStore, uploadTaskStore } from "./stores/storage.js"; export { - Doc, - User, - Collection, - FirebaseApp, - SignedOut, - SignedIn, - UploadTask, - StorageList, - DownloadURL, - downloadUrlStore, - storageListStore, - uploadTaskStore, - docStore, - collectionStore, - userStore, - getFirebaseContext, -} \ No newline at end of file + Doc, + User, + Collection, + FirebaseApp, + SignedOut, + SignedIn, + UploadTask, + StorageList, + DownloadURL, + downloadUrlStore, + storageListStore, + uploadTaskStore, + docStore, + collectionStore, + userStore, + getFirebaseContext, +}; diff --git a/src/lib/stores/firestore.ts b/src/lib/stores/firestore.ts index 6bdd771..976e4c9 100644 --- a/src/lib/stores/firestore.ts +++ b/src/lib/stores/firestore.ts @@ -1,11 +1,6 @@ import { writable } from "svelte/store"; import { doc, collection, onSnapshot } from "firebase/firestore"; -import type { - Query, - CollectionReference, - DocumentReference, - Firestore, -} from "firebase/firestore"; +import type { Query, CollectionReference, DocumentReference, Firestore } from "firebase/firestore"; interface DocStore { subscribe: (cb: (value: T | null) => void) => void | (() => void); @@ -49,10 +44,7 @@ export function docStore( }; } - const docRef = - typeof ref === "string" - ? (doc(firestore, ref) as DocumentReference) - : ref; + const docRef = typeof ref === "string" ? (doc(firestore, ref) as DocumentReference) : ref; const { subscribe } = writable(startWith, (set) => { unsubscribe = onSnapshot(docRef, (snapshot) => { diff --git a/src/lib/stores/sdk.ts b/src/lib/stores/sdk.ts index d8d525a..401a7a6 100644 --- a/src/lib/stores/sdk.ts +++ b/src/lib/stores/sdk.ts @@ -3,7 +3,6 @@ import type { Auth } from "firebase/auth"; import { getContext, setContext } from "svelte"; import type { FirebaseStorage } from "firebase/storage"; - export interface FirebaseSDKContext { auth?: Auth; firestore?: Firestore; diff --git a/src/lib/stores/storage.ts b/src/lib/stores/storage.ts index 168207a..b482bd1 100644 --- a/src/lib/stores/storage.ts +++ b/src/lib/stores/storage.ts @@ -1,10 +1,5 @@ import { readable } from "svelte/store"; -import { - getDownloadURL, - list, - ref, - uploadBytesResumable, -} from "firebase/storage"; +import { getDownloadURL, list, ref, uploadBytesResumable } from "firebase/storage"; import type { StorageReference, @@ -56,8 +51,7 @@ export function storageListStore( }; } - const storageRef = - typeof reference === "string" ? ref(storage, reference) : reference; + const storageRef = typeof reference === "string" ? ref(storage, reference) : reference; const { subscribe } = readable(startWith, (set) => { list(storageRef).then((snapshot) => { @@ -108,8 +102,7 @@ export function downloadUrlStore( }; } - const storageRef = - typeof reference === "string" ? ref(storage, reference) : reference; + const storageRef = typeof reference === "string" ? ref(storage, reference) : reference; const { subscribe } = readable(startWith, (set) => { getDownloadURL(storageRef).then((snapshot) => { @@ -124,9 +117,7 @@ export function downloadUrlStore( } interface UploadTaskStore { - subscribe: ( - cb: (value: UploadTaskSnapshot | null) => void - ) => void | (() => void); + subscribe: (cb: (value: UploadTaskSnapshot | null) => void) => void | (() => void); reference: StorageReference | null; } @@ -157,8 +148,7 @@ export function uploadTaskStore( }; } - const storageRef = - typeof reference === "string" ? ref(storage, reference) : reference; + const storageRef = typeof reference === "string" ? ref(storage, reference) : reference; let unsubscribe: () => void; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 3551237..6f51539 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,9 +1,8 @@ - + diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 258a113..b329513 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,9 +1,7 @@

Welcome to SvelteFire

diff --git a/src/routes/auth-test/+page.svelte b/src/routes/auth-test/+page.svelte index cacf096..7948855 100644 --- a/src/routes/auth-test/+page.svelte +++ b/src/routes/auth-test/+page.svelte @@ -1,18 +1,18 @@

Auth Test

-

Signed In

-

Hello {user.uid}

- +

Signed In

+

Hello {user.uid}

+
-

Signed Out

- +

Signed Out

+
diff --git a/src/routes/firebase.ts b/src/routes/firebase.ts index 0d92226..14c96f8 100644 --- a/src/routes/firebase.ts +++ b/src/routes/firebase.ts @@ -4,15 +4,14 @@ import { connectAuthEmulator, getAuth } from "firebase/auth"; import { dev } from "$app/environment"; import { connectStorageEmulator, getStorage, ref, uploadString } from "firebase/storage"; - const firebaseConfig = { - apiKey: "AIzaSyAMHfJp1ec85QBo-mnke89qtiYGen9zTSE", - authDomain: "sveltefire-testing.firebaseapp.com", - databaseURL: "https://sveltefire-testing.firebaseio.com", - projectId: "sveltefire-testing", - storageBucket: "sveltefire-testing.appspot.com", - messagingSenderId: "1030648105982", - appId: "1:1030648105982:web:2afebc34841fa242ed4eaf" + apiKey: "AIzaSyAMHfJp1ec85QBo-mnke89qtiYGen9zTSE", + authDomain: "sveltefire-testing.firebaseapp.com", + databaseURL: "https://sveltefire-testing.firebaseio.com", + projectId: "sveltefire-testing", + storageBucket: "sveltefire-testing.appspot.com", + messagingSenderId: "1030648105982", + appId: "1:1030648105982:web:2afebc34841fa242ed4eaf", }; // Initialize Firebase @@ -22,27 +21,25 @@ export const auth = getAuth(app); export const storage = getStorage(app); if (dev || import.meta.env.MODE === "ci") { - connectAuthEmulator(auth, "http://localhost:9099"); - connectFirestoreEmulator(db, "localhost", 8080); - connectStorageEmulator(storage, "localhost", 9199); - - // Seed Firestore - setDoc(doc(db, "posts", "test"), { - title: "Hi Mom", - content: "this is a test" + connectAuthEmulator(auth, "http://localhost:9099"); + connectFirestoreEmulator(db, "localhost", 8080); + connectStorageEmulator(storage, "localhost", 9199); + + // Seed Firestore + setDoc(doc(db, "posts", "test"), { + title: "Hi Mom", + content: "this is a test", + }); + + // Create a reference to the file to create + const fileRef = ref(storage, "test.txt"); + + // Upload a string to the file + uploadString(fileRef, "Hello, world!", "raw") + .then(() => { + console.log("File created successfully!"); + }) + .catch((error) => { + console.error("Error creating file:", error); }); - - - // Create a reference to the file to create - const fileRef = ref(storage, "test.txt"); - - // Upload a string to the file - uploadString(fileRef, "Hello, world!", "raw") - .then(() => { - console.log("File created successfully!"); - }) - .catch((error) => { - console.error("Error creating file:", error); - }); } - diff --git a/src/routes/firestore-test/+page.svelte b/src/routes/firestore-test/+page.svelte index 40d5894..32976c0 100644 --- a/src/routes/firestore-test/+page.svelte +++ b/src/routes/firestore-test/+page.svelte @@ -1,13 +1,8 @@ @@ -45,20 +37,13 @@

User Owned Posts

-

Signed Out

- +

Signed Out

+
- -

Collection

- +

You've made {count} posts

    diff --git a/src/routes/ssr-test/+page.svelte b/src/routes/ssr-test/+page.svelte index 9787a76..02a823f 100644 --- a/src/routes/ssr-test/+page.svelte +++ b/src/routes/ssr-test/+page.svelte @@ -7,9 +7,9 @@

    Not Hydrated: {data?.title}

    -

    Hydrated: {realtimeData?.title}

    +

    Hydrated: {realtimeData?.title}

    Home -

    \ No newline at end of file +

    diff --git a/src/routes/ssr-test/+page.ts b/src/routes/ssr-test/+page.ts index 77468a3..5a0660f 100644 --- a/src/routes/ssr-test/+page.ts +++ b/src/routes/ssr-test/+page.ts @@ -1,13 +1,13 @@ -import { doc, getDoc } from 'firebase/firestore'; -import { db } from '../firebase.js'; +import { doc, getDoc } from "firebase/firestore"; +import { db } from "../firebase.js"; -export const load = (async () => { - const ref = doc(db, 'posts', 'test'); - const docSnap = await getDoc(ref); - const data = docSnap.data(); - return { - title: data?.title, - content: data?.content, - uid: data?.uid, - }; -}); \ No newline at end of file +export const load = async () => { + const ref = doc(db, "posts", "test"); + const docSnap = await getDoc(ref); + const data = docSnap.data(); + return { + title: data?.title, + content: data?.content, + uid: data?.uid, + }; +}; diff --git a/svelte.config.js b/svelte.config.js index 46d378f..b879fb1 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,13 +1,13 @@ -import adapter from '@sveltejs/adapter-auto'; -import { vitePreprocess } from '@sveltejs/kit/vite'; +import adapter from "@sveltejs/adapter-auto"; +import { vitePreprocess } from "@sveltejs/kit/vite"; /** @type {import('@sveltejs/kit').Config} */ const config = { - preprocess: vitePreprocess(), + preprocess: vitePreprocess(), - kit: { - adapter: adapter() - } + kit: { + adapter: adapter(), + }, }; export default config; diff --git a/tests/auth.test.ts b/tests/auth.test.ts index 3f766c2..70ec345 100644 --- a/tests/auth.test.ts +++ b/tests/auth.test.ts @@ -16,9 +16,8 @@ test.describe.serial("Auth", () => { }); test("User can sign in and out", async () => { - await expect(page.getByRole("button", { name: "Sign In" })).toBeVisible(); - await page.getByRole("button", { name: "Sign In" }).click({delay: 1000}); + await page.getByRole("button", { name: "Sign In" }).click({ delay: 1000 }); await expect(page.getByRole("button", { name: "Sign Out" })).toBeVisible(); await page.getByRole("button", { name: "Sign Out" }).click(); diff --git a/tests/firestore.test.ts b/tests/firestore.test.ts index 02d3a70..ec50d39 100644 --- a/tests/firestore.test.ts +++ b/tests/firestore.test.ts @@ -1,21 +1,18 @@ -import { expect, test } from '@playwright/test'; +import { expect, test } from "@playwright/test"; -test('Renders a single document', async ({ page }) => { - await page.goto('/firestore-test'); - await expect(page.getByTestId('doc-data')).toContainText('Hi Mom'); +test("Renders a single document", async ({ page }) => { + await page.goto("/firestore-test"); + await expect(page.getByTestId("doc-data")).toContainText("Hi Mom"); }); -test('Renders a collection of items for an authenticated user in realtime', async ({ page }) => { - await page.goto('/firestore-test'); - await page.getByRole('button', { 'name': 'Sign In'}).click(); - await expect(page.getByTestId('count')).toContainText('0 posts'); - await page.getByRole('button', { name: 'Add Post' }).click(); - await expect(page.getByTestId('count')).toContainText('1 posts'); - await page.getByRole('button', { name: 'Add Post' }).click(); - await expect(page.getByTestId('count')).toContainText('2 posts'); - await expect(page.locator('li')).toHaveCount(2); - await expect(page.locator('li')).toContainText([ - 'firestore item', - 'firestore item' - ]); +test("Renders a collection of items for an authenticated user in realtime", async ({ page }) => { + await page.goto("/firestore-test"); + await page.getByRole("button", { name: "Sign In" }).click(); + await expect(page.getByTestId("count")).toContainText("0 posts"); + await page.getByRole("button", { name: "Add Post" }).click(); + await expect(page.getByTestId("count")).toContainText("1 posts"); + await page.getByRole("button", { name: "Add Post" }).click(); + await expect(page.getByTestId("count")).toContainText("2 posts"); + await expect(page.locator("li")).toHaveCount(2); + await expect(page.locator("li")).toContainText(["firestore item", "firestore item"]); }); diff --git a/tests/main.test.ts b/tests/main.test.ts index 465f104..a5eaf5a 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1,14 +1,14 @@ -import { expect, test } from '@playwright/test'; +import { expect, test } from "@playwright/test"; -test('SvelteFire app initializes properly', async ({ page }) => { - await page.goto('/'); - await expect(page.locator('h1')).toHaveText('Welcome to SvelteFire'); +test("SvelteFire app initializes properly", async ({ page }) => { + await page.goto("/"); + await expect(page.locator("h1")).toHaveText("Welcome to SvelteFire"); }); -test('Firebase SDK context is defined via FirebaseApp component', async ({ page }) => { - await page.goto('/'); - - await expect( page.getByTestId('auth')).toContainText('true'); - await expect( page.getByTestId('firestore')).toContainText('true'); - await expect( page.getByTestId('storage')).toContainText('true'); -}); \ No newline at end of file +test("Firebase SDK context is defined via FirebaseApp component", async ({ page }) => { + await page.goto("/"); + + await expect(page.getByTestId("auth")).toContainText("true"); + await expect(page.getByTestId("firestore")).toContainText("true"); + await expect(page.getByTestId("storage")).toContainText("true"); +}); diff --git a/tests/storage.test.ts b/tests/storage.test.ts index 4e5e523..ef5e3e6 100644 --- a/tests/storage.test.ts +++ b/tests/storage.test.ts @@ -1,16 +1,15 @@ -import { expect, test } from '@playwright/test'; +import { expect, test } from "@playwright/test"; - -test('Renders download links', async ({ page }) => { - await page.goto('/storage-test'); - await page.waitForSelector('[data-testid="download-link"]'); - const linksCount = await page.getByTestId('download-link').count() - expect( linksCount ).toBeGreaterThan(0); +test("Renders download links", async ({ page }) => { + await page.goto("/storage-test"); + await page.waitForSelector('[data-testid="download-link"]'); + const linksCount = await page.getByTestId("download-link").count(); + expect(linksCount).toBeGreaterThan(0); }); -test('Uploads a file', async ({ page }) => { - await page.goto('/storage-test'); - await page.getByRole('button', { name: 'Make File' }).click(); - await expect(page.getByTestId('progress')).toContainText('100% uploaded'); - await expect(page.getByTestId('download-link2')).toContainText('test-upload.txt'); -}); \ No newline at end of file +test("Uploads a file", async ({ page }) => { + await page.goto("/storage-test"); + await page.getByRole("button", { name: "Make File" }).click(); + await expect(page.getByTestId("progress")).toContainText("100% uploaded"); + await expect(page.getByTestId("download-link2")).toContainText("test-upload.txt"); +}); diff --git a/tsconfig.json b/tsconfig.json index f56aae6..9a9b2ea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,14 @@ { - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "moduleResolution": "NodeNext" - } + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "NodeNext" + } } diff --git a/vite.config.js b/vite.config.js index bbf8c7d..80864b9 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,6 +1,6 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; +import { sveltekit } from "@sveltejs/kit/vite"; +import { defineConfig } from "vite"; export default defineConfig({ - plugins: [sveltekit()] + plugins: [sveltekit()], });