Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"no-empty-function": "off",
"@typescript-eslint/no-empty-function": ["error"],
"global-require": "off",
"import/no-dynamic-require": "off"
"import/no-dynamic-require": "off",
"camelcase": "off"
},
"settings": {
"import/resolver": {
Expand Down
69 changes: 43 additions & 26 deletions lib/adapters/haerperDB.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import add from "date-fns/add"
import { HarperDB } from "harperdbjs"
import { Account, Profile } from "next-auth"
import { Adapter } from "next-auth/adapters"
import pricing from "../../pricing.json"
import { HarperDB } from "../harperDB"
import { AppUser, AppUserJSON, IAppUser, PaymentStatus, Plans } from "../models"

// @ts-expect-error
Expand All @@ -26,69 +26,84 @@ export const HarperDBAdapter: Adapter<HarperDB, never, IAppUser, Profile> = (db)
},
}

const [userId] = await db.insert<Omit<AppUserJSON, "id">>({
const { inserted_hashes } = await db.insert<Omit<AppUserJSON, "id">>(user, {
schema: "dev",
table: "users",
records: [user],
})

if (!inserted_hashes?.[0]) {
return null
}

const [userId] = inserted_hashes

return AppUser.fromJSON({ id: userId, ...user })
},

async getUser(id) {
const [user] = await db.findByIds<AppUserJSON>([id], { table: "users" })
const {
records: [user],
} = await db.searchByHash([id], { schema: "dev", table: "users" })

if (!user) return null

return AppUser.fromJSON(user)
return AppUser.fromJSON(user as AppUserJSON)
},

async getUserByEmail(email) {
if (!email) return null

const [user] = await db.findByValue<AppUserJSON>("email", email, { table: "users" })
const {
records: [user],
} = await db.searchByValue("email", email, { schema: "dev", table: "users" })

if (!user) return null

return AppUser.fromJSON(user)
return AppUser.fromJSON(user as AppUserJSON)
},

async getUserByProviderAccountId(providerId, providerAccountId) {
const [accountSnapshot] = await db.findByConditions<Account>(
"and",
const {
records: [accountSnapshot],
} = await db.searchByConditions(
[
{ attribute: "providerId", type: "equals", value: providerId },
{ attribute: "providerAccountId", type: "equals", value: providerAccountId },
{ searchAttribute: "providerId", searchType: "equals", searchValue: providerId },
{ searchAttribute: "providerAccountId", searchType: "equals", searchValue: providerAccountId },
],
{
schema: "dev",
table: "accounts",
limit: 1,
}
)

if (!accountSnapshot) return null

const userId = accountSnapshot?.userId as string
const userId = (accountSnapshot as Account)?.userId as string

if (!userId) return null

const [user] = await db.findByIds<AppUserJSON>([userId], { table: "users" })
const {
records: [user],
} = await db.searchByHash([userId], { schema: "dev", table: "users" })

if (!user) return null

return AppUser.fromJSON(user)
return AppUser.fromJSON(user as AppUserJSON)
},

async updateUser(user) {
await db.update<AppUserJSON>({
await db.updateOne<AppUserJSON>(new AppUser(user).toJSON(), {
schema: "dev",
table: "users",
records: [new AppUser(user).toJSON()],
})

return user
},

async deleteUser(userId) {
await db.delete([userId], {
await db.deleteOne(userId, {
schema: "dev",
table: "users",
})
},
Expand All @@ -104,33 +119,35 @@ export const HarperDBAdapter: Adapter<HarperDB, never, IAppUser, Profile> = (db)
accessTokenExpires,
}

await db.insert({
await db.insert(account, {
schema: "dev",
table: "accounts",
records: [account],
})

return account
},

async unlinkAccount(userId, providerId, providerAccountId) {
const [account] = await db.findByConditions<Account>(
"and",
const {
records: [account],
} = await db.searchByConditions(
[
{ attribute: "userId", type: "equals", value: userId },
{ attribute: "providerId", type: "equals", value: providerId },
{ attribute: "providerAccountId", type: "equals", value: providerAccountId },
{ searchAttribute: "userId", searchType: "equals", searchValue: userId },
{ searchAttribute: "providerId", searchType: "equals", searchValue: providerId },
{ searchAttribute: "providerAccountId", searchType: "equals", searchValue: providerAccountId },
],
{
schema: "dev",
table: "accounts",
limit: 1,
}
)

if (!account) return null

const accountId = account.id
const accountId = (account as Account).id

return db.delete([accountId], { table: "accounts" })
return db.deleteOne(accountId, { schema: "dev", table: "accounts" })
},

// next-auth throws error if these functions aren't defined
Expand Down
129 changes: 5 additions & 124 deletions lib/harperDB/index.ts
Original file line number Diff line number Diff line change
@@ -1,125 +1,6 @@
import axios, { AxiosResponse } from "axios"
import omitBy from "lodash/omitBy"
import isNil from "lodash/isNil"
import { HarperDB } from "harperdbjs"

/* eslint-disable camelcase */
export class HarperDB {
private readonly baseURL = process.env.NEXT_PUBLIC_DB_ENDPOINT

private readonly authToken = process.env.NEXT_PUBLIC_DB_AUTH_TOKEN

constructor(public readonly schema: string) {}

private readonly client = axios.create({
baseURL: this.baseURL,
headers: {
Authorization: `Basic ${this.authToken}`,
"Content-Type": "application/json",
},
method: "POST",
})

async insert<T>(options: { table: string; records: T[] }) {
const data = JSON.stringify({
operation: "insert",
schema: this.schema,
table: options.table,
records: options.records.map((record) => omitBy(record, isNil)),
})

const {
data: { inserted_hashes },
} = await this.client({ data })
return (inserted_hashes ?? []) as string[]
}

async findByIds<T>(ids: string[], options: { table: string; attributes?: string[] }) {
const data = JSON.stringify({
operation: "search_by_hash",
schema: this.schema,
table: options.table,
hash_values: ids,
get_attributes: options.attributes ?? ["*"],
})

return ((await this.client({ data })) as AxiosResponse<T[]>).data
}

async findByValue<T>(attribute: string, value: string, options: { table: string; attributes?: string[] }) {
const data = JSON.stringify({
operation: "search_by_value",
schema: this.schema,
table: options.table,
search_attribute: attribute,
search_value: value,
get_attributes: options.attributes ?? ["*"],
})

return ((await this.client({ data })) as AxiosResponse<T[]>).data
}

async findByConditions<T>(
operator: "and" | "or",
conditions: {
attribute: string
type: "equals" | "contains" | "starts_with" | "ends_with" | "greater_than" | "greater_than_equal" | "less_than" | "less_than_equal" | "between"
value: string
}[],
options: { table: string; attributes?: string[]; limit?: number; offset?: number }
) {
const data = JSON.stringify({
operation: "search_by_conditions",
schema: this.schema,
table: options.table,
operator,
offset: options.offset ?? 0,
limit: options.offset ?? 20,
get_attributes: options.attributes ?? ["*"],
conditions: conditions.map(({ attribute, type, value }) => ({ search_attribute: attribute, search_type: type, search_value: value })),
})

return ((await this.client({ data })) as AxiosResponse<T[]>).data
}

async update<T>(options: { table: string; records: ({ id: string } & Partial<T>)[] }) {
const data = JSON.stringify({
operation: "update",
schema: this.schema,
table: options.table,
records: options.records.map((record) => omitBy(record, isNil)),
})

const {
data: { update_hashes },
} = await this.client({ data })
return (update_hashes ?? []) as string[]
}

async upsert<T>(options: { table: string; records: T[] }) {
const data = JSON.stringify({
operation: "upsert",
schema: this.schema,
table: options.table,
records: omitBy(options.records, isNil),
})

const {
data: { upserted_hashes },
} = await this.client({ data })
return (upserted_hashes ?? []) as string[]
}

async delete(ids: string[], options: { table: string }) {
const data = JSON.stringify({
operation: "delete",
schema: this.schema,
table: options.table,
hash_values: ids,
})

const {
data: { deleted_hashes },
} = await this.client({ data })
return (deleted_hashes ?? []) as string[]
}
}
export const harperdb = new HarperDB({
url: process.env.DB_URL ?? "",
token: process.env.DB_TOKEN,
})
12 changes: 6 additions & 6 deletions lib/middlewares/authenticate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { NextApiRequest, NextApiResponse } from "next"
import { NextMiddleware, use } from "next-api-middleware"
import { Session } from "next-auth"
import { getSession } from "next-auth/client"
import { HarperDB } from "../harperDB"
import { AppUser, IAppUser } from "../models"
import { harperdb } from "../harperDB"
import { AppUser, AppUserJSON } from "../models"

export type NextApiRequestWithAuth = NextApiRequest & {
session: Session
Expand All @@ -17,16 +17,16 @@ const authenticate = async (req: NextApiRequestWithAuth, res: NextApiResponse, n
return res.status(403).json({ message: "You are not allowed to perform this action." })
}

const db = new HarperDB("dev")

const [user] = await db.findByIds<IAppUser>([session.id], { table: "users" })
const {
records: [user],
} = (await harperdb.searchByHash([session.id], { schema: "dev", table: "users" })) as unknown as { records: AppUserJSON[] }

if (!user) {
return res.status(403).json({ message: "You are not allowed to perform this action." })
}

req.session = session
req.user = new AppUser(user)
req.user = AppUser.fromJSON(user)

return next()
}
Expand Down
4 changes: 2 additions & 2 deletions lib/models/appUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { IUsage, Usage } from "./usage"
import pricing from "../../pricing.json"

export interface IAppUser {
id: string
id: string | number
name?: string
email?: string
isEmailVerified?: boolean
Expand All @@ -16,7 +16,7 @@ export interface IAppUser {
export type AppUserJSON = Omit<IAppUser, "subscription"> & { subscription: SubscriptionJSON }

export class AppUser implements IAppUser {
id: string
id: string | number

name?: string | undefined

Expand Down
16 changes: 8 additions & 8 deletions lib/models/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@ import format from "date-fns/format"
import { Plans } from "./subscription"

export interface IPayment {
id: string
userId: string
id: string | number
userId: string | number
plan: Plans
amount: number
currency: string
couponUsed?: string
discount?: number
razorpayOrderId: string
razorpayPaymentId: string
razorpayOrderId: string | number
razorpayPaymentId: string | number
createdAt?: string
updatedAt?: string
}

export type PaymentJSON = Omit<IPayment, "createdAt" | "updatedAt"> & { __createdtime__: string; __updatedtime__: string }

export class Payment implements IPayment {
id: string
id: string | number

userId: string
userId: string | number

plan: Plans

Expand All @@ -32,9 +32,9 @@ export class Payment implements IPayment {

discount?: number | undefined

razorpayOrderId: string
razorpayOrderId: string | number

razorpayPaymentId: string
razorpayPaymentId: string | number

createdAt?: string | undefined

Expand Down
Loading