sveltedfire 0.0.8 → 0.1.3

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 CHANGED
@@ -26,6 +26,18 @@ This guarantees that firebase has been initialized prior to any data loading cal
26
26
 
27
27
  ### Authentication
28
28
 
29
+ In order to fully utilize the helper components sveltedfire contains, you must wrap your app at a high level with the `SveltedAuth` component. This initializes the firebase authentication system and provides a context that provides access to the current user. To access the auth context, use the `getAuthContext` helper. Additional keys can be injected onto the context by adding them as props on `SveltedAuth` with the prefix `extra_` and the value being a function that accepts user and token. This function will be called with user and token of null in the case of a logged out user to initialize default values. E.g., to add the key `claimLevel` to the sveltedAuth context:
30
+
31
+ ```svelte
32
+ <script lang="ts">
33
+ import { SveltedAuth } from 'sveltedfire'
34
+ </script>
35
+
36
+ <SveltedAuth extra_claimLevel={(user, token) => token!.claims.level || ''}>
37
+ ...rest of application
38
+ </SveltedAuth>
39
+ ```
40
+
29
41
  You can use the SignedIn/SignoutOut components to selectively render based on the user's authentication state. In addition, the `signOut` and `signInWithGoogle` helpers are available. Note that the signInWithGoogle automatically performs a signInWithPopup. If you would rather use signInWithRedirect, you will need to implement that manually.
30
42
 
31
43
  ### Fetching/Querying
@@ -37,11 +49,12 @@ fetchDoc('pages', params.slug)
37
49
  fetchDoc('pages', 'home', 'posts', params.postId)
38
50
  ```
39
51
 
40
- To perform a query for one or more documents, use the `fetchDocs` method. This is a double-invoked function. The first invocation sets the collection path. The second invocation accepts either three arguments (field name, comparator, value), no arguments for a simple collection fetch, or a single argument of an already formed QueryFieldFilterConstraint or a QueryCompositeFilterConstraint. E.g.,
52
+ To perform a query for one or more documents, use the `fetchDocs` method. This is a double-invoked function. The first invocation sets the collection path. The second invocation accepts either a variable number of arguments. It accepts three arguments specifically for a simpler form of a where condition. Otherwise, you can pass one or more firestore constraints (where, limit, orderBy, startAt, endAt) and up to one composite filter (and, or)
41
53
  ```typescript
42
54
  fetchDocs('pages')() // fetch all pages
43
55
  fetchDocs('pages')('public', '==', true) // fetch all public pages
44
56
  fetchDocs('pages')(and(where('published_at', '>=', '2025-01-01'), where('published_at', '<=', '2025-01-31'))) // fetch all pages published in the month of January
57
+ fetchDocs('pages')(where('public', '==', true), limit(10), orderBy('published_at', 'desc'))
45
58
  ```
46
59
 
47
60
  To listen for the snapshots of an object, use `listenDoc`. This takes the same parameters as `fetchDoc`, but returns a store. This should be used with rune syntax as below:
package/dist/index.d.ts CHANGED
@@ -7,6 +7,10 @@ export { listenDoc } from './sveltedfire/utilities/listenDoc.js';
7
7
  export { listenDocs } from './sveltedfire/utilities/listenDocs.js';
8
8
  export { kindlyFetchDoc } from './sveltedfire/utilities/kindlyFetchDoc.js';
9
9
  export { kindlyFetchDocs } from './sveltedfire/utilities/kindlyFetchDocs.js';
10
+ export { type AuthSig } from './sveltedfire/auth/AuthSig.js';
11
+ export { getAuthContext } from './sveltedfire/auth/getAuthContext.js';
10
12
  import SignedIn from './sveltedfire/components/SignedIn.svelte';
11
13
  import SignedOut from './sveltedfire/components/SignedOut.svelte';
12
- export { SignedIn, SignedOut };
14
+ import SveltedAuth from "./sveltedfire/components/SveltedAuth.svelte";
15
+ import FireForm from "./sveltedfire/components/FireForm.svelte";
16
+ export { SignedIn, SignedOut, SveltedAuth, FireForm };
package/dist/index.js CHANGED
@@ -8,6 +8,10 @@ export { listenDoc } from './sveltedfire/utilities/listenDoc.js';
8
8
  export { listenDocs } from './sveltedfire/utilities/listenDocs.js';
9
9
  export { kindlyFetchDoc } from './sveltedfire/utilities/kindlyFetchDoc.js';
10
10
  export { kindlyFetchDocs } from './sveltedfire/utilities/kindlyFetchDocs.js';
11
+ export {} from './sveltedfire/auth/AuthSig.js';
12
+ export { getAuthContext } from './sveltedfire/auth/getAuthContext.js';
11
13
  import SignedIn from './sveltedfire/components/SignedIn.svelte';
12
14
  import SignedOut from './sveltedfire/components/SignedOut.svelte';
13
- export { SignedIn, SignedOut };
15
+ import SveltedAuth from "./sveltedfire/components/SveltedAuth.svelte";
16
+ import FireForm from "./sveltedfire/components/FireForm.svelte";
17
+ export { SignedIn, SignedOut, SveltedAuth, FireForm };
@@ -0,0 +1,7 @@
1
+ import { type User } from "firebase/auth";
2
+ export type AuthSig = {
3
+ currentUser: User | null;
4
+ signInWithGoogle: any;
5
+ signOut: any;
6
+ [k: string]: any;
7
+ };
@@ -0,0 +1 @@
1
+ import {} from "firebase/auth";
@@ -0,0 +1 @@
1
+ export declare const getAuthContext: () => unknown;
@@ -0,0 +1,3 @@
1
+ import { getContext } from "svelte";
2
+ import { AUTH_CONTEXT_NAME } from '../constants.js';
3
+ export const getAuthContext = () => getContext(AUTH_CONTEXT_NAME);
@@ -0,0 +1,54 @@
1
+ <script lang="ts">
2
+ import { getFirestore, collection, doc, getDoc, updateDoc, setDoc, addDoc, deleteField } from "firebase/firestore"
3
+
4
+ let { collectionName, docId = null, docIdField = null, onSubmit, children, beforeSubmit = null, ...rest } = $props()
5
+ const db = getFirestore()
6
+
7
+ const submitTheForm = async (ev: SubmitEvent) => {
8
+ console.log('Attempting to save')
9
+ ev.preventDefault()
10
+ const formData = new FormData(ev.target as HTMLFormElement)
11
+ let col = collection(db, collectionName)
12
+ let objData = Object.fromEntries(formData.entries())
13
+ if (beforeSubmit) {
14
+ objData = beforeSubmit(objData, ev)
15
+ }
16
+ Object.keys(objData).forEach(k => {
17
+ if (objData[k] === '_deleteme_') {
18
+ if (!k.match(/\[/)) {
19
+ objData[k] = deleteField()
20
+ }
21
+ }
22
+ let matcher = k.match(/^(.*)\[(.*)\]$/)
23
+ if (matcher) {
24
+ if (!(matcher[1] in objData)) {
25
+ objData[matcher[1]] = []
26
+ }
27
+ if (objData[k] === '_deleteme_') {
28
+ console.log('Deletion override')
29
+ objData[matcher[1]] = deleteField()
30
+ } else {
31
+ objData[matcher[1]][parseInt(matcher[2], 10)] = objData[k]
32
+ }
33
+ delete objData[k]
34
+ }
35
+ })
36
+ console.log('Object data is', objData)
37
+ let docRefId
38
+ if (docId) {
39
+ await updateDoc(doc(col, docId), objData)
40
+ docRefId = docId
41
+ } else if (docIdField) {
42
+ await updateDoc(doc(col, formData.get(docIdField) as string), objData)
43
+ docRefId = formData.get(docIdField) as string
44
+ } else {
45
+ let docRef = await addDoc(col, objData)
46
+ docRefId = docRef.id
47
+ }
48
+ onSubmit(docRefId)
49
+ }
50
+ </script>
51
+
52
+ <form onsubmit={submitTheForm} {...rest}>
53
+ {@render children()}
54
+ </form>
@@ -0,0 +1,10 @@
1
+ declare const FireForm: import("svelte").Component<{
2
+ collectionName: any;
3
+ docId?: any;
4
+ docIdField?: any;
5
+ onSubmit: any;
6
+ children: any;
7
+ beforeSubmit?: any;
8
+ } & Record<string, any>, {}, "">;
9
+ type FireForm = ReturnType<typeof FireForm>;
10
+ export default FireForm;
@@ -1,14 +1,11 @@
1
1
  <script lang="ts">
2
2
  const { children } = $props()
3
- import { getAuth } from 'firebase/auth'
3
+ import { getContext } from 'svelte';
4
+ import { AuthSig } from '../auth/AuthSig.js';
4
5
 
5
- const auth = getAuth()
6
- let user = $state(null)
7
- auth.onAuthStateChanged(u => {
8
- user = u
9
- })
6
+ let fullAuth = getContext<AuthSig>('sveltedAuth')
10
7
  </script>
11
8
 
12
- {#if user}
9
+ {#if fullAuth!.currentUser}
13
10
  {@render children()}
14
11
  {/if}
@@ -1,14 +1,11 @@
1
1
  <script lang="ts">
2
2
  const { children } = $props()
3
- import { getAuth } from 'firebase/auth'
3
+ import { getContext } from 'svelte';
4
+ import { type AuthSig } from '../auth/AuthSig.js';
4
5
 
5
- const auth = getAuth()
6
- let user = $state(null)
7
- auth.onAuthStateChanged(u => {
8
- user = u
9
- })
6
+ let fullAuth = getContext<AuthSig>('sveltedAuth')
10
7
  </script>
11
8
 
12
- {#if !user}
9
+ {#if fullAuth && !fullAuth!.currentUser}
13
10
  {@render children()}
14
11
  {/if}
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import { setContext } from 'svelte'
3
+ import { getAuth, type User } from 'firebase/auth'
4
+ import { signOut } from '../auth/signOut.js'
5
+ import { signInWithGoogle } from '../auth/signInWithGoogle.js'
6
+ import { type AuthSig } from '../auth/AuthSig.js';
7
+ import { AUTH_CONTEXT_NAME } from '../constants.js'
8
+
9
+ const { children, ...rest } = $props()
10
+
11
+ let additionalKeys: {[k: string]: any} = {}
12
+ Object.keys(rest).forEach(k => {
13
+ if (k.startsWith('extra_')) {
14
+ const actualKey = k.replace('^extra_', '')
15
+ additionalKeys[actualKey] = k
16
+ }
17
+ })
18
+
19
+ const auth = getAuth()
20
+
21
+ let fullAuth = $state<AuthSig>({
22
+ currentUser: null,
23
+ signOut,
24
+ signInWithGoogle
25
+ })
26
+
27
+ auth.onAuthStateChanged(user => {
28
+ fullAuth.currentUser = user
29
+ Object.keys(additionalKeys).forEach((k: string) => {
30
+ fullAuth[k] = rest[additionalKeys[k]](null, null)
31
+ })
32
+ user?.getIdTokenResult().then(token => {
33
+ Object.keys(additionalKeys).forEach((k: string) => {
34
+ fullAuth[k] = rest[additionalKeys[k]](user, token)
35
+ })
36
+ })
37
+ })
38
+
39
+ setContext<AuthSig>(AUTH_CONTEXT_NAME, fullAuth)
40
+
41
+ </script>
42
+
43
+ {@render children()}
@@ -0,0 +1,5 @@
1
+ declare const SveltedAuth: import("svelte").Component<{
2
+ children: any;
3
+ } & Record<string, any>, {}, "">;
4
+ type SveltedAuth = ReturnType<typeof SveltedAuth>;
5
+ export default SveltedAuth;
@@ -0,0 +1 @@
1
+ export declare const AUTH_CONTEXT_NAME = "sveltedAuth";
@@ -0,0 +1 @@
1
+ export const AUTH_CONTEXT_NAME = 'sveltedAuth';
@@ -1,8 +1,11 @@
1
- import { QueryCompositeFilterConstraint } from "firebase/firestore";
2
- export declare const fetchDocs: (...collectionPath: Array<string>) => (qOrField?: QueryCompositeFilterConstraint | string | null, comparator?: string | null, value?: string | boolean | number | null) => Promise<{
1
+ import { QueryFieldFilterConstraint, QueryCompositeFilterConstraint, type QueryNonFilterConstraint, type WhereFilterOp } from "firebase/firestore";
2
+ type QueryFieldsType = QueryCompositeFilterConstraint | QueryFieldFilterConstraint | QueryNonFilterConstraint;
3
+ type TheFieldsType = string | QueryFieldsType | WhereFilterOp | number | boolean;
4
+ export declare const fetchDocs: (...collectionPath: Array<string>) => (...fields: TheFieldsType[]) => Promise<{
3
5
  docs: {
4
6
  _id: string;
5
7
  id: string;
6
8
  }[];
7
9
  count: number;
8
10
  }>;
11
+ export {};
@@ -1,5 +1,5 @@
1
- import { getFirestore, collection, doc, getDocs, Query, QueryFieldFilterConstraint, where, query, QueryCompositeFilterConstraint } from "firebase/firestore";
2
- export const fetchDocs = (...collectionPath) => async (qOrField = null, comparator = null, value = null) => {
1
+ import { getFirestore, collection, getDocs, QueryFieldFilterConstraint, where, query, QueryCompositeFilterConstraint, QueryConstraint, QueryOrderByConstraint, QueryLimitConstraint, QueryStartAtConstraint, QueryEndAtConstraint } from "firebase/firestore";
2
+ export const fetchDocs = (...collectionPath) => async (...fields) => {
3
3
  const db = getFirestore();
4
4
  let theRef;
5
5
  if (collectionPath.length > 1) {
@@ -9,16 +9,38 @@ export const fetchDocs = (...collectionPath) => async (qOrField = null, comparat
9
9
  theRef = collection(db, collectionPath[0]);
10
10
  }
11
11
  let theQuery = query(theRef);
12
- if (qOrField) {
13
- if (comparator) {
14
- theQuery = query(theRef, where(qOrField, comparator, value));
12
+ if (fields.length > 0) {
13
+ if ((fields.length === 3) && (typeof fields[1] === "string")) {
14
+ theQuery = query(theRef, where(fields[0], fields[1], fields[2]));
15
15
  }
16
16
  else {
17
- if (qOrField instanceof QueryFieldFilterConstraint) {
18
- theQuery = query(theRef, qOrField);
17
+ const builtFields = [];
18
+ let compositeConstraint = null;
19
+ fields.forEach(k => {
20
+ if (k instanceof QueryCompositeFilterConstraint) {
21
+ compositeConstraint = k;
22
+ }
23
+ else if (k instanceof QueryFieldFilterConstraint) {
24
+ builtFields.push(k);
25
+ }
26
+ else if (k instanceof QueryOrderByConstraint) {
27
+ builtFields.push(k);
28
+ }
29
+ else if (k instanceof QueryLimitConstraint) {
30
+ builtFields.push(k);
31
+ }
32
+ else if (k instanceof QueryStartAtConstraint) {
33
+ builtFields.push(k);
34
+ }
35
+ else if (k instanceof QueryEndAtConstraint) {
36
+ builtFields.push(k);
37
+ }
38
+ });
39
+ if (compositeConstraint) {
40
+ theQuery = query(theRef, compositeConstraint, ...builtFields);
19
41
  }
20
- else if (qOrField instanceof QueryCompositeFilterConstraint) {
21
- theQuery = query(theRef, qOrField);
42
+ else {
43
+ theQuery = query(theRef, ...builtFields);
22
44
  }
23
45
  }
24
46
  }
@@ -1,6 +1,9 @@
1
- import { QueryCompositeFilterConstraint } from "firebase/firestore";
1
+ import { QueryFieldFilterConstraint, QueryCompositeFilterConstraint, type WhereFilterOp, type QueryNonFilterConstraint } from "firebase/firestore";
2
2
  import { type DocumentData } from "firebase/firestore";
3
- export declare const listenDocs: (...collectionPath: Array<string>) => (qOrField?: QueryCompositeFilterConstraint | string | null, comparator?: string | null, value?: string | boolean | number | null) => Promise<import("svelte/store").Readable<{
3
+ type QueryFieldsType = QueryCompositeFilterConstraint | QueryFieldFilterConstraint | QueryNonFilterConstraint;
4
+ type TheFieldsType = string | QueryFieldsType | WhereFilterOp | number | boolean;
5
+ export declare const listenDocs: (...collectionPath: Array<string>) => (...fields: TheFieldsType[]) => import("svelte/store").Readable<{
4
6
  docs: DocumentData[];
5
7
  count: number;
6
- } | null>>;
8
+ } | null>;
9
+ export {};
@@ -1,7 +1,7 @@
1
- import { getFirestore, collection, doc, getDocs, Query, QueryFieldFilterConstraint, where, query, QueryCompositeFilterConstraint } from "firebase/firestore";
1
+ import { getFirestore, collection, doc, getDocs, Query, QueryFieldFilterConstraint, where, query, QueryCompositeFilterConstraint, QueryConstraint, QueryOrderByConstraint, QueryLimitConstraint, QueryStartAtConstraint, QueryEndAtConstraint } from "firebase/firestore";
2
2
  import { onSnapshot } from "firebase/firestore";
3
3
  import { readable } from 'svelte/store';
4
- export const listenDocs = (...collectionPath) => async (qOrField = null, comparator = null, value = null) => {
4
+ export const listenDocs = (...collectionPath) => (...fields) => {
5
5
  const db = getFirestore();
6
6
  let theRef;
7
7
  if (collectionPath.length > 1) {
@@ -11,16 +11,38 @@ export const listenDocs = (...collectionPath) => async (qOrField = null, compara
11
11
  theRef = collection(db, collectionPath[0]);
12
12
  }
13
13
  let theQuery = query(theRef);
14
- if (qOrField) {
15
- if (comparator) {
16
- theQuery = query(theRef, where(qOrField, comparator, value));
14
+ if (fields.length > 0) {
15
+ if ((fields.length === 3) && (typeof fields[1] === "string")) {
16
+ theQuery = query(theRef, where(fields[0], fields[1], fields[2]));
17
17
  }
18
18
  else {
19
- if (qOrField instanceof QueryFieldFilterConstraint) {
20
- theQuery = query(theRef, qOrField);
19
+ const builtFields = [];
20
+ let compositeConstraint = null;
21
+ fields.forEach(k => {
22
+ if (k instanceof QueryCompositeFilterConstraint) {
23
+ compositeConstraint = k;
24
+ }
25
+ else if (k instanceof QueryFieldFilterConstraint) {
26
+ builtFields.push(k);
27
+ }
28
+ else if (k instanceof QueryOrderByConstraint) {
29
+ builtFields.push(k);
30
+ }
31
+ else if (k instanceof QueryLimitConstraint) {
32
+ builtFields.push(k);
33
+ }
34
+ else if (k instanceof QueryStartAtConstraint) {
35
+ builtFields.push(k);
36
+ }
37
+ else if (k instanceof QueryEndAtConstraint) {
38
+ builtFields.push(k);
39
+ }
40
+ });
41
+ if (compositeConstraint) {
42
+ theQuery = query(theRef, compositeConstraint, ...builtFields);
21
43
  }
22
- else if (qOrField instanceof QueryCompositeFilterConstraint) {
23
- theQuery = query(theRef, qOrField);
44
+ else {
45
+ theQuery = query(theRef, ...builtFields);
24
46
  }
25
47
  }
26
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sveltedfire",
3
- "version": "0.0.8",
3
+ "version": "0.1.3",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",