AHHHH Idekgit add -Agit add -A
This commit is contained in:
parent
b2df111d5a
commit
b7990488d3
3
.gitignore
vendored
3
.gitignore
vendored
@ -31,6 +31,9 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# Apple Private Key
|
||||||
|
*.p8
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
|
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
|
||||||
.env
|
.env
|
||||||
|
33
package.json
33
package.json
@ -11,35 +11,42 @@
|
|||||||
"db:studio": "drizzle-kit studio",
|
"db:studio": "drizzle-kit studio",
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"start": "next start"
|
"start": "next start",
|
||||||
|
"generate-apple-secret": "tsx src/scripts/generate_apple_secret.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth/drizzle-adapter": "^1.4.2",
|
||||||
"@t3-oss/env-nextjs": "^0.10.1",
|
"@t3-oss/env-nextjs": "^0.10.1",
|
||||||
|
"@types/jsonwebtoken": "^9.0.6",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
"drizzle-orm": "^0.30.10",
|
"drizzle-orm": "^0.30.10",
|
||||||
"geist": "^1.3.0",
|
"geist": "^1.3.1",
|
||||||
"next": "^14.2.4",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"next": "^14.2.5",
|
||||||
"next-auth": "5.0.0-beta.20",
|
"next-auth": "5.0.0-beta.20",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"zod": "^3.23.3"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/eslint": "^8.56.10",
|
"@types/eslint": "^8.56.11",
|
||||||
"@types/node": "^20.14.10",
|
"@types/node": "^20.14.14",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||||
"@typescript-eslint/parser": "^7.1.1",
|
"@typescript-eslint/parser": "^7.18.0",
|
||||||
"drizzle-kit": "^0.21.4",
|
"drizzle-kit": "^0.21.4",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-next": "^14.2.4",
|
"eslint-config-next": "^14.2.5",
|
||||||
"eslint-plugin-drizzle": "^0.2.3",
|
"eslint-plugin-drizzle": "^0.2.3",
|
||||||
"postcss": "^8.4.39",
|
"postcss": "^8.4.41",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.8",
|
||||||
"typescript": "^5.5.3"
|
"ts-node": "^10.9.2",
|
||||||
|
"tsx": "^4.16.5",
|
||||||
|
"typescript": "^5.5.4"
|
||||||
},
|
},
|
||||||
"ct3aMetadata": {
|
"ct3aMetadata": {
|
||||||
"initVersion": "7.36.2"
|
"initVersion": "7.36.2"
|
||||||
|
533
pnpm-lock.yaml
533
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,9 @@
|
|||||||
import NextAuth from "next-auth"
|
import NextAuth from "next-auth"
|
||||||
|
import { DrizzleAdapter } from "@auth/drizzle-adapter"
|
||||||
|
import { db } from "~/server/db/schema"
|
||||||
|
import Apple from "next-auth/providers/apple"
|
||||||
|
|
||||||
export const { handlers, signIn, signOut, auth } = NextAuth({
|
export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||||
providers: [],
|
adapter: DrizzleAdapter(db),
|
||||||
|
providers: [Apple],
|
||||||
})
|
})
|
||||||
|
57
src/scripts/generate_apple_secret.ts
Normal file
57
src/scripts/generate_apple_secret.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
|
// Load environment variables from .env file
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
// Type definitions for Apple Auth Configuration
|
||||||
|
interface AppleAuthConfig {
|
||||||
|
teamId: string;
|
||||||
|
clientId: string;
|
||||||
|
keyId: string;
|
||||||
|
privateKeyPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the directory name of the current module
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
const generateAppleSecret = (config: AppleAuthConfig): string => {
|
||||||
|
const { teamId, clientId, keyId, privateKeyPath } = config;
|
||||||
|
|
||||||
|
const privateKey = fs.readFileSync(privateKeyPath).toString();
|
||||||
|
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
iss: teamId,
|
||||||
|
iat: now,
|
||||||
|
exp: now + 86400 * 180, // 180 days
|
||||||
|
aud: 'https://appleid.apple.com',
|
||||||
|
sub: clientId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
alg: 'ES256',
|
||||||
|
kid: keyId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return jwt.sign(payload, privateKey, { algorithm: 'ES256', header: headers });
|
||||||
|
};
|
||||||
|
|
||||||
|
const config: AppleAuthConfig = {
|
||||||
|
teamId: process.env.APPLE_TEAM_ID ?? '',
|
||||||
|
clientId: process.env.AUTH_APPLE_ID ?? '',
|
||||||
|
keyId: process.env.APPLE_KEY_ID ?? '',
|
||||||
|
privateKeyPath: path.resolve(__dirname, process.env.APPLE_PRIVATE_KEY_PATH ?? ''),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!config.teamId || !config.clientId || !config.keyId || !config.privateKeyPath) {
|
||||||
|
console.error('Missing necessary Apple configuration');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const appleSecret = generateAppleSecret(config);
|
||||||
|
console.log(`Your Apple Secret:\n\n${appleSecret}\n`);
|
@ -1,36 +1,93 @@
|
|||||||
// Example model schema from the Drizzle docs
|
|
||||||
// https://orm.drizzle.team/docs/sql-schema-declaration
|
|
||||||
|
|
||||||
import { sql } from "drizzle-orm";
|
|
||||||
import {
|
import {
|
||||||
index,
|
boolean,
|
||||||
pgTableCreator,
|
|
||||||
serial,
|
|
||||||
timestamp,
|
timestamp,
|
||||||
varchar,
|
pgTable,
|
||||||
} from "drizzle-orm/pg-core";
|
text,
|
||||||
|
primaryKey,
|
||||||
|
integer,
|
||||||
|
} from "drizzle-orm/pg-core"
|
||||||
|
import postgres from "postgres"
|
||||||
|
import { drizzle } from "drizzle-orm/postgres-js"
|
||||||
|
import type { AdapterAccountType } from "next-auth/adapters"
|
||||||
|
|
||||||
/**
|
const connectionString = process.env.DATABASE_URL ?? "";
|
||||||
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
|
const pool = postgres(connectionString, { max: 1 })
|
||||||
* database instance for multiple projects.
|
|
||||||
*
|
|
||||||
* @see https://orm.drizzle.team/docs/goodies#multi-project-schema
|
|
||||||
*/
|
|
||||||
export const createTable = pgTableCreator((name) => `rent_portal_${name}`);
|
|
||||||
|
|
||||||
export const posts = createTable(
|
export const db = drizzle(pool)
|
||||||
"post",
|
|
||||||
|
export const users = pgTable("user", {
|
||||||
|
id: text("id")
|
||||||
|
.primaryKey()
|
||||||
|
.$defaultFn(() => crypto.randomUUID()),
|
||||||
|
name: text("name"),
|
||||||
|
email: text("email").unique(),
|
||||||
|
emailVerified: timestamp("emailVerified", { mode: "date" }),
|
||||||
|
image: text("image"),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const accounts = pgTable(
|
||||||
|
"account",
|
||||||
{
|
{
|
||||||
id: serial("id").primaryKey(),
|
userId: text("userId")
|
||||||
name: varchar("name", { length: 256 }),
|
.notNull()
|
||||||
createdAt: timestamp("created_at", { withTimezone: true })
|
.references(() => users.id, { onDelete: "cascade" }),
|
||||||
.default(sql`CURRENT_TIMESTAMP`)
|
type: text("type").$type<AdapterAccountType>().notNull(),
|
||||||
.notNull(),
|
provider: text("provider").notNull(),
|
||||||
updatedAt: timestamp("updated_at", { withTimezone: true }).$onUpdate(
|
providerAccountId: text("providerAccountId").notNull(),
|
||||||
() => new Date()
|
refresh_token: text("refresh_token"),
|
||||||
),
|
access_token: text("access_token"),
|
||||||
|
expires_at: integer("expires_at"),
|
||||||
|
token_type: text("token_type"),
|
||||||
|
scope: text("scope"),
|
||||||
|
id_token: text("id_token"),
|
||||||
|
session_state: text("session_state"),
|
||||||
},
|
},
|
||||||
(example) => ({
|
(account) => ({
|
||||||
nameIndex: index("name_idx").on(example.name),
|
compoundKey: primaryKey({
|
||||||
|
columns: [account.provider, account.providerAccountId],
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
|
export const sessions = pgTable("session", {
|
||||||
|
sessionToken: text("sessionToken").primaryKey(),
|
||||||
|
userId: text("userId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: "cascade" }),
|
||||||
|
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const verificationTokens = pgTable(
|
||||||
|
"verificationToken",
|
||||||
|
{
|
||||||
|
identifier: text("identifier").notNull(),
|
||||||
|
token: text("token").notNull(),
|
||||||
|
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||||
|
},
|
||||||
|
(verificationToken) => ({
|
||||||
|
compositePk: primaryKey({
|
||||||
|
columns: [verificationToken.identifier, verificationToken.token],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export const authenticators = pgTable(
|
||||||
|
"authenticator",
|
||||||
|
{
|
||||||
|
credentialID: text("credentialID").notNull().unique(),
|
||||||
|
userId: text("userId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: "cascade" }),
|
||||||
|
providerAccountId: text("providerAccountId").notNull(),
|
||||||
|
credentialPublicKey: text("credentialPublicKey").notNull(),
|
||||||
|
counter: integer("counter").notNull(),
|
||||||
|
credentialDeviceType: text("credentialDeviceType").notNull(),
|
||||||
|
credentialBackedUp: boolean("credentialBackedUp").notNull(),
|
||||||
|
transports: text("transports"),
|
||||||
|
},
|
||||||
|
(authenticator) => ({
|
||||||
|
compositePK: primaryKey({
|
||||||
|
columns: [authenticator.userId, authenticator.credentialID],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
@ -36,7 +36,8 @@
|
|||||||
"**/*.tsx",
|
"**/*.tsx",
|
||||||
"**/*.cjs",
|
"**/*.cjs",
|
||||||
"**/*.js",
|
"**/*.js",
|
||||||
".next/types/**/*.ts"
|
".next/types/**/*.ts",
|
||||||
|
"src/scripts/*"
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user