Skip to content

Commit

Permalink
Merge pull request timothymiller#142 from rmarscher/lucia-1.0
Browse files Browse the repository at this point in the history
[lucia] Update lucia dependency to 3.0!
  • Loading branch information
timothymiller authored Feb 8, 2024
2 parents 855dd41 + 826902d commit 93c8ee3
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 27 deletions.
Binary file modified bun.lockb
Binary file not shown.
10 changes: 5 additions & 5 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"main": "src/index.ts",
"license": "MIT",
"scripts": {
"dev": "wrangler dev",
"dev": "wrangler dev --test-scheduled",
"types": "wrangler types",
"generate": "drizzle-kit generate:sqlite --schema=./src/db/schema.ts --out=./migrations",
"migrate": "wrangler d1 migrations apply production",
Expand All @@ -20,15 +20,15 @@
"@cloudflare/workers-wasi": "^0.0.5",
"@hono/trpc-server": "^0.1.0",
"@libsql/client": "^0.3.5",
"@lucia-auth/adapter-drizzle": "1.0.0-beta.2",
"@lucia-auth/adapter-drizzle": "1.0.0",
"@trpc/server": "^10.43.2",
"arctic": "0.10.2",
"arctic": "1.1.3",
"drizzle-orm": "^0.29.0",
"drizzle-valibot": "beta",
"hono": "^3.9.2",
"lucia": "3.0.0-beta.12",
"lucia": "3.0.1",
"miniflare": "3.20231025.1",
"oslo": "0.25.0",
"oslo": "1.0.3",
"superjson": "1.13.3",
"ts-pattern": "^5.0.5",
"valibot": "^0.20.1"
Expand Down
23 changes: 9 additions & 14 deletions packages/api/src/auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Adapter, DatabaseSessionAttributes, DatabaseUserAttributes, Lucia, TimeSpan } from 'lucia'
import { Adapter, Lucia, TimeSpan } from 'lucia'
import { DrizzleSQLiteAdapter } from '@lucia-auth/adapter-drizzle'
import { SessionTable, UserTable } from '../db/schema'
import { DB } from '../db/client'
Expand All @@ -21,15 +21,8 @@ export const getAllowedOriginHost = (app_url: string, request?: Request) => {
export const createAuth = (db: DB, appUrl: string) => {
// @ts-ignore Expect type errors because this is D1 and not SQLite... but it works
const adapter = new DrizzleSQLiteAdapter(db, SessionTable, UserTable)
// cast probably only needed until adapter-drizzle is updated
return new Lucia(adapter as Adapter, {
...getAuthOptions(appUrl),
})
}

export const getAuthOptions = (appUrl: string) => {
const env = !appUrl || appUrl.startsWith('http:') ? 'DEV' : 'PROD'
return {
return new Lucia(adapter as Adapter, {
getUserAttributes: (data: DatabaseUserAttributes) => {
return {
email: data.email || '',
Expand All @@ -54,15 +47,17 @@ export const getAuthOptions = (appUrl: string) => {
// experimental: {
// debugMode: true,
// },
}
})
}

declare module 'lucia' {
interface Register {
Lucia: ReturnType<typeof createAuth>
DatabaseSessionAttributes: DatabaseSessionAttributes
DatabaseUserAttributes: DatabaseUserAttributes
}
interface DatabaseSessionAttributes {}
interface DatabaseUserAttributes {
email: string | null
}
}
interface DatabaseSessionAttributes {}
interface DatabaseUserAttributes {
email: string | null
}
13 changes: 7 additions & 6 deletions packages/api/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export interface ApiContextProps {

export const createContext = async (
env: Bindings,
context: HonoContext,
resHeaders: Headers
context?: HonoContext,
resHeaders?: Headers
): Promise<ApiContextProps> => {
if (!env.DB) {
throw new Error('Database binding is undefined')
Expand All @@ -36,6 +36,7 @@ export const createContext = async (
// This was used with supabase auth,
// For lucia, we pass just the session ID rather than a JWT
async function getUser() {
if (!context) return null
const sessionToken = context.req.header('Authorization')?.split(' ')[1]

if (sessionToken !== undefined && sessionToken !== 'undefined') {
Expand Down Expand Up @@ -65,7 +66,7 @@ export const createContext = async (
// const user = await getUser()

const auth = createAuth(db, env.APP_URL)
const enableTokens = Boolean(context.req.header('x-enable-tokens'))
const enableTokens = Boolean(context?.req.header('x-enable-tokens'))

async function getSession() {
let user: User | undefined
Expand All @@ -75,7 +76,7 @@ export const createContext = async (
session,
}

if (!context.req) return res
if (!context?.req) return res

const cookieSessionId = getCookie(context, auth.sessionCookieName)
const bearerSessionId = enableTokens && context.req.header('authorization')?.split(' ')[1]
Expand Down Expand Up @@ -123,13 +124,13 @@ export const createContext = async (
return {
db,
auth,
req: context.req,
req: context?.req,
c: context,
session,
user,
enableTokens,
setCookie: (value) => {
resHeaders.append('set-cookie', value)
resHeaders?.append('set-cookie', value)
},
env,
}
Expand Down
18 changes: 18 additions & 0 deletions packages/api/src/scheduled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { match } from 'ts-pattern'
import { createContext } from './context'
import { Bindings } from './worker'

const scheduled: ExportedHandlerScheduledHandler<Bindings> = async (event, env, _) => {
console.log('Running cron', event.cron)
const ctx = await createContext(env)
await match({ event, ctx })
.with({ event: { cron: '15 2 * * sat' } }, async ({ ctx }) => {
await ctx.auth.deleteExpiredSessions()
console.log('Deleted expired sessions')
})
.otherwise(async () => {
console.log('Unhandled cron event', event)
})
}

export default scheduled
2 changes: 1 addition & 1 deletion packages/api/src/utils/id.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { generateRandomString, alphabet } from 'oslo/random'
import { generateRandomString, alphabet } from 'oslo/crypto'

export const idAlphabet = alphabet('a-z', '0-9')
export const codeAlphabet = '0123456789'
Expand Down
6 changes: 5 additions & 1 deletion packages/api/src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { appRouter } from '@t4/api/src/router'
import { cors } from 'hono/cors'
import { createContext } from '@t4/api/src/context'
import { trpcServer } from '@hono/trpc-server'
import scheduled from './scheduled'

export type Bindings = Env & {
JWT_VERIFICATION_KEY: string
Expand Down Expand Up @@ -57,4 +58,7 @@ app.use('/trpc/*', async (c, next) => {
})(c, next)
})

export default app
export default {
...app,
scheduled,
}
12 changes: 12 additions & 0 deletions packages/api/wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ database_name = "production"
database_id = "aa5e3923-0f1b-469a-8bb8-d10fb866efe0"
migrations_dir = "migrations"

[triggers]
# Schedule cron triggers:
# examples:
# - At every 3rd minute
# - At 3PM on first day of the month
# - At 11:59PM on the last weekday of the month
# crons = [ "*/3 * * * *", "0 15 1 * *", "59 23 LW * *" ]
# For now, we're using "15 2 * * sat" to delete expired sessions from the database weekly
# Test locally with "http://localhost:8787/__scheduled?cron=15+2+*+*+sat"
crons = [ "15 2 * * sat" ]


# The necessary secrets are:
# - APP_URL - for preventing CORS errors
# - JWT_VERIFICATION_KEY - for Supabase @link https://supabase.com
Expand Down

0 comments on commit 93c8ee3

Please sign in to comment.