Skip to content

Commit 4780851

Browse files
committed
Update README details, update Firebase to latest version
1 parent 6f779f0 commit 4780851

File tree

6 files changed

+2110
-1738
lines changed

6 files changed

+2110
-1738
lines changed

README.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ npm install
2323

2424
3. To expose your app server using an HTTP tunnel, install [ngrok](https://www.npmjs.com/package/ngrok#usage) globally, then start the ngrok service.
2525

26+
Starting a local HTTP tunnel with ngrok requires you to create an [ngrok account](https://dashboard.ngrok.com/signup) and add your [ngrok authtoken](https://dashboard.ngrok.com/get-started/your-authtoken) to the ngrok config file.
27+
28+
```shell
29+
ngrok config add-authtoken $YOUR_AUTHTOKEN
30+
```
31+
2632
You can use `npm` to install ngrok:
2733

2834
```shell
@@ -57,29 +63,29 @@ cp .env-sample .env
5763

5864
6. In the `.env` file, replace the `CLIENT_ID` and `CLIENT_SECRET` variables with the API account credentials in the app profile. To locate the credentials, find the app's profile in the [Developer Portal](https://devtools.bigcommerce.com/my/apps), then click **View Client ID**.
5965

60-
7. In the `.env` file, update the `AUTH_CALLBACK` variable with the `ngrok_url` from step 4.
66+
7. In the `.env` file, update the `AUTH_CALLBACK` variable with the auth callback URL from step 4.
6167

6268
8. In the `.env` file, enter a secret `JWT_KEY`. To support HS256 encryption, the JWT key must be at least 32 random characters (256 bits).
6369

64-
9. **Configure the data store.** In the `.env` file, specify the `DB_TYPE`.
70+
9. **Configure the data store.** This project was written to use [Firebase](https://firebase.google.com/) or [MySQL](https://www.mysql.com/)
6571

66-
> The DB type must be either `firebase` or `mysql`.
72+
In the `.env` file, specify the `DB_TYPE`.
6773

68-
If using Firebase, supply the `FIRE_` config keys listed in the `.env` file. See the [Firebase quickstart (Google)](https://firebase.google.com/docs/firestore/quickstart).
74+
If using Firebase, copy the contents of your Service Account JSON key file into the `sample-firebase-keys.json` file. This file can be generated by:
75+
1. Creating a new project in Firebase
76+
2. Adding a Cloud Firestore
77+
3. And generating a new Private Key under Project Settings > Service Accounts
78+
See the [Firebase quickstart (Google)](https://firebase.google.com/docs/firestore/quickstart) for more detailed information.
6979

70-
If using MySQL, supply the `MYSQL_` config keys listed in the `.env` file, then do the initial database migration by running the following npm script:
71-
72-
```shell
73-
npm run db:setup
74-
```
80+
If using MySQL, supply the `MYSQL_` config keys listed in the `.env` file, then do the initial database migration by running the following npm script: `npm run db:setup`
7581

7682
10. Start your dev environment in a dedicated terminal session, **separate from `ngrok`**.
7783

7884
```shell
7985
npm run dev
8086
```
8187

82-
> If `ngrok` expires, update the callbacks in steps 4 and 7 with the new `ngrok_url`. You can learn more about [persisting ngrok tunnels longer (ngrok)](https://ngrok.com/docs/getting-started/#step-3-connect-your-agent-to-your-ngrok-account).
88+
> If you relaunch `ngrok`, update the callbacks in steps 4 and 7 with the new `ngrok_url`. You can learn more about [persisting ngrok tunnels longer (ngrok)](https://ngrok.com/docs/getting-started/#step-3-connect-your-agent-to-your-ngrok-account).
8389
8490
11. Consult our developer documentation to [install and launch the app](https://developer.bigcommerce.com/api-docs/apps/quick-start#install-the-app).
8591

lib/auth.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ export function setSession(session: SessionProps) {
5959

6060
export async function getSession({ query: { context = '' } }: NextApiRequest) {
6161
if (typeof context !== 'string') return;
62-
const { context: storeHash, user } = decodePayload(context);
63-
const hasUser = await db.hasStoreUser(storeHash, user?.id);
62+
const { context: storeHash, user } = decodePayload(context) as SessionProps;
63+
const hasUser = await db.hasStoreUser(storeHash, String(user?.id));
6464

6565
// Before retrieving session/ hitting APIs, check user
6666
if (!hasUser) {

lib/dbs/firebase.ts

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
1-
import { initializeApp } from 'firebase/app';
2-
import { deleteDoc, doc, getDoc, getFirestore, setDoc, updateDoc } from 'firebase/firestore';
1+
import { cert, getApp, getApps, initializeApp } from 'firebase-admin/app';
2+
import { getFirestore } from 'firebase-admin/firestore';
3+
import serviceAccount from '../../sample-firebase-keys.json';
34
import { SessionProps, UserData } from '../../types';
45

5-
// Firebase config and initialization
6-
// Prod applications might use config file
7-
const { FIRE_API_KEY, FIRE_DOMAIN, FIRE_PROJECT_ID } = process.env;
8-
const firebaseConfig = {
9-
apiKey: FIRE_API_KEY,
10-
authDomain: FIRE_DOMAIN,
11-
projectId: FIRE_PROJECT_ID,
12-
};
13-
const app = initializeApp(firebaseConfig);
6+
const app = getApps().length
7+
? getApp()
8+
: initializeApp({ credential: cert(serviceAccount as any) });
149
const db = getFirestore(app);
1510

1611
// Firestore data management functions
@@ -20,14 +15,14 @@ export async function setUser({ user }: SessionProps) {
2015
if (!user) return null;
2116

2217
const { email, id, username } = user;
23-
const ref = doc(db, 'users', String(id));
18+
const ref = db.collection('user').doc(String(id));
2419
const data: UserData = { email };
2520

2621
if (username) {
2722
data.username = username;
2823
}
2924

30-
await setDoc(ref, data, { merge: true });
25+
await ref.set(data, {merge: true });
3126
}
3227

3328
export async function setStore(session: SessionProps) {
@@ -41,10 +36,10 @@ export async function setStore(session: SessionProps) {
4136
if (!accessToken || !scope) return null;
4237

4338
const storeHash = context?.split('/')[1] || '';
44-
const ref = doc(db, 'store', storeHash);
39+
const ref = db.collection('store').doc(storeHash);
4540
const data = { accessToken, adminId: id, scope };
4641

47-
await setDoc(ref, data);
42+
await ref.set(data);
4843
}
4944

5045
// User management for multi-user apps
@@ -62,22 +57,22 @@ export async function setStoreUser(session: SessionProps) {
6257
const contextString = context ?? sub;
6358
const storeHash = contextString?.split('/')[1] || '';
6459
const documentId = `${userId}_${storeHash}`; // users can belong to multiple stores
65-
const ref = doc(db, 'storeUsers', documentId);
66-
const storeUser = await getDoc(ref);
60+
const ref = db.collection('storeUsers').doc(documentId);
61+
const storeUser = await ref.get();
6762

6863
// Set admin (store owner) if installing/ updating the app
6964
// https://developer.bigcommerce.com/api-docs/apps/guide/users
7065
if (accessToken) {
7166
// Create a new admin user if none exists
72-
if (!storeUser.exists()) {
73-
await setDoc(ref, { storeHash, isAdmin: true });
67+
if (!storeUser.exists) {
68+
await ref.set({ storeHash, isAdmin: true });
7469
} else if (!storeUser.data()?.isAdmin) {
75-
await updateDoc(ref, { isAdmin: true });
70+
await ref.update({ isAdmin: true });
7671
}
7772
} else {
7873
// Create a new user if it doesn't exist
79-
if (!storeUser.exists()) {
80-
await setDoc(ref, { storeHash, isAdmin: owner.id === userId }); // isAdmin true if owner == user
74+
if (!storeUser.exists) {
75+
await ref.set({ storeHash, isAdmin: owner.id === userId });
8176
}
8277
}
8378
}
@@ -86,29 +81,29 @@ export async function deleteUser({ context, user, sub }: SessionProps) {
8681
const contextString = context ?? sub;
8782
const storeHash = contextString?.split('/')[1] || '';
8883
const docId = `${user?.id}_${storeHash}`;
89-
const ref = doc(db, 'storeUsers', docId);
84+
const ref = db.collection('storeUsers').doc(docId);
9085

91-
await deleteDoc(ref);
86+
await ref.delete();
9287
}
9388

9489
export async function hasStoreUser(storeHash: string, userId: string) {
9590
if (!storeHash || !userId) return false;
9691

9792
const docId = `${userId}_${storeHash}`;
98-
const userDoc = await getDoc(doc(db, 'storeUsers', docId));
93+
const userDoc = await db.collection('storeUsers').doc(docId).get();
9994

100-
return userDoc.exists();
95+
return userDoc.exists;
10196
}
10297

10398
export async function getStoreToken(storeHash: string) {
10499
if (!storeHash) return null;
105-
const storeDoc = await getDoc(doc(db, 'store', storeHash));
100+
const storeDoc = await db.collection('store').doc(storeHash).get();
106101

107102
return storeDoc.data()?.accessToken ?? null;
108103
}
109104

110105
export async function deleteStore({ store_hash: storeHash }: SessionProps) {
111-
const ref = doc(db, 'store', storeHash);
106+
const ref = db.collection('store').doc(storeHash);
112107

113-
await deleteDoc(ref);
108+
await ref.delete();
114109
}

0 commit comments

Comments
 (0)