@reause/firebase 0.1.2
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/LICENSE +21 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.iife.js +267 -0
- package/dist/index.iife.min.js +1 -0
- package/dist/index.js +4 -0
- package/dist/useAuth.d.ts +87 -0
- package/dist/useAuth.iife.js +97 -0
- package/dist/useAuth.iife.min.js +1 -0
- package/dist/useAuth.js +95 -0
- package/dist/useFirestore.d.ts +25 -0
- package/dist/useFirestore.iife.js +120 -0
- package/dist/useFirestore.iife.min.js +1 -0
- package/dist/useFirestore.js +119 -0
- package/dist/useRTDB.d.ts +59 -0
- package/dist/useRTDB.iife.js +56 -0
- package/dist/useRTDB.iife.min.js +1 -0
- package/dist/useRTDB.js +55 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hairyf
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { UseAuthOptions, UseAuthReturn, useAuth } from "./useAuth.js";
|
|
2
|
+
import { FirebaseDocRef, UseFirestoreOptions, useFirestore } from "./useFirestore.js";
|
|
3
|
+
import { UseRTDBOptions, UseRTDBReturn, useRTDB } from "./useRTDB.js";
|
|
4
|
+
export { FirebaseDocRef, UseAuthOptions, UseAuthReturn, UseFirestoreOptions, UseRTDBOptions, UseRTDBReturn, useAuth, useFirestore, useRTDB };
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
(function(exports, react, _reause_shared, firebase_database) {
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region useAuth/index.tsx
|
|
4
|
+
/**
|
|
5
|
+
* React port of VueUse's `useAuth`.
|
|
6
|
+
*
|
|
7
|
+
* Map from @vueuse/firebase/useAuth
|
|
8
|
+
* (`source/vueuse/packages/firebase/useAuth/`). Reactive
|
|
9
|
+
* [Firebase Auth](https://firebase.google.com/docs/auth) binding — it exposes
|
|
10
|
+
* the current `user` and an `isAuthenticated` flag, so a component can react to
|
|
11
|
+
* sign-in, sign-out and ID-token refresh events.
|
|
12
|
+
*
|
|
13
|
+
* Adjustment for React:
|
|
14
|
+
* - the `Auth` instance stays the first argument (`useAuth(auth)`), but the
|
|
15
|
+
* return is a plain object `{ isAuthenticated, user, loading, error }` — the
|
|
16
|
+
* values are read during render instead of being Vue refs (`ComputedRef`
|
|
17
|
+
* / `Ref`), and the object is returned rather than a destructured tuple;
|
|
18
|
+
* - `loading` and `error` are additions to upstream. Firebase reports the
|
|
19
|
+
* current auth state **asynchronously**, so a port without `loading` would
|
|
20
|
+
* render the signed-out UI for one frame before the listener corrects it;
|
|
21
|
+
* `loading` starts `true` and flips to `false` with the first callback (a
|
|
22
|
+
* signed-out callback included). `error` stays `null` unless subscribing
|
|
23
|
+
* itself throws;
|
|
24
|
+
* - `user` is seeded from `auth.currentUser` (upstream's
|
|
25
|
+
* `ref(auth.currentUser)`), so an already signed-in visitor renders
|
|
26
|
+
* authenticated on the very first pass, while `loading` is still `true`;
|
|
27
|
+
* - upstream subscribes in `setup()` and **never** unsubscribes; this port
|
|
28
|
+
* subscribes in an effect keyed on `auth` and returns the listener's
|
|
29
|
+
* `Unsubscribe` as cleanup, so a new `Auth` instance re-subscribes (and
|
|
30
|
+
* re-seeds `user`/`loading`/`error`) and unmounting stops the listener — a
|
|
31
|
+
* deliberate React-idiomatic deviation that fixes upstream's leak;
|
|
32
|
+
* - errors on sign-in/sign-out are **not** routed here: the `error` and
|
|
33
|
+
* `completed` callbacks of `onIdTokenChanged` are deprecated in Firebase and
|
|
34
|
+
* documented as never firing. Catch those on the promise returned by
|
|
35
|
+
* `signInWithPopup` / `signOut` itself; `error` only reports a subscription
|
|
36
|
+
* that could not be established;
|
|
37
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
38
|
+
* does not re-subscribe;
|
|
39
|
+
* - nothing runs while rendering, so server rendering is safe.
|
|
40
|
+
*
|
|
41
|
+
* @see https://vueuse.org/firebase/useAuth/
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const auth = getAuth(app)
|
|
45
|
+
* const { isAuthenticated, user, loading, error } = useAuth(auth)
|
|
46
|
+
* if (loading) return <div>Loading...</div>
|
|
47
|
+
* if (!isAuthenticated) return <div>Please log in</div>
|
|
48
|
+
* return <div>Welcome, {user.displayName}</div>
|
|
49
|
+
*
|
|
50
|
+
* @__NO_SIDE_EFFECTS__
|
|
51
|
+
*/
|
|
52
|
+
function useAuth(auth, options = {}) {
|
|
53
|
+
const { errorHandler = (err) => console.error(err) } = options;
|
|
54
|
+
const [user, setUser] = (0, react.useState)(() => auth.currentUser);
|
|
55
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
56
|
+
const [error, setError] = (0, react.useState)(null);
|
|
57
|
+
const errorHandlerRef = (0, react.useRef)(errorHandler);
|
|
58
|
+
(0, react.useEffect)(() => {
|
|
59
|
+
errorHandlerRef.current = errorHandler;
|
|
60
|
+
}, [errorHandler]);
|
|
61
|
+
const subscribedAuthRef = (0, react.useRef)(auth);
|
|
62
|
+
(0, react.useEffect)(() => {
|
|
63
|
+
if (subscribedAuthRef.current !== auth) {
|
|
64
|
+
subscribedAuthRef.current = auth;
|
|
65
|
+
setUser(auth.currentUser);
|
|
66
|
+
setLoading(true);
|
|
67
|
+
setError(null);
|
|
68
|
+
}
|
|
69
|
+
let unsubscribe;
|
|
70
|
+
let active = true;
|
|
71
|
+
try {
|
|
72
|
+
unsubscribe = auth.onIdTokenChanged((authUser) => {
|
|
73
|
+
if (!active) return;
|
|
74
|
+
setUser(authUser);
|
|
75
|
+
setLoading(false);
|
|
76
|
+
});
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const subscriptionError = err instanceof Error ? err : new Error(String(err));
|
|
79
|
+
setError(subscriptionError);
|
|
80
|
+
setLoading(false);
|
|
81
|
+
errorHandlerRef.current(subscriptionError);
|
|
82
|
+
}
|
|
83
|
+
return () => {
|
|
84
|
+
active = false;
|
|
85
|
+
unsubscribe === null || unsubscribe === void 0 || unsubscribe();
|
|
86
|
+
};
|
|
87
|
+
}, [auth]);
|
|
88
|
+
return {
|
|
89
|
+
isAuthenticated: user !== null,
|
|
90
|
+
user,
|
|
91
|
+
loading,
|
|
92
|
+
error
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region useFirestore/index.tsx
|
|
97
|
+
/**
|
|
98
|
+
* Attach the document `id` as a non-writable property of the snapshot data —
|
|
99
|
+
* ported verbatim from upstream. `data()` may be `undefined` for a deleted
|
|
100
|
+
* document.
|
|
101
|
+
*/
|
|
102
|
+
function getData(docRef) {
|
|
103
|
+
const data = docRef.data();
|
|
104
|
+
if (data) Object.defineProperty(data, "id", {
|
|
105
|
+
value: docRef.id.toString(),
|
|
106
|
+
writable: false
|
|
107
|
+
});
|
|
108
|
+
return data;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Slash-parity check, ported verbatim from upstream: a `DocumentReference`
|
|
112
|
+
* path has an odd number of segments (`users/ada`), a `Query` path an even
|
|
113
|
+
* number (`users` or `users/ada/posts`).
|
|
114
|
+
*/
|
|
115
|
+
function isDocumentReference(docRef) {
|
|
116
|
+
var _docRef$path;
|
|
117
|
+
return (((_docRef$path = docRef.path) === null || _docRef$path === void 0 ? void 0 : _docRef$path.match(/\//g)) || []).length % 2 !== 0;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* React port of VueUse's `useFirestore`.
|
|
121
|
+
*
|
|
122
|
+
* Map from @vueuse/firebase/useFirestore
|
|
123
|
+
* (`source/vueuse/packages/firebase/useFirestore/`). Reactive
|
|
124
|
+
* [Firestore](https://firebase.google.com/docs/firestore) binding — it keeps
|
|
125
|
+
* local state in sync with a document reference or a query, so a component
|
|
126
|
+
* always renders the freshest remote data.
|
|
127
|
+
*
|
|
128
|
+
* Adjustment for React:
|
|
129
|
+
* - `maybeDocRef` is a plain value (upstream accepts `MaybeRef`): read-only
|
|
130
|
+
* value-source parameters take plain `T`. Pass a new reference/query
|
|
131
|
+
* identity to re-subscribe — **keep it stable across renders** (memoize
|
|
132
|
+
* `doc`/`collection`/`query` results): a fresh identity on every render
|
|
133
|
+
* re-subscribes on every render;
|
|
134
|
+
* - the return is the plain state VALUE (not a tuple, not an object) —
|
|
135
|
+
* upstream exposes no setter (0 writable values), so the shape mirrors the
|
|
136
|
+
* read side of upstream's `Ref<T | null>` / `Ref<T[]>`; a document resolves
|
|
137
|
+
* to `T | null` (a deleted document becomes `null`), a query to `T[]`;
|
|
138
|
+
* - the subscription lives in an effect keyed on `maybeDocRef`, so a new
|
|
139
|
+
* ref/query identity re-subscribes and closes the previous `onSnapshot`
|
|
140
|
+
* (upstream's immediate watch); a falsy docRef resets `data` to
|
|
141
|
+
* `initialValue`;
|
|
142
|
+
* - `firebase/firestore` is loaded through a guarded **dynamic** import, so
|
|
143
|
+
* this module never throws at import time when `firebase` is missing — a
|
|
144
|
+
* missing module or a failed `onSnapshot` call surfaces through
|
|
145
|
+
* `errorHandler` instead, and `data` stays at `initialValue`;
|
|
146
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
147
|
+
* does not re-subscribe;
|
|
148
|
+
* - nothing runs while rendering, so server rendering is safe.
|
|
149
|
+
*
|
|
150
|
+
* @see https://vueuse.org/firebase/useFirestore/
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* const todos = useFirestore(collection(db, 'todos'))
|
|
154
|
+
* const user = useFirestore(doc(db, 'users', 'my-user-id'))
|
|
155
|
+
*
|
|
156
|
+
* @__NO_SIDE_EFFECTS__
|
|
157
|
+
*/
|
|
158
|
+
function useFirestore(maybeDocRef, initialValue = void 0, options = {}) {
|
|
159
|
+
const { errorHandler = (err) => console.error(err), autoDispose = true } = options;
|
|
160
|
+
const [data, setData] = (0, react.useState)(initialValue);
|
|
161
|
+
const initialValueRef = (0, react.useRef)(initialValue);
|
|
162
|
+
const autoDisposeRef = (0, react.useRef)(autoDispose);
|
|
163
|
+
const errorHandlerRef = (0, react.useRef)(errorHandler);
|
|
164
|
+
(0, react.useEffect)(() => {
|
|
165
|
+
errorHandlerRef.current = errorHandler;
|
|
166
|
+
}, [errorHandler]);
|
|
167
|
+
const closeRef = (0, react.useRef)(() => {});
|
|
168
|
+
(0, react.useEffect)(() => {
|
|
169
|
+
closeRef.current();
|
|
170
|
+
closeRef.current = () => {};
|
|
171
|
+
if (!maybeDocRef) {
|
|
172
|
+
setData(initialValueRef.current);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
let active = true;
|
|
176
|
+
let close;
|
|
177
|
+
import("firebase/firestore").then(({ onSnapshot }) => {
|
|
178
|
+
if (!active) return;
|
|
179
|
+
try {
|
|
180
|
+
var _close;
|
|
181
|
+
if (isDocumentReference(maybeDocRef)) close = onSnapshot(maybeDocRef, (snapshot) => {
|
|
182
|
+
if (!active) return;
|
|
183
|
+
setData(getData(snapshot) || null);
|
|
184
|
+
}, (err) => errorHandlerRef.current(err));
|
|
185
|
+
else close = onSnapshot(maybeDocRef, (snapshot) => {
|
|
186
|
+
if (!active) return;
|
|
187
|
+
setData(snapshot.docs.map(getData).filter(_reause_shared.isDef));
|
|
188
|
+
}, (err) => errorHandlerRef.current(err));
|
|
189
|
+
closeRef.current = (_close = close) !== null && _close !== void 0 ? _close : (() => {});
|
|
190
|
+
} catch (err) {
|
|
191
|
+
errorHandlerRef.current(err instanceof Error ? err : new Error(String(err)));
|
|
192
|
+
}
|
|
193
|
+
}).catch((err) => {
|
|
194
|
+
if (!active) return;
|
|
195
|
+
errorHandlerRef.current(err instanceof Error ? err : new Error(String(err)));
|
|
196
|
+
});
|
|
197
|
+
return () => {
|
|
198
|
+
active = false;
|
|
199
|
+
};
|
|
200
|
+
}, [maybeDocRef]);
|
|
201
|
+
(0, react.useEffect)(() => {
|
|
202
|
+
return () => {
|
|
203
|
+
if (autoDisposeRef.current === true) closeRef.current();
|
|
204
|
+
else if (typeof autoDisposeRef.current === "number") setTimeout(() => {
|
|
205
|
+
closeRef.current();
|
|
206
|
+
}, autoDisposeRef.current);
|
|
207
|
+
};
|
|
208
|
+
}, []);
|
|
209
|
+
return data;
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region useRTDB/index.tsx
|
|
213
|
+
/**
|
|
214
|
+
* React port of VueUse's `useRTDB`.
|
|
215
|
+
*
|
|
216
|
+
* Map from @vueuse/firebase `useRTDB`
|
|
217
|
+
*
|
|
218
|
+
* Reactive [Firebase Realtime Database](https://firebase.google.com/docs/database)
|
|
219
|
+
* binding — keeps local state in sync with a database reference. The listener
|
|
220
|
+
* is registered with `onValue` in a mount effect and feeds `data` with
|
|
221
|
+
* `snapshot.val()` on every database change.
|
|
222
|
+
*
|
|
223
|
+
* Adjustment for React:
|
|
224
|
+
* - upstream returns a writable `Ref<T | undefined>`, so this port returns the
|
|
225
|
+
* `[data, setData]` tuple; `data` starts `undefined` and holds the latest
|
|
226
|
+
* snapshot value;
|
|
227
|
+
* - `setData` writes **local state only** — it does not write to the Realtime
|
|
228
|
+
* Database (upstream's ref is equally local). Use the `firebase/database`
|
|
229
|
+
* write APIs (`set` / `update` / `push`) to persist;
|
|
230
|
+
* - the subscription lives in a `useEffect` keyed on `docRef` and `autoDispose`,
|
|
231
|
+
* so a new `docRef` identity re-subscribes and unsubscribes the previous
|
|
232
|
+
* listener (upstream subscribes once per `setup()` — a deliberate
|
|
233
|
+
* React-idiomatic deviation);
|
|
234
|
+
* - cleanup calls the `onValue` unsubscribe only when `autoDispose` is `true`
|
|
235
|
+
* (upstream parity). `autoDispose: false` means the subscription outlives the
|
|
236
|
+
* component: the caller gets no `off` handle and must live with the leak —
|
|
237
|
+
* discouraged, kept only for upstream parity;
|
|
238
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
239
|
+
* does not re-subscribe.
|
|
240
|
+
*
|
|
241
|
+
* @see https://vueuse.org/useRTDB
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* const [todos, setTodos] = useRTDB<Record<string, Todo>>(ref(getDatabase(app), 'todos'))
|
|
245
|
+
*
|
|
246
|
+
* @__NO_SIDE_EFFECTS__
|
|
247
|
+
*/
|
|
248
|
+
function useRTDB(docRef, options = {}) {
|
|
249
|
+
const { errorHandler = (err) => console.error(err), autoDispose = true } = options;
|
|
250
|
+
const [data, setData] = (0, react.useState)(void 0);
|
|
251
|
+
const errorHandlerRef = (0, react.useRef)(errorHandler);
|
|
252
|
+
(0, react.useEffect)(() => {
|
|
253
|
+
errorHandlerRef.current = errorHandler;
|
|
254
|
+
}, [errorHandler]);
|
|
255
|
+
(0, react.useEffect)(() => {
|
|
256
|
+
const off = (0, firebase_database.onValue)(docRef, (snapshot) => setData(snapshot.val()), (err) => errorHandlerRef.current(err));
|
|
257
|
+
return () => {
|
|
258
|
+
if (autoDispose) off();
|
|
259
|
+
};
|
|
260
|
+
}, [docRef, autoDispose]);
|
|
261
|
+
return [data, setData];
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
264
|
+
exports.useAuth = useAuth;
|
|
265
|
+
exports.useFirestore = useFirestore;
|
|
266
|
+
exports.useRTDB = useRTDB;
|
|
267
|
+
})(this.reause = this.reause || {}, React, reause, firebase);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function i(e,n={}){let{errorHandler:r=e=>console.error(e)}=n,[i,a]=(0,t.useState)(()=>e.currentUser),[o,s]=(0,t.useState)(!0),[c,l]=(0,t.useState)(null),u=(0,t.useRef)(r);(0,t.useEffect)(()=>{u.current=r},[r]);let d=(0,t.useRef)(e);return(0,t.useEffect)(()=>{d.current!==e&&(d.current=e,a(e.currentUser),s(!0),l(null));let t,n=!0;try{t=e.onIdTokenChanged(e=>{n&&(a(e),s(!1))})}catch(e){let t=e instanceof Error?e:Error(String(e));l(t),s(!1),u.current(t)}return()=>{n=!1,t==null||t()}},[e]),{isAuthenticated:i!==null,user:i,loading:o,error:c}}function a(e){let t=e.data();return t&&Object.defineProperty(t,"id",{value:e.id.toString(),writable:!1}),t}function o(e){var t;return(((t=e.path)==null?void 0:t.match(/\//g))||[]).length%2!=0}function s(e,r=void 0,i={}){let{errorHandler:s=e=>console.error(e),autoDispose:c=!0}=i,[l,u]=(0,t.useState)(r),d=(0,t.useRef)(r),f=(0,t.useRef)(c),p=(0,t.useRef)(s);(0,t.useEffect)(()=>{p.current=s},[s]);let m=(0,t.useRef)(()=>{});return(0,t.useEffect)(()=>{if(m.current(),m.current=()=>{},!e){u(d.current);return}let t=!0,r;return import(`firebase/firestore`).then(({onSnapshot:i})=>{if(t)try{var s;r=o(e)?i(e,e=>{t&&u(a(e)||null)},e=>p.current(e)):i(e,e=>{t&&u(e.docs.map(a).filter(n.isDef))},e=>p.current(e)),m.current=(s=r)==null?(()=>{}):s}catch(e){p.current(e instanceof Error?e:Error(String(e)))}}).catch(e=>{t&&p.current(e instanceof Error?e:Error(String(e)))}),()=>{t=!1}},[e]),(0,t.useEffect)(()=>()=>{f.current===!0?m.current():typeof f.current==`number`&&setTimeout(()=>{m.current()},f.current)},[]),l}function c(e,n={}){let{errorHandler:i=e=>console.error(e),autoDispose:a=!0}=n,[o,s]=(0,t.useState)(void 0),c=(0,t.useRef)(i);return(0,t.useEffect)(()=>{c.current=i},[i]),(0,t.useEffect)(()=>{let t=(0,r.onValue)(e,e=>s(e.val()),e=>c.current(e));return()=>{a&&t()}},[e,a]),[o,s]}e.useAuth=i,e.useFirestore=s,e.useRTDB=c})(this.reause=this.reause||{},React,reause,firebase);
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Auth, User } from "firebase/auth";
|
|
2
|
+
//#region useAuth/index.d.ts
|
|
3
|
+
export interface UseAuthOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Custom error handler for auth subscription errors.
|
|
6
|
+
*
|
|
7
|
+
* @default (error) => console.error(error)
|
|
8
|
+
*/
|
|
9
|
+
errorHandler?: (err: Error) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Result object of `useAuth` — the plain-value counterpart of upstream's
|
|
13
|
+
* `{ isAuthenticated, user }` refs, plus the `loading` and `error` states.
|
|
14
|
+
*/
|
|
15
|
+
export interface UseAuthReturn {
|
|
16
|
+
/**
|
|
17
|
+
* Whether a user is currently authenticated (upstream's `isAuthenticated`
|
|
18
|
+
* computed): `true` whenever `user` is not `null`.
|
|
19
|
+
*/
|
|
20
|
+
isAuthenticated: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The current Firebase user, or `null` if not authenticated (upstream's
|
|
23
|
+
* `user` ref). Seeded from `auth.currentUser` and kept in sync by
|
|
24
|
+
* `onIdTokenChanged`.
|
|
25
|
+
*/
|
|
26
|
+
user: User | null;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the auth state is still being resolved: `true` on the first render
|
|
29
|
+
* and until `onIdTokenChanged` reports the current state (or the subscription
|
|
30
|
+
* fails), then `false` — including when the reported state is signed out.
|
|
31
|
+
*/
|
|
32
|
+
loading: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The error thrown while subscribing to `auth.onIdTokenChanged`, or `null`.
|
|
35
|
+
*/
|
|
36
|
+
error: Error | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* React port of VueUse's `useAuth`.
|
|
40
|
+
*
|
|
41
|
+
* Map from @vueuse/firebase/useAuth
|
|
42
|
+
* (`source/vueuse/packages/firebase/useAuth/`). Reactive
|
|
43
|
+
* [Firebase Auth](https://firebase.google.com/docs/auth) binding — it exposes
|
|
44
|
+
* the current `user` and an `isAuthenticated` flag, so a component can react to
|
|
45
|
+
* sign-in, sign-out and ID-token refresh events.
|
|
46
|
+
*
|
|
47
|
+
* Adjustment for React:
|
|
48
|
+
* - the `Auth` instance stays the first argument (`useAuth(auth)`), but the
|
|
49
|
+
* return is a plain object `{ isAuthenticated, user, loading, error }` — the
|
|
50
|
+
* values are read during render instead of being Vue refs (`ComputedRef`
|
|
51
|
+
* / `Ref`), and the object is returned rather than a destructured tuple;
|
|
52
|
+
* - `loading` and `error` are additions to upstream. Firebase reports the
|
|
53
|
+
* current auth state **asynchronously**, so a port without `loading` would
|
|
54
|
+
* render the signed-out UI for one frame before the listener corrects it;
|
|
55
|
+
* `loading` starts `true` and flips to `false` with the first callback (a
|
|
56
|
+
* signed-out callback included). `error` stays `null` unless subscribing
|
|
57
|
+
* itself throws;
|
|
58
|
+
* - `user` is seeded from `auth.currentUser` (upstream's
|
|
59
|
+
* `ref(auth.currentUser)`), so an already signed-in visitor renders
|
|
60
|
+
* authenticated on the very first pass, while `loading` is still `true`;
|
|
61
|
+
* - upstream subscribes in `setup()` and **never** unsubscribes; this port
|
|
62
|
+
* subscribes in an effect keyed on `auth` and returns the listener's
|
|
63
|
+
* `Unsubscribe` as cleanup, so a new `Auth` instance re-subscribes (and
|
|
64
|
+
* re-seeds `user`/`loading`/`error`) and unmounting stops the listener — a
|
|
65
|
+
* deliberate React-idiomatic deviation that fixes upstream's leak;
|
|
66
|
+
* - errors on sign-in/sign-out are **not** routed here: the `error` and
|
|
67
|
+
* `completed` callbacks of `onIdTokenChanged` are deprecated in Firebase and
|
|
68
|
+
* documented as never firing. Catch those on the promise returned by
|
|
69
|
+
* `signInWithPopup` / `signOut` itself; `error` only reports a subscription
|
|
70
|
+
* that could not be established;
|
|
71
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
72
|
+
* does not re-subscribe;
|
|
73
|
+
* - nothing runs while rendering, so server rendering is safe.
|
|
74
|
+
*
|
|
75
|
+
* @see https://vueuse.org/firebase/useAuth/
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const auth = getAuth(app)
|
|
79
|
+
* const { isAuthenticated, user, loading, error } = useAuth(auth)
|
|
80
|
+
* if (loading) return <div>Loading...</div>
|
|
81
|
+
* if (!isAuthenticated) return <div>Please log in</div>
|
|
82
|
+
* return <div>Welcome, {user.displayName}</div>
|
|
83
|
+
*
|
|
84
|
+
* @__NO_SIDE_EFFECTS__
|
|
85
|
+
*/
|
|
86
|
+
export declare function useAuth(auth: Auth, options?: UseAuthOptions): UseAuthReturn;
|
|
87
|
+
//#endregion
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
(function(exports, react) {
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region useAuth/index.tsx
|
|
4
|
+
/**
|
|
5
|
+
* React port of VueUse's `useAuth`.
|
|
6
|
+
*
|
|
7
|
+
* Map from @vueuse/firebase/useAuth
|
|
8
|
+
* (`source/vueuse/packages/firebase/useAuth/`). Reactive
|
|
9
|
+
* [Firebase Auth](https://firebase.google.com/docs/auth) binding — it exposes
|
|
10
|
+
* the current `user` and an `isAuthenticated` flag, so a component can react to
|
|
11
|
+
* sign-in, sign-out and ID-token refresh events.
|
|
12
|
+
*
|
|
13
|
+
* Adjustment for React:
|
|
14
|
+
* - the `Auth` instance stays the first argument (`useAuth(auth)`), but the
|
|
15
|
+
* return is a plain object `{ isAuthenticated, user, loading, error }` — the
|
|
16
|
+
* values are read during render instead of being Vue refs (`ComputedRef`
|
|
17
|
+
* / `Ref`), and the object is returned rather than a destructured tuple;
|
|
18
|
+
* - `loading` and `error` are additions to upstream. Firebase reports the
|
|
19
|
+
* current auth state **asynchronously**, so a port without `loading` would
|
|
20
|
+
* render the signed-out UI for one frame before the listener corrects it;
|
|
21
|
+
* `loading` starts `true` and flips to `false` with the first callback (a
|
|
22
|
+
* signed-out callback included). `error` stays `null` unless subscribing
|
|
23
|
+
* itself throws;
|
|
24
|
+
* - `user` is seeded from `auth.currentUser` (upstream's
|
|
25
|
+
* `ref(auth.currentUser)`), so an already signed-in visitor renders
|
|
26
|
+
* authenticated on the very first pass, while `loading` is still `true`;
|
|
27
|
+
* - upstream subscribes in `setup()` and **never** unsubscribes; this port
|
|
28
|
+
* subscribes in an effect keyed on `auth` and returns the listener's
|
|
29
|
+
* `Unsubscribe` as cleanup, so a new `Auth` instance re-subscribes (and
|
|
30
|
+
* re-seeds `user`/`loading`/`error`) and unmounting stops the listener — a
|
|
31
|
+
* deliberate React-idiomatic deviation that fixes upstream's leak;
|
|
32
|
+
* - errors on sign-in/sign-out are **not** routed here: the `error` and
|
|
33
|
+
* `completed` callbacks of `onIdTokenChanged` are deprecated in Firebase and
|
|
34
|
+
* documented as never firing. Catch those on the promise returned by
|
|
35
|
+
* `signInWithPopup` / `signOut` itself; `error` only reports a subscription
|
|
36
|
+
* that could not be established;
|
|
37
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
38
|
+
* does not re-subscribe;
|
|
39
|
+
* - nothing runs while rendering, so server rendering is safe.
|
|
40
|
+
*
|
|
41
|
+
* @see https://vueuse.org/firebase/useAuth/
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const auth = getAuth(app)
|
|
45
|
+
* const { isAuthenticated, user, loading, error } = useAuth(auth)
|
|
46
|
+
* if (loading) return <div>Loading...</div>
|
|
47
|
+
* if (!isAuthenticated) return <div>Please log in</div>
|
|
48
|
+
* return <div>Welcome, {user.displayName}</div>
|
|
49
|
+
*
|
|
50
|
+
* @__NO_SIDE_EFFECTS__
|
|
51
|
+
*/
|
|
52
|
+
function useAuth(auth, options = {}) {
|
|
53
|
+
const { errorHandler = (err) => console.error(err) } = options;
|
|
54
|
+
const [user, setUser] = (0, react.useState)(() => auth.currentUser);
|
|
55
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
56
|
+
const [error, setError] = (0, react.useState)(null);
|
|
57
|
+
const errorHandlerRef = (0, react.useRef)(errorHandler);
|
|
58
|
+
(0, react.useEffect)(() => {
|
|
59
|
+
errorHandlerRef.current = errorHandler;
|
|
60
|
+
}, [errorHandler]);
|
|
61
|
+
const subscribedAuthRef = (0, react.useRef)(auth);
|
|
62
|
+
(0, react.useEffect)(() => {
|
|
63
|
+
if (subscribedAuthRef.current !== auth) {
|
|
64
|
+
subscribedAuthRef.current = auth;
|
|
65
|
+
setUser(auth.currentUser);
|
|
66
|
+
setLoading(true);
|
|
67
|
+
setError(null);
|
|
68
|
+
}
|
|
69
|
+
let unsubscribe;
|
|
70
|
+
let active = true;
|
|
71
|
+
try {
|
|
72
|
+
unsubscribe = auth.onIdTokenChanged((authUser) => {
|
|
73
|
+
if (!active) return;
|
|
74
|
+
setUser(authUser);
|
|
75
|
+
setLoading(false);
|
|
76
|
+
});
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const subscriptionError = err instanceof Error ? err : new Error(String(err));
|
|
79
|
+
setError(subscriptionError);
|
|
80
|
+
setLoading(false);
|
|
81
|
+
errorHandlerRef.current(subscriptionError);
|
|
82
|
+
}
|
|
83
|
+
return () => {
|
|
84
|
+
active = false;
|
|
85
|
+
unsubscribe === null || unsubscribe === void 0 || unsubscribe();
|
|
86
|
+
};
|
|
87
|
+
}, [auth]);
|
|
88
|
+
return {
|
|
89
|
+
isAuthenticated: user !== null,
|
|
90
|
+
user,
|
|
91
|
+
loading,
|
|
92
|
+
error
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
exports.useAuth = useAuth;
|
|
97
|
+
})(this.reause = this.reause || {}, React);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function n(e,n={}){let{errorHandler:r=e=>console.error(e)}=n,[i,a]=(0,t.useState)(()=>e.currentUser),[o,s]=(0,t.useState)(!0),[c,l]=(0,t.useState)(null),u=(0,t.useRef)(r);(0,t.useEffect)(()=>{u.current=r},[r]);let d=(0,t.useRef)(e);return(0,t.useEffect)(()=>{d.current!==e&&(d.current=e,a(e.currentUser),s(!0),l(null));let t,n=!0;try{t=e.onIdTokenChanged(e=>{n&&(a(e),s(!1))})}catch(e){let t=e instanceof Error?e:Error(String(e));l(t),s(!1),u.current(t)}return()=>{n=!1,t==null||t()}},[e]),{isAuthenticated:i!==null,user:i,loading:o,error:c}}e.useAuth=n})(this.reause=this.reause||{},React);
|
package/dist/useAuth.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
//#region useAuth/index.tsx
|
|
3
|
+
/**
|
|
4
|
+
* React port of VueUse's `useAuth`.
|
|
5
|
+
*
|
|
6
|
+
* Map from @vueuse/firebase/useAuth
|
|
7
|
+
* (`source/vueuse/packages/firebase/useAuth/`). Reactive
|
|
8
|
+
* [Firebase Auth](https://firebase.google.com/docs/auth) binding — it exposes
|
|
9
|
+
* the current `user` and an `isAuthenticated` flag, so a component can react to
|
|
10
|
+
* sign-in, sign-out and ID-token refresh events.
|
|
11
|
+
*
|
|
12
|
+
* Adjustment for React:
|
|
13
|
+
* - the `Auth` instance stays the first argument (`useAuth(auth)`), but the
|
|
14
|
+
* return is a plain object `{ isAuthenticated, user, loading, error }` — the
|
|
15
|
+
* values are read during render instead of being Vue refs (`ComputedRef`
|
|
16
|
+
* / `Ref`), and the object is returned rather than a destructured tuple;
|
|
17
|
+
* - `loading` and `error` are additions to upstream. Firebase reports the
|
|
18
|
+
* current auth state **asynchronously**, so a port without `loading` would
|
|
19
|
+
* render the signed-out UI for one frame before the listener corrects it;
|
|
20
|
+
* `loading` starts `true` and flips to `false` with the first callback (a
|
|
21
|
+
* signed-out callback included). `error` stays `null` unless subscribing
|
|
22
|
+
* itself throws;
|
|
23
|
+
* - `user` is seeded from `auth.currentUser` (upstream's
|
|
24
|
+
* `ref(auth.currentUser)`), so an already signed-in visitor renders
|
|
25
|
+
* authenticated on the very first pass, while `loading` is still `true`;
|
|
26
|
+
* - upstream subscribes in `setup()` and **never** unsubscribes; this port
|
|
27
|
+
* subscribes in an effect keyed on `auth` and returns the listener's
|
|
28
|
+
* `Unsubscribe` as cleanup, so a new `Auth` instance re-subscribes (and
|
|
29
|
+
* re-seeds `user`/`loading`/`error`) and unmounting stops the listener — a
|
|
30
|
+
* deliberate React-idiomatic deviation that fixes upstream's leak;
|
|
31
|
+
* - errors on sign-in/sign-out are **not** routed here: the `error` and
|
|
32
|
+
* `completed` callbacks of `onIdTokenChanged` are deprecated in Firebase and
|
|
33
|
+
* documented as never firing. Catch those on the promise returned by
|
|
34
|
+
* `signInWithPopup` / `signOut` itself; `error` only reports a subscription
|
|
35
|
+
* that could not be established;
|
|
36
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
37
|
+
* does not re-subscribe;
|
|
38
|
+
* - nothing runs while rendering, so server rendering is safe.
|
|
39
|
+
*
|
|
40
|
+
* @see https://vueuse.org/firebase/useAuth/
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const auth = getAuth(app)
|
|
44
|
+
* const { isAuthenticated, user, loading, error } = useAuth(auth)
|
|
45
|
+
* if (loading) return <div>Loading...</div>
|
|
46
|
+
* if (!isAuthenticated) return <div>Please log in</div>
|
|
47
|
+
* return <div>Welcome, {user.displayName}</div>
|
|
48
|
+
*
|
|
49
|
+
* @__NO_SIDE_EFFECTS__
|
|
50
|
+
*/
|
|
51
|
+
function useAuth(auth, options = {}) {
|
|
52
|
+
const { errorHandler = (err) => console.error(err) } = options;
|
|
53
|
+
const [user, setUser] = useState(() => auth.currentUser);
|
|
54
|
+
const [loading, setLoading] = useState(true);
|
|
55
|
+
const [error, setError] = useState(null);
|
|
56
|
+
const errorHandlerRef = useRef(errorHandler);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
errorHandlerRef.current = errorHandler;
|
|
59
|
+
}, [errorHandler]);
|
|
60
|
+
const subscribedAuthRef = useRef(auth);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (subscribedAuthRef.current !== auth) {
|
|
63
|
+
subscribedAuthRef.current = auth;
|
|
64
|
+
setUser(auth.currentUser);
|
|
65
|
+
setLoading(true);
|
|
66
|
+
setError(null);
|
|
67
|
+
}
|
|
68
|
+
let unsubscribe;
|
|
69
|
+
let active = true;
|
|
70
|
+
try {
|
|
71
|
+
unsubscribe = auth.onIdTokenChanged((authUser) => {
|
|
72
|
+
if (!active) return;
|
|
73
|
+
setUser(authUser);
|
|
74
|
+
setLoading(false);
|
|
75
|
+
});
|
|
76
|
+
} catch (err) {
|
|
77
|
+
const subscriptionError = err instanceof Error ? err : new Error(String(err));
|
|
78
|
+
setError(subscriptionError);
|
|
79
|
+
setLoading(false);
|
|
80
|
+
errorHandlerRef.current(subscriptionError);
|
|
81
|
+
}
|
|
82
|
+
return () => {
|
|
83
|
+
active = false;
|
|
84
|
+
unsubscribe === null || unsubscribe === void 0 || unsubscribe();
|
|
85
|
+
};
|
|
86
|
+
}, [auth]);
|
|
87
|
+
return {
|
|
88
|
+
isAuthenticated: user !== null,
|
|
89
|
+
user,
|
|
90
|
+
loading,
|
|
91
|
+
error
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { useAuth };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DocumentData, DocumentReference, Query } from "firebase/firestore";
|
|
2
|
+
//#region useFirestore/index.d.ts
|
|
3
|
+
export interface UseFirestoreOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Custom error handler for Firestore subscription errors.
|
|
6
|
+
*
|
|
7
|
+
* @default (error) => console.error(error)
|
|
8
|
+
*/
|
|
9
|
+
errorHandler?: (err: Error) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Automatically unsubscribe when the component unmounts. Pass a number to
|
|
12
|
+
* delay the unsubscribe by that many milliseconds (upstream's
|
|
13
|
+
* `useTimeoutFn`-based delayed dispose).
|
|
14
|
+
*
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
autoDispose?: boolean | number;
|
|
18
|
+
}
|
|
19
|
+
export type FirebaseDocRef<T> = Query<T> | DocumentReference<T>;
|
|
20
|
+
type Falsy = false | 0 | '' | null | undefined;
|
|
21
|
+
export declare function useFirestore<T extends DocumentData>(maybeDocRef: DocumentReference<T> | Falsy, initialValue: T, options?: UseFirestoreOptions): T | null;
|
|
22
|
+
export declare function useFirestore<T extends DocumentData>(maybeDocRef: Query<T> | Falsy, initialValue: T[], options?: UseFirestoreOptions): T[];
|
|
23
|
+
export declare function useFirestore<T extends DocumentData>(maybeDocRef: DocumentReference<T> | Falsy, initialValue?: T | undefined | null, options?: UseFirestoreOptions): T | undefined | null;
|
|
24
|
+
export declare function useFirestore<T extends DocumentData>(maybeDocRef: Query<T> | Falsy, initialValue?: T[], options?: UseFirestoreOptions): T[] | undefined;
|
|
25
|
+
//#endregion
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
(function(exports, _reause_shared, react) {
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region useFirestore/index.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Attach the document `id` as a non-writable property of the snapshot data —
|
|
6
|
+
* ported verbatim from upstream. `data()` may be `undefined` for a deleted
|
|
7
|
+
* document.
|
|
8
|
+
*/
|
|
9
|
+
function getData(docRef) {
|
|
10
|
+
const data = docRef.data();
|
|
11
|
+
if (data) Object.defineProperty(data, "id", {
|
|
12
|
+
value: docRef.id.toString(),
|
|
13
|
+
writable: false
|
|
14
|
+
});
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Slash-parity check, ported verbatim from upstream: a `DocumentReference`
|
|
19
|
+
* path has an odd number of segments (`users/ada`), a `Query` path an even
|
|
20
|
+
* number (`users` or `users/ada/posts`).
|
|
21
|
+
*/
|
|
22
|
+
function isDocumentReference(docRef) {
|
|
23
|
+
var _docRef$path;
|
|
24
|
+
return (((_docRef$path = docRef.path) === null || _docRef$path === void 0 ? void 0 : _docRef$path.match(/\//g)) || []).length % 2 !== 0;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* React port of VueUse's `useFirestore`.
|
|
28
|
+
*
|
|
29
|
+
* Map from @vueuse/firebase/useFirestore
|
|
30
|
+
* (`source/vueuse/packages/firebase/useFirestore/`). Reactive
|
|
31
|
+
* [Firestore](https://firebase.google.com/docs/firestore) binding — it keeps
|
|
32
|
+
* local state in sync with a document reference or a query, so a component
|
|
33
|
+
* always renders the freshest remote data.
|
|
34
|
+
*
|
|
35
|
+
* Adjustment for React:
|
|
36
|
+
* - `maybeDocRef` is a plain value (upstream accepts `MaybeRef`): read-only
|
|
37
|
+
* value-source parameters take plain `T`. Pass a new reference/query
|
|
38
|
+
* identity to re-subscribe — **keep it stable across renders** (memoize
|
|
39
|
+
* `doc`/`collection`/`query` results): a fresh identity on every render
|
|
40
|
+
* re-subscribes on every render;
|
|
41
|
+
* - the return is the plain state VALUE (not a tuple, not an object) —
|
|
42
|
+
* upstream exposes no setter (0 writable values), so the shape mirrors the
|
|
43
|
+
* read side of upstream's `Ref<T | null>` / `Ref<T[]>`; a document resolves
|
|
44
|
+
* to `T | null` (a deleted document becomes `null`), a query to `T[]`;
|
|
45
|
+
* - the subscription lives in an effect keyed on `maybeDocRef`, so a new
|
|
46
|
+
* ref/query identity re-subscribes and closes the previous `onSnapshot`
|
|
47
|
+
* (upstream's immediate watch); a falsy docRef resets `data` to
|
|
48
|
+
* `initialValue`;
|
|
49
|
+
* - `firebase/firestore` is loaded through a guarded **dynamic** import, so
|
|
50
|
+
* this module never throws at import time when `firebase` is missing — a
|
|
51
|
+
* missing module or a failed `onSnapshot` call surfaces through
|
|
52
|
+
* `errorHandler` instead, and `data` stays at `initialValue`;
|
|
53
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
54
|
+
* does not re-subscribe;
|
|
55
|
+
* - nothing runs while rendering, so server rendering is safe.
|
|
56
|
+
*
|
|
57
|
+
* @see https://vueuse.org/firebase/useFirestore/
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const todos = useFirestore(collection(db, 'todos'))
|
|
61
|
+
* const user = useFirestore(doc(db, 'users', 'my-user-id'))
|
|
62
|
+
*
|
|
63
|
+
* @__NO_SIDE_EFFECTS__
|
|
64
|
+
*/
|
|
65
|
+
function useFirestore(maybeDocRef, initialValue = void 0, options = {}) {
|
|
66
|
+
const { errorHandler = (err) => console.error(err), autoDispose = true } = options;
|
|
67
|
+
const [data, setData] = (0, react.useState)(initialValue);
|
|
68
|
+
const initialValueRef = (0, react.useRef)(initialValue);
|
|
69
|
+
const autoDisposeRef = (0, react.useRef)(autoDispose);
|
|
70
|
+
const errorHandlerRef = (0, react.useRef)(errorHandler);
|
|
71
|
+
(0, react.useEffect)(() => {
|
|
72
|
+
errorHandlerRef.current = errorHandler;
|
|
73
|
+
}, [errorHandler]);
|
|
74
|
+
const closeRef = (0, react.useRef)(() => {});
|
|
75
|
+
(0, react.useEffect)(() => {
|
|
76
|
+
closeRef.current();
|
|
77
|
+
closeRef.current = () => {};
|
|
78
|
+
if (!maybeDocRef) {
|
|
79
|
+
setData(initialValueRef.current);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
let active = true;
|
|
83
|
+
let close;
|
|
84
|
+
import("firebase/firestore").then(({ onSnapshot }) => {
|
|
85
|
+
if (!active) return;
|
|
86
|
+
try {
|
|
87
|
+
var _close;
|
|
88
|
+
if (isDocumentReference(maybeDocRef)) close = onSnapshot(maybeDocRef, (snapshot) => {
|
|
89
|
+
if (!active) return;
|
|
90
|
+
setData(getData(snapshot) || null);
|
|
91
|
+
}, (err) => errorHandlerRef.current(err));
|
|
92
|
+
else close = onSnapshot(maybeDocRef, (snapshot) => {
|
|
93
|
+
if (!active) return;
|
|
94
|
+
setData(snapshot.docs.map(getData).filter(_reause_shared.isDef));
|
|
95
|
+
}, (err) => errorHandlerRef.current(err));
|
|
96
|
+
closeRef.current = (_close = close) !== null && _close !== void 0 ? _close : (() => {});
|
|
97
|
+
} catch (err) {
|
|
98
|
+
errorHandlerRef.current(err instanceof Error ? err : new Error(String(err)));
|
|
99
|
+
}
|
|
100
|
+
}).catch((err) => {
|
|
101
|
+
if (!active) return;
|
|
102
|
+
errorHandlerRef.current(err instanceof Error ? err : new Error(String(err)));
|
|
103
|
+
});
|
|
104
|
+
return () => {
|
|
105
|
+
active = false;
|
|
106
|
+
};
|
|
107
|
+
}, [maybeDocRef]);
|
|
108
|
+
(0, react.useEffect)(() => {
|
|
109
|
+
return () => {
|
|
110
|
+
if (autoDisposeRef.current === true) closeRef.current();
|
|
111
|
+
else if (typeof autoDisposeRef.current === "number") setTimeout(() => {
|
|
112
|
+
closeRef.current();
|
|
113
|
+
}, autoDisposeRef.current);
|
|
114
|
+
};
|
|
115
|
+
}, []);
|
|
116
|
+
return data;
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
exports.useFirestore = useFirestore;
|
|
120
|
+
})(this.reause = this.reause || {}, reause, React);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function r(e){let t=e.data();return t&&Object.defineProperty(t,"id",{value:e.id.toString(),writable:!1}),t}function i(e){var t;return(((t=e.path)==null?void 0:t.match(/\//g))||[]).length%2!=0}function a(e,a=void 0,o={}){let{errorHandler:s=e=>console.error(e),autoDispose:c=!0}=o,[l,u]=(0,n.useState)(a),d=(0,n.useRef)(a),f=(0,n.useRef)(c),p=(0,n.useRef)(s);(0,n.useEffect)(()=>{p.current=s},[s]);let m=(0,n.useRef)(()=>{});return(0,n.useEffect)(()=>{if(m.current(),m.current=()=>{},!e){u(d.current);return}let n=!0,a;return import(`firebase/firestore`).then(({onSnapshot:o})=>{if(n)try{var s;a=i(e)?o(e,e=>{n&&u(r(e)||null)},e=>p.current(e)):o(e,e=>{n&&u(e.docs.map(r).filter(t.isDef))},e=>p.current(e)),m.current=(s=a)==null?(()=>{}):s}catch(e){p.current(e instanceof Error?e:Error(String(e)))}}).catch(e=>{n&&p.current(e instanceof Error?e:Error(String(e)))}),()=>{n=!1}},[e]),(0,n.useEffect)(()=>()=>{f.current===!0?m.current():typeof f.current==`number`&&setTimeout(()=>{m.current()},f.current)},[]),l}e.useFirestore=a})(this.reause=this.reause||{},reause,React);
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { isDef } from "@reause/shared";
|
|
3
|
+
//#region useFirestore/index.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Attach the document `id` as a non-writable property of the snapshot data —
|
|
6
|
+
* ported verbatim from upstream. `data()` may be `undefined` for a deleted
|
|
7
|
+
* document.
|
|
8
|
+
*/
|
|
9
|
+
function getData(docRef) {
|
|
10
|
+
const data = docRef.data();
|
|
11
|
+
if (data) Object.defineProperty(data, "id", {
|
|
12
|
+
value: docRef.id.toString(),
|
|
13
|
+
writable: false
|
|
14
|
+
});
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Slash-parity check, ported verbatim from upstream: a `DocumentReference`
|
|
19
|
+
* path has an odd number of segments (`users/ada`), a `Query` path an even
|
|
20
|
+
* number (`users` or `users/ada/posts`).
|
|
21
|
+
*/
|
|
22
|
+
function isDocumentReference(docRef) {
|
|
23
|
+
var _docRef$path;
|
|
24
|
+
return (((_docRef$path = docRef.path) === null || _docRef$path === void 0 ? void 0 : _docRef$path.match(/\//g)) || []).length % 2 !== 0;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* React port of VueUse's `useFirestore`.
|
|
28
|
+
*
|
|
29
|
+
* Map from @vueuse/firebase/useFirestore
|
|
30
|
+
* (`source/vueuse/packages/firebase/useFirestore/`). Reactive
|
|
31
|
+
* [Firestore](https://firebase.google.com/docs/firestore) binding — it keeps
|
|
32
|
+
* local state in sync with a document reference or a query, so a component
|
|
33
|
+
* always renders the freshest remote data.
|
|
34
|
+
*
|
|
35
|
+
* Adjustment for React:
|
|
36
|
+
* - `maybeDocRef` is a plain value (upstream accepts `MaybeRef`): read-only
|
|
37
|
+
* value-source parameters take plain `T`. Pass a new reference/query
|
|
38
|
+
* identity to re-subscribe — **keep it stable across renders** (memoize
|
|
39
|
+
* `doc`/`collection`/`query` results): a fresh identity on every render
|
|
40
|
+
* re-subscribes on every render;
|
|
41
|
+
* - the return is the plain state VALUE (not a tuple, not an object) —
|
|
42
|
+
* upstream exposes no setter (0 writable values), so the shape mirrors the
|
|
43
|
+
* read side of upstream's `Ref<T | null>` / `Ref<T[]>`; a document resolves
|
|
44
|
+
* to `T | null` (a deleted document becomes `null`), a query to `T[]`;
|
|
45
|
+
* - the subscription lives in an effect keyed on `maybeDocRef`, so a new
|
|
46
|
+
* ref/query identity re-subscribes and closes the previous `onSnapshot`
|
|
47
|
+
* (upstream's immediate watch); a falsy docRef resets `data` to
|
|
48
|
+
* `initialValue`;
|
|
49
|
+
* - `firebase/firestore` is loaded through a guarded **dynamic** import, so
|
|
50
|
+
* this module never throws at import time when `firebase` is missing — a
|
|
51
|
+
* missing module or a failed `onSnapshot` call surfaces through
|
|
52
|
+
* `errorHandler` instead, and `data` stays at `initialValue`;
|
|
53
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
54
|
+
* does not re-subscribe;
|
|
55
|
+
* - nothing runs while rendering, so server rendering is safe.
|
|
56
|
+
*
|
|
57
|
+
* @see https://vueuse.org/firebase/useFirestore/
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const todos = useFirestore(collection(db, 'todos'))
|
|
61
|
+
* const user = useFirestore(doc(db, 'users', 'my-user-id'))
|
|
62
|
+
*
|
|
63
|
+
* @__NO_SIDE_EFFECTS__
|
|
64
|
+
*/
|
|
65
|
+
function useFirestore(maybeDocRef, initialValue = void 0, options = {}) {
|
|
66
|
+
const { errorHandler = (err) => console.error(err), autoDispose = true } = options;
|
|
67
|
+
const [data, setData] = useState(initialValue);
|
|
68
|
+
const initialValueRef = useRef(initialValue);
|
|
69
|
+
const autoDisposeRef = useRef(autoDispose);
|
|
70
|
+
const errorHandlerRef = useRef(errorHandler);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
errorHandlerRef.current = errorHandler;
|
|
73
|
+
}, [errorHandler]);
|
|
74
|
+
const closeRef = useRef(() => {});
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
closeRef.current();
|
|
77
|
+
closeRef.current = () => {};
|
|
78
|
+
if (!maybeDocRef) {
|
|
79
|
+
setData(initialValueRef.current);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
let active = true;
|
|
83
|
+
let close;
|
|
84
|
+
import("firebase/firestore").then(({ onSnapshot }) => {
|
|
85
|
+
if (!active) return;
|
|
86
|
+
try {
|
|
87
|
+
var _close;
|
|
88
|
+
if (isDocumentReference(maybeDocRef)) close = onSnapshot(maybeDocRef, (snapshot) => {
|
|
89
|
+
if (!active) return;
|
|
90
|
+
setData(getData(snapshot) || null);
|
|
91
|
+
}, (err) => errorHandlerRef.current(err));
|
|
92
|
+
else close = onSnapshot(maybeDocRef, (snapshot) => {
|
|
93
|
+
if (!active) return;
|
|
94
|
+
setData(snapshot.docs.map(getData).filter(isDef));
|
|
95
|
+
}, (err) => errorHandlerRef.current(err));
|
|
96
|
+
closeRef.current = (_close = close) !== null && _close !== void 0 ? _close : (() => {});
|
|
97
|
+
} catch (err) {
|
|
98
|
+
errorHandlerRef.current(err instanceof Error ? err : new Error(String(err)));
|
|
99
|
+
}
|
|
100
|
+
}).catch((err) => {
|
|
101
|
+
if (!active) return;
|
|
102
|
+
errorHandlerRef.current(err instanceof Error ? err : new Error(String(err)));
|
|
103
|
+
});
|
|
104
|
+
return () => {
|
|
105
|
+
active = false;
|
|
106
|
+
};
|
|
107
|
+
}, [maybeDocRef]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
return () => {
|
|
110
|
+
if (autoDisposeRef.current === true) closeRef.current();
|
|
111
|
+
else if (typeof autoDisposeRef.current === "number") setTimeout(() => {
|
|
112
|
+
closeRef.current();
|
|
113
|
+
}, autoDisposeRef.current);
|
|
114
|
+
};
|
|
115
|
+
}, []);
|
|
116
|
+
return data;
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
export { useFirestore };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { DatabaseReference } from "firebase/database";
|
|
2
|
+
//#region useRTDB/index.d.ts
|
|
3
|
+
export interface UseRTDBOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Custom error handler for database errors.
|
|
6
|
+
*
|
|
7
|
+
* @default (error) => console.error(error)
|
|
8
|
+
*/
|
|
9
|
+
errorHandler?: (err: Error) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Automatically unsubscribe from the database reference when the component
|
|
12
|
+
* unmounts.
|
|
13
|
+
*
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
autoDispose?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Result tuple of `useRTDB`, mirroring upstream's writable Vue ref:
|
|
20
|
+
* `[data, setData]`.
|
|
21
|
+
*/
|
|
22
|
+
export type UseRTDBReturn<T> = [data: T | undefined, setData: (value: T | undefined) => void];
|
|
23
|
+
/**
|
|
24
|
+
* React port of VueUse's `useRTDB`.
|
|
25
|
+
*
|
|
26
|
+
* Map from @vueuse/firebase `useRTDB`
|
|
27
|
+
*
|
|
28
|
+
* Reactive [Firebase Realtime Database](https://firebase.google.com/docs/database)
|
|
29
|
+
* binding — keeps local state in sync with a database reference. The listener
|
|
30
|
+
* is registered with `onValue` in a mount effect and feeds `data` with
|
|
31
|
+
* `snapshot.val()` on every database change.
|
|
32
|
+
*
|
|
33
|
+
* Adjustment for React:
|
|
34
|
+
* - upstream returns a writable `Ref<T | undefined>`, so this port returns the
|
|
35
|
+
* `[data, setData]` tuple; `data` starts `undefined` and holds the latest
|
|
36
|
+
* snapshot value;
|
|
37
|
+
* - `setData` writes **local state only** — it does not write to the Realtime
|
|
38
|
+
* Database (upstream's ref is equally local). Use the `firebase/database`
|
|
39
|
+
* write APIs (`set` / `update` / `push`) to persist;
|
|
40
|
+
* - the subscription lives in a `useEffect` keyed on `docRef` and `autoDispose`,
|
|
41
|
+
* so a new `docRef` identity re-subscribes and unsubscribes the previous
|
|
42
|
+
* listener (upstream subscribes once per `setup()` — a deliberate
|
|
43
|
+
* React-idiomatic deviation);
|
|
44
|
+
* - cleanup calls the `onValue` unsubscribe only when `autoDispose` is `true`
|
|
45
|
+
* (upstream parity). `autoDispose: false` means the subscription outlives the
|
|
46
|
+
* component: the caller gets no `off` handle and must live with the leak —
|
|
47
|
+
* discouraged, kept only for upstream parity;
|
|
48
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
49
|
+
* does not re-subscribe.
|
|
50
|
+
*
|
|
51
|
+
* @see https://vueuse.org/useRTDB
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const [todos, setTodos] = useRTDB<Record<string, Todo>>(ref(getDatabase(app), 'todos'))
|
|
55
|
+
*
|
|
56
|
+
* @__NO_SIDE_EFFECTS__
|
|
57
|
+
*/
|
|
58
|
+
export declare function useRTDB<T = any>(docRef: DatabaseReference, options?: UseRTDBOptions): UseRTDBReturn<T>;
|
|
59
|
+
//#endregion
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
(function(exports, firebase_database, react) {
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region useRTDB/index.tsx
|
|
4
|
+
/**
|
|
5
|
+
* React port of VueUse's `useRTDB`.
|
|
6
|
+
*
|
|
7
|
+
* Map from @vueuse/firebase `useRTDB`
|
|
8
|
+
*
|
|
9
|
+
* Reactive [Firebase Realtime Database](https://firebase.google.com/docs/database)
|
|
10
|
+
* binding — keeps local state in sync with a database reference. The listener
|
|
11
|
+
* is registered with `onValue` in a mount effect and feeds `data` with
|
|
12
|
+
* `snapshot.val()` on every database change.
|
|
13
|
+
*
|
|
14
|
+
* Adjustment for React:
|
|
15
|
+
* - upstream returns a writable `Ref<T | undefined>`, so this port returns the
|
|
16
|
+
* `[data, setData]` tuple; `data` starts `undefined` and holds the latest
|
|
17
|
+
* snapshot value;
|
|
18
|
+
* - `setData` writes **local state only** — it does not write to the Realtime
|
|
19
|
+
* Database (upstream's ref is equally local). Use the `firebase/database`
|
|
20
|
+
* write APIs (`set` / `update` / `push`) to persist;
|
|
21
|
+
* - the subscription lives in a `useEffect` keyed on `docRef` and `autoDispose`,
|
|
22
|
+
* so a new `docRef` identity re-subscribes and unsubscribes the previous
|
|
23
|
+
* listener (upstream subscribes once per `setup()` — a deliberate
|
|
24
|
+
* React-idiomatic deviation);
|
|
25
|
+
* - cleanup calls the `onValue` unsubscribe only when `autoDispose` is `true`
|
|
26
|
+
* (upstream parity). `autoDispose: false` means the subscription outlives the
|
|
27
|
+
* component: the caller gets no `off` handle and must live with the leak —
|
|
28
|
+
* discouraged, kept only for upstream parity;
|
|
29
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
30
|
+
* does not re-subscribe.
|
|
31
|
+
*
|
|
32
|
+
* @see https://vueuse.org/useRTDB
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const [todos, setTodos] = useRTDB<Record<string, Todo>>(ref(getDatabase(app), 'todos'))
|
|
36
|
+
*
|
|
37
|
+
* @__NO_SIDE_EFFECTS__
|
|
38
|
+
*/
|
|
39
|
+
function useRTDB(docRef, options = {}) {
|
|
40
|
+
const { errorHandler = (err) => console.error(err), autoDispose = true } = options;
|
|
41
|
+
const [data, setData] = (0, react.useState)(void 0);
|
|
42
|
+
const errorHandlerRef = (0, react.useRef)(errorHandler);
|
|
43
|
+
(0, react.useEffect)(() => {
|
|
44
|
+
errorHandlerRef.current = errorHandler;
|
|
45
|
+
}, [errorHandler]);
|
|
46
|
+
(0, react.useEffect)(() => {
|
|
47
|
+
const off = (0, firebase_database.onValue)(docRef, (snapshot) => setData(snapshot.val()), (err) => errorHandlerRef.current(err));
|
|
48
|
+
return () => {
|
|
49
|
+
if (autoDispose) off();
|
|
50
|
+
};
|
|
51
|
+
}, [docRef, autoDispose]);
|
|
52
|
+
return [data, setData];
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
exports.useRTDB = useRTDB;
|
|
56
|
+
})(this.reause = this.reause || {}, firebase, React);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function r(e,r={}){let{errorHandler:i=e=>console.error(e),autoDispose:a=!0}=r,[o,s]=(0,n.useState)(void 0),c=(0,n.useRef)(i);return(0,n.useEffect)(()=>{c.current=i},[i]),(0,n.useEffect)(()=>{let n=(0,t.onValue)(e,e=>s(e.val()),e=>c.current(e));return()=>{a&&n()}},[e,a]),[o,s]}e.useRTDB=r})(this.reause=this.reause||{},firebase,React);
|
package/dist/useRTDB.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { onValue } from "firebase/database";
|
|
3
|
+
//#region useRTDB/index.tsx
|
|
4
|
+
/**
|
|
5
|
+
* React port of VueUse's `useRTDB`.
|
|
6
|
+
*
|
|
7
|
+
* Map from @vueuse/firebase `useRTDB`
|
|
8
|
+
*
|
|
9
|
+
* Reactive [Firebase Realtime Database](https://firebase.google.com/docs/database)
|
|
10
|
+
* binding — keeps local state in sync with a database reference. The listener
|
|
11
|
+
* is registered with `onValue` in a mount effect and feeds `data` with
|
|
12
|
+
* `snapshot.val()` on every database change.
|
|
13
|
+
*
|
|
14
|
+
* Adjustment for React:
|
|
15
|
+
* - upstream returns a writable `Ref<T | undefined>`, so this port returns the
|
|
16
|
+
* `[data, setData]` tuple; `data` starts `undefined` and holds the latest
|
|
17
|
+
* snapshot value;
|
|
18
|
+
* - `setData` writes **local state only** — it does not write to the Realtime
|
|
19
|
+
* Database (upstream's ref is equally local). Use the `firebase/database`
|
|
20
|
+
* write APIs (`set` / `update` / `push`) to persist;
|
|
21
|
+
* - the subscription lives in a `useEffect` keyed on `docRef` and `autoDispose`,
|
|
22
|
+
* so a new `docRef` identity re-subscribes and unsubscribes the previous
|
|
23
|
+
* listener (upstream subscribes once per `setup()` — a deliberate
|
|
24
|
+
* React-idiomatic deviation);
|
|
25
|
+
* - cleanup calls the `onValue` unsubscribe only when `autoDispose` is `true`
|
|
26
|
+
* (upstream parity). `autoDispose: false` means the subscription outlives the
|
|
27
|
+
* component: the caller gets no `off` handle and must live with the leak —
|
|
28
|
+
* discouraged, kept only for upstream parity;
|
|
29
|
+
* - the latest `errorHandler` is read from a ref, so passing an inline handler
|
|
30
|
+
* does not re-subscribe.
|
|
31
|
+
*
|
|
32
|
+
* @see https://vueuse.org/useRTDB
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const [todos, setTodos] = useRTDB<Record<string, Todo>>(ref(getDatabase(app), 'todos'))
|
|
36
|
+
*
|
|
37
|
+
* @__NO_SIDE_EFFECTS__
|
|
38
|
+
*/
|
|
39
|
+
function useRTDB(docRef, options = {}) {
|
|
40
|
+
const { errorHandler = (err) => console.error(err), autoDispose = true } = options;
|
|
41
|
+
const [data, setData] = useState(void 0);
|
|
42
|
+
const errorHandlerRef = useRef(errorHandler);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
errorHandlerRef.current = errorHandler;
|
|
45
|
+
}, [errorHandler]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const off = onValue(docRef, (snapshot) => setData(snapshot.val()), (err) => errorHandlerRef.current(err));
|
|
48
|
+
return () => {
|
|
49
|
+
if (autoDispose) off();
|
|
50
|
+
};
|
|
51
|
+
}, [docRef, autoDispose]);
|
|
52
|
+
return [data, setData];
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { useRTDB };
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reause/firebase",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.2",
|
|
5
|
+
"description": "Realtime bindings for Firebase — React port of @vueuse/firebase",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./*": "./dist/*",
|
|
11
|
+
"./useAuth": "./dist/useAuth.js",
|
|
12
|
+
"./useFirestore": "./dist/useFirestore.js",
|
|
13
|
+
"./useRTDB": "./dist/useRTDB.js",
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"unpkg": "./dist/index.iife.min.js",
|
|
19
|
+
"jsdelivr": "./dist/index.iife.min.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"firebase": ">=9.0.0",
|
|
26
|
+
"react": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsdown"
|
|
30
|
+
}
|
|
31
|
+
}
|