Some checks failed
Test and deploy staging / staging (push) Failing after 14s
- 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>
124 lines
3.7 KiB
TypeScript
124 lines
3.7 KiB
TypeScript
// 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]
|
||
})
|
||
}));
|