Files
esports/src/lib/server/db/auth.schema.ts
Stan Runge d5448d9a94
Some checks failed
Test and deploy staging / staging (push) Failing after 14s
feat!: upgrade to SvelteKit 3 and adapter-bun
- run sv migrate sveltekit-3: config moves into vite.config.ts, $lib becomes
  #lib, $env/dynamic becomes $app/env/private via src/env.ts, $app/environment
  becomes $app/env, hook types move to @sveltejs/kit/hooks
- env vars stay optional (the migrator defaulted them to ''), and BANCHO_MODE,
  which it missed, is declared and passed to simulatorEnabled
- handleError only logs and masks unknown errors; Kit 3 now routes 404s and
  error(...) through it too
- json()/text() become Response.json()/new Response(); goto keepFocus/noScroll
  becomes reset: false; invalidateAll becomes refreshAll; page.url is copied
  before mutating
- replace adapter-node with @sveltejs/adapter-bun; prod-server.ts wraps
  Bun.serve to add native WebSockets (bunSockets) for /ws paths, since the
  generated server has no websocket option
- drop the Kit readdir patch: Kit 3 sorts route entries itself
- match view and broadcast pages use the live score modules

BREAKING CHANGE: requires SvelteKit 3, TypeScript 6 and Bun 1.4; the build
output is build/index.js from adapter-bun, started through prod-server.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:02:53 +00:00

124 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/lib/server/db/auth.schema.ts
import { relations } from 'drizzle-orm';
import {
pgTable,
text,
timestamp,
boolean,
index,
integer,
uniqueIndex
} from 'drizzle-orm/pg-core';
import { jsonb } from './jsonb';
import type { ConnectionProfile } from '#lib/auth-identity.js';
export const user = pgTable('user', {
id: text('id').primaryKey(),
name: text('name').notNull(),
// Only actual contact addresses belong here. OAuth identity lives in account.
email: text('contact_email').unique(),
// Better Auth's required email field is mapped to this private compatibility field.
authEmail: text('email').notNull().unique(),
emailVerified: boolean('email_verified').default(false).notNull(),
image: text('image'),
// ── Staff role: 'player' | 'referee' | 'admin' ──
role: text('role').default('player').notNull(),
rootAdmin: boolean('root_admin').default(false).notNull(),
mergedIntoUserId: text('merged_into_user_id'),
osuId: integer('osu_id'),
countryCode: text('country_code'),
discordId: text('discord_id'),
bannedAt: timestamp('banned_at', { withTimezone: true }),
timezone: text('timezone'),
/** Local hours (0–23) the player can play. Empty means no preference. */
availableHours: jsonb('available_hours').$type<number[]>(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.defaultNow()
.$onUpdate(() => new Date())
.notNull()
});
export const session = pgTable(
'session',
{
id: text('id').primaryKey(),
expiresAt: timestamp('expires_at').notNull(),
token: text('token').notNull().unique(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.$onUpdate(() => new Date())
.notNull(),
ipAddress: text('ip_address'),
userAgent: text('user_agent'),
userId: text('user_id')
.notNull()
.references(() => user.id, { onDelete: 'cascade' })
},
(table) => [index('session_userId_idx').on(table.userId)]
);
export const account = pgTable(
'account',
{
id: text('id').primaryKey(),
accountId: text('account_id').notNull(),
providerId: text('provider_id').notNull(),
userId: text('user_id')
.notNull()
.references(() => user.id, { onDelete: 'cascade' }),
accessToken: text('access_token'),
refreshToken: text('refresh_token'),
idToken: text('id_token'),
accessTokenExpiresAt: timestamp('access_token_expires_at'),
refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
scope: text('scope'),
password: text('password'),
profile: jsonb('profile').$type<ConnectionProfile>(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.$onUpdate(() => new Date())
.notNull()
},
(table) => [
index('account_userId_idx').on(table.userId),
uniqueIndex('account_provider_identity_idx').on(table.providerId, table.accountId),
uniqueIndex('account_user_provider_idx').on(table.userId, table.providerId)
]
);
export const verification = pgTable(
'verification',
{
id: text('id').primaryKey(),
identifier: text('identifier').notNull(),
value: text('value').notNull(),
expiresAt: timestamp('expires_at').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.defaultNow()
.$onUpdate(() => new Date())
.notNull()
},
(table) => [index('verification_identifier_idx').on(table.identifier)]
);
export const userRelations = relations(user, ({ many }) => ({
sessions: many(session),
accounts: many(account)
}));
export const sessionRelations = relations(session, ({ one }) => ({
user: one(user, {
fields: [session.userId],
references: [user.id]
})
}));
export const accountRelations = relations(account, ({ one }) => ({
user: one(user, {
fields: [account.userId],
references: [user.id]
})
}));