sitepaige-mcp-server 0.7.7 → 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ import { NextResponse } from 'next/server';
9
9
  import * as crypto from 'node:crypto';
10
10
 
11
11
  import { db_init, db_query } from '../../db';
12
- import { upsertUser, ensureAuthTables, storeOAuthToken, validateSession, rotateSession } from '../../db-users';
12
+ import { upsertUser, storeOAuthToken, validateSession, rotateSession } from '../../db-users';
13
13
  import { validateCsrfToken } from '../../csrf';
14
14
 
15
15
  type OAuthProvider = 'google' | 'facebook' | 'apple' | 'github';
@@ -29,9 +29,6 @@ const USER_INFO_ENDPOINTS = {
29
29
  };
30
30
 
31
31
  export async function POST(request: Request) {
32
- // Ensure authentication tables exist
33
- await ensureAuthTables();
34
-
35
32
  const db = await db_init();
36
33
 
37
34
  try {
@@ -214,9 +211,6 @@ export async function POST(request: Request) {
214
211
  }
215
212
 
216
213
  export async function GET() {
217
- // Ensure authentication tables exist
218
- await ensureAuthTables();
219
-
220
214
  try {
221
215
  // Get session token from cookies
222
216
  const sessionCookie = await cookies();
@@ -308,9 +302,6 @@ export async function DELETE(request: Request) {
308
302
  );
309
303
  }
310
304
 
311
- // Ensure authentication tables exist
312
- await ensureAuthTables();
313
-
314
305
  const db = await db_init();
315
306
 
316
307
  try {
@@ -105,6 +105,60 @@ export async function db_query(
105
105
  * @returns SQL string for creating the table
106
106
  */
107
107
  export function db_migrate(model: Model, dbType: string): string {
108
+ // Special handling for auth tables - create them first
109
+ if (model.name === '__auth_tables__') {
110
+ return `-- Users table (required for authentication)
111
+ CREATE TABLE IF NOT EXISTS \`Users\` (
112
+ \`userid\` VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
113
+ \`OAuthID\` VARCHAR(255) NOT NULL UNIQUE,
114
+ \`Source\` VARCHAR(20) NOT NULL CHECK(\`Source\` IN ('google', 'facebook', 'apple', 'github')),
115
+ \`UserName\` VARCHAR(255) NOT NULL,
116
+ \`Email\` VARCHAR(255),
117
+ \`AvatarURL\` TEXT,
118
+ \`UserLevel\` INTEGER NOT NULL DEFAULT 1 CHECK(\`UserLevel\` IN (0, 1, 2)),
119
+ \`UserTier\` INTEGER NOT NULL DEFAULT 0,
120
+ \`LastLoginDate\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
121
+ \`CreatedDate\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
122
+ \`IsActive\` BOOLEAN NOT NULL DEFAULT true
123
+ );
124
+
125
+ -- Indexes for Users table
126
+ CREATE INDEX idx_users_oauthid ON \`Users\`(\`OAuthID\`);
127
+ CREATE INDEX idx_users_email ON \`Users\`(\`Email\`);
128
+ CREATE INDEX idx_users_usertier ON \`Users\`(\`UserTier\`);
129
+
130
+ -- UserSession table
131
+ CREATE TABLE IF NOT EXISTS \`UserSession\` (
132
+ \`ID\` VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
133
+ \`SessionToken\` VARCHAR(255) NOT NULL UNIQUE,
134
+ \`userid\` VARCHAR(36) NOT NULL,
135
+ \`ExpirationDate\` DATETIME NOT NULL,
136
+ FOREIGN KEY (\`userid\`) REFERENCES \`Users\`(\`userid\`) ON DELETE CASCADE
137
+ );
138
+
139
+ -- Indexes for UserSession table
140
+ CREATE INDEX idx_session_token ON \`UserSession\`(\`SessionToken\`);
141
+ CREATE INDEX idx_session_user ON \`UserSession\`(\`userid\`);
142
+ CREATE INDEX idx_session_expiry ON \`UserSession\`(\`ExpirationDate\`);
143
+
144
+ -- OAuthTokens table
145
+ CREATE TABLE IF NOT EXISTS \`OAuthTokens\` (
146
+ \`ID\` VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
147
+ \`userid\` VARCHAR(36) NOT NULL,
148
+ \`Provider\` VARCHAR(20) NOT NULL CHECK(\`Provider\` IN ('google', 'facebook', 'apple', 'github')),
149
+ \`AccessToken\` TEXT NOT NULL,
150
+ \`RefreshToken\` TEXT,
151
+ \`ExpiresAt\` DATETIME,
152
+ \`CreatedAt\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
153
+ \`UpdatedAt\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
154
+ FOREIGN KEY (\`userid\`) REFERENCES \`Users\`(\`userid\`) ON DELETE CASCADE
155
+ );
156
+
157
+ -- Indexes for OAuthTokens table
158
+ CREATE INDEX idx_oauth_user ON \`OAuthTokens\`(\`userid\`);
159
+ CREATE INDEX idx_oauth_provider ON \`OAuthTokens\`(\`userid\`, \`Provider\`);`;
160
+ }
161
+
108
162
  const sanitizedTableName = model.name;
109
163
 
110
164
  // Start with the model's fields
@@ -116,6 +116,60 @@ export async function db_query(
116
116
  * @returns SQL string for creating the table
117
117
  */
118
118
  export function db_migrate(model: Model, dbType: string): string {
119
+ // Special handling for auth tables - create them first
120
+ if (model.name === '__auth_tables__') {
121
+ return `-- Users table (required for authentication)
122
+ CREATE TABLE IF NOT EXISTS "Users" (
123
+ "userid" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
124
+ "OAuthID" TEXT NOT NULL UNIQUE,
125
+ "Source" TEXT NOT NULL CHECK("Source" IN ('google', 'facebook', 'apple', 'github')),
126
+ "UserName" TEXT NOT NULL,
127
+ "Email" TEXT,
128
+ "AvatarURL" TEXT,
129
+ "UserLevel" INTEGER NOT NULL DEFAULT 1 CHECK("UserLevel" IN (0, 1, 2)),
130
+ "UserTier" INTEGER NOT NULL DEFAULT 0,
131
+ "LastLoginDate" TIMESTAMP NOT NULL DEFAULT NOW(),
132
+ "CreatedDate" TIMESTAMP NOT NULL DEFAULT NOW(),
133
+ "IsActive" BOOLEAN NOT NULL DEFAULT true
134
+ );
135
+
136
+ -- Indexes for Users table
137
+ CREATE INDEX IF NOT EXISTS idx_users_oauthid ON "Users"("OAuthID");
138
+ CREATE INDEX IF NOT EXISTS idx_users_email ON "Users"("Email");
139
+ CREATE INDEX IF NOT EXISTS idx_users_usertier ON "Users"("UserTier");
140
+
141
+ -- UserSession table
142
+ CREATE TABLE IF NOT EXISTS "UserSession" (
143
+ "ID" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
144
+ "SessionToken" VARCHAR(255) NOT NULL UNIQUE,
145
+ "userid" UUID NOT NULL,
146
+ "ExpirationDate" TIMESTAMP NOT NULL,
147
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
148
+ );
149
+
150
+ -- Indexes for UserSession table
151
+ CREATE INDEX IF NOT EXISTS idx_session_token ON "UserSession"("SessionToken");
152
+ CREATE INDEX IF NOT EXISTS idx_session_user ON "UserSession"("userid");
153
+ CREATE INDEX IF NOT EXISTS idx_session_expiry ON "UserSession"("ExpirationDate");
154
+
155
+ -- OAuthTokens table
156
+ CREATE TABLE IF NOT EXISTS "OAuthTokens" (
157
+ "ID" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
158
+ "userid" UUID NOT NULL,
159
+ "Provider" VARCHAR(20) NOT NULL CHECK("Provider" IN ('google', 'facebook', 'apple', 'github')),
160
+ "AccessToken" TEXT NOT NULL,
161
+ "RefreshToken" TEXT,
162
+ "ExpiresAt" TIMESTAMP,
163
+ "CreatedAt" TIMESTAMP NOT NULL DEFAULT NOW(),
164
+ "UpdatedAt" TIMESTAMP NOT NULL DEFAULT NOW(),
165
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
166
+ );
167
+
168
+ -- Indexes for OAuthTokens table
169
+ CREATE INDEX IF NOT EXISTS idx_oauth_user ON "OAuthTokens"("userid");
170
+ CREATE INDEX IF NOT EXISTS idx_oauth_provider ON "OAuthTokens"("userid", "Provider");`;
171
+ }
172
+
119
173
  const sanitizedTableName = model.name;
120
174
 
121
175
  // Start with the model's fields
@@ -181,6 +181,60 @@ export async function db_query(
181
181
  * @returns SQL string for creating the table
182
182
  */
183
183
  export function db_migrate(model: Model, dbType: string): string {
184
+ // Special handling for auth tables - create them first
185
+ if (model.name === '__auth_tables__') {
186
+ return `-- Users table (required for authentication)
187
+ CREATE TABLE IF NOT EXISTS "Users" (
188
+ "userid" TEXT PRIMARY KEY,
189
+ "OAuthID" TEXT NOT NULL UNIQUE,
190
+ "Source" TEXT NOT NULL CHECK("Source" IN ('google', 'facebook', 'apple', 'github')),
191
+ "UserName" TEXT NOT NULL,
192
+ "Email" TEXT,
193
+ "AvatarURL" TEXT,
194
+ "UserLevel" INTEGER NOT NULL DEFAULT 1 CHECK("UserLevel" IN (0, 1, 2)),
195
+ "UserTier" INTEGER NOT NULL DEFAULT 0,
196
+ "LastLoginDate" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
197
+ "CreatedDate" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
198
+ "IsActive" INTEGER NOT NULL DEFAULT 1
199
+ );
200
+
201
+ -- Indexes for Users table
202
+ CREATE INDEX IF NOT EXISTS idx_users_oauthid ON "Users"("OAuthID");
203
+ CREATE INDEX IF NOT EXISTS idx_users_email ON "Users"("Email");
204
+ CREATE INDEX IF NOT EXISTS idx_users_usertier ON "Users"("UserTier");
205
+
206
+ -- UserSession table
207
+ CREATE TABLE IF NOT EXISTS "UserSession" (
208
+ "ID" TEXT PRIMARY KEY,
209
+ "SessionToken" TEXT NOT NULL UNIQUE,
210
+ "userid" TEXT NOT NULL,
211
+ "ExpirationDate" TEXT NOT NULL,
212
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
213
+ );
214
+
215
+ -- Indexes for UserSession table
216
+ CREATE INDEX IF NOT EXISTS idx_session_token ON "UserSession"("SessionToken");
217
+ CREATE INDEX IF NOT EXISTS idx_session_user ON "UserSession"("userid");
218
+ CREATE INDEX IF NOT EXISTS idx_session_expiry ON "UserSession"("ExpirationDate");
219
+
220
+ -- OAuthTokens table
221
+ CREATE TABLE IF NOT EXISTS "OAuthTokens" (
222
+ "ID" TEXT PRIMARY KEY,
223
+ "userid" TEXT NOT NULL,
224
+ "Provider" TEXT NOT NULL CHECK("Provider" IN ('google', 'facebook', 'apple', 'github')),
225
+ "AccessToken" TEXT NOT NULL,
226
+ "RefreshToken" TEXT,
227
+ "ExpiresAt" TEXT,
228
+ "CreatedAt" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
229
+ "UpdatedAt" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
230
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
231
+ );
232
+
233
+ -- Indexes for OAuthTokens table
234
+ CREATE INDEX IF NOT EXISTS idx_oauth_user ON "OAuthTokens"("userid");
235
+ CREATE INDEX IF NOT EXISTS idx_oauth_provider ON "OAuthTokens"("userid", "Provider");`;
236
+ }
237
+
184
238
  const sanitizedTableName = model.name;
185
239
 
186
240
  // Start with the model's fields
@@ -39,147 +39,29 @@ export interface OAuthToken {
39
39
  }
40
40
 
41
41
  /**
42
- * Ensure the Users table exists with the correct schema
42
+ * @deprecated Table creation is now handled by db_migrate in the database implementation files
43
43
  */
44
44
  export async function ensureUsersTable(): Promise<void> {
45
- // Skip table creation during build time
46
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
47
- return;
48
- }
49
-
50
- const client = await db_init();
51
-
52
- // Create or migrate the Users table
53
- const createTableSQL = `
54
- CREATE TABLE IF NOT EXISTS Users (
55
- userid VARCHAR(36) PRIMARY KEY NOT NULL,
56
- OAuthID VARCHAR(255) NOT NULL UNIQUE,
57
- Source VARCHAR(20) NOT NULL CHECK(Source IN ('google', 'facebook', 'apple', 'github')),
58
- UserName VARCHAR(255) NOT NULL,
59
- Email VARCHAR(255),
60
- AvatarURL TEXT,
61
- UserLevel INTEGER NOT NULL DEFAULT 1 CHECK(UserLevel IN (0, 1, 2)),
62
- UserTier INTEGER NOT NULL DEFAULT 0,
63
- LastLoginDate DATETIME NOT NULL,
64
- CreatedDate DATETIME NOT NULL,
65
- IsActive BOOLEAN NOT NULL DEFAULT true
66
- );
67
-
68
- CREATE INDEX IF NOT EXISTS idx_users_oauth ON Users(OAuthID);
69
- CREATE INDEX IF NOT EXISTS idx_users_permission ON Users(UserLevel);
70
- `;
71
-
72
- // Split and execute statements separately for compatibility
73
- const statements = createTableSQL.split(';').map(s => s.trim()).filter(s => s.length > 0);
74
- for (const statement of statements) {
75
- try {
76
- await db_query(client, statement);
77
- } catch (error) {
78
- // Ignore errors for index creation as some databases don't support IF NOT EXISTS for indexes
79
- if (!statement.includes('CREATE INDEX')) {
80
- throw error;
81
- }
82
- }
83
- }
45
+ // No longer needed - Users table is created by db_migrate
46
+ return;
84
47
  }
85
48
 
86
49
  /**
87
- * Ensure the UserSession table exists
50
+ * @deprecated Table creation is now handled by db_migrate in the database implementation files
88
51
  */
89
52
  export async function ensureUserSessionTable(): Promise<void> {
90
- // Skip table creation during build time
91
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
92
- return;
93
- }
94
-
95
- const client = await db_init();
96
-
97
- const createTableSQL = `
98
- CREATE TABLE IF NOT EXISTS UserSession (
99
- ID VARCHAR(36) PRIMARY KEY NOT NULL,
100
- SessionToken VARCHAR(255) NOT NULL UNIQUE,
101
- userid VARCHAR(36) NOT NULL,
102
- ExpirationDate DATETIME NOT NULL,
103
- FOREIGN KEY (userid) REFERENCES Users(userid) ON DELETE CASCADE
104
- );
105
-
106
- CREATE INDEX IF NOT EXISTS idx_session_token ON UserSession(SessionToken);
107
- CREATE INDEX IF NOT EXISTS idx_session_user ON UserSession(userid);
108
- CREATE INDEX IF NOT EXISTS idx_session_expiry ON UserSession(ExpirationDate);
109
- `;
110
-
111
- // Split and execute statements separately for compatibility
112
- const statements = createTableSQL.split(';').map(s => s.trim()).filter(s => s.length > 0);
113
- for (const statement of statements) {
114
- try {
115
- await db_query(client, statement);
116
- } catch (error) {
117
- // Ignore errors for index creation as some databases don't support IF NOT EXISTS for indexes
118
- if (!statement.includes('CREATE INDEX')) {
119
- throw error;
120
- }
121
- }
122
- }
53
+ // No longer needed - UserSession table is created by db_migrate
54
+ return;
123
55
  }
124
56
 
125
57
  /**
126
- * Ensure the OAuthTokens table exists
58
+ * @deprecated Table creation is now handled by db_migrate in the database implementation files
127
59
  */
128
60
  export async function ensureOAuthTokensTable(): Promise<void> {
129
- // Skip table creation during build time
130
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
131
- return;
132
- }
133
-
134
- const client = await db_init();
135
-
136
- const createTableSQL = `
137
- CREATE TABLE IF NOT EXISTS OAuthTokens (
138
- ID VARCHAR(36) PRIMARY KEY NOT NULL,
139
- userid VARCHAR(36) NOT NULL,
140
- Provider VARCHAR(20) NOT NULL CHECK(Provider IN ('google', 'facebook', 'apple', 'github')),
141
- AccessToken TEXT NOT NULL,
142
- RefreshToken TEXT,
143
- ExpiresAt DATETIME,
144
- CreatedAt DATETIME NOT NULL,
145
- UpdatedAt DATETIME NOT NULL,
146
- FOREIGN KEY (userid) REFERENCES Users(userid) ON DELETE CASCADE
147
- );
148
-
149
- CREATE INDEX IF NOT EXISTS idx_oauth_user ON OAuthTokens(userid);
150
- CREATE INDEX IF NOT EXISTS idx_oauth_provider ON OAuthTokens(userid, Provider);
151
- `;
152
-
153
- // Split and execute statements separately for compatibility
154
- const statements = createTableSQL.split(';').map(s => s.trim()).filter(s => s.length > 0);
155
- for (const statement of statements) {
156
- try {
157
- await db_query(client, statement);
158
- } catch (error) {
159
- // Ignore errors for index creation as some databases don't support IF NOT EXISTS for indexes
160
- if (!statement.includes('CREATE INDEX')) {
161
- throw error;
162
- }
163
- }
164
- }
61
+ // No longer needed - OAuthTokens table is created by db_migrate
62
+ return;
165
63
  }
166
64
 
167
- /**
168
- * Ensure all authentication tables exist
169
- */
170
- export async function ensureAuthTables(): Promise<void> {
171
- // Skip table creation during build time
172
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
173
- return;
174
- }
175
-
176
- const client = await db_init();
177
-
178
- // IMPORTANT: Create Users table first since UserSession and OAuthTokens have foreign keys to it
179
- await ensureUsersTable();
180
- await ensureUserSessionTable();
181
- await ensureOAuthTokensTable();
182
- }
183
65
 
184
66
  /**
185
67
  * Get all users from the database
package/defaultapp/db.ts CHANGED
@@ -158,6 +158,27 @@ export async function initializeDatabase(
158
158
  const client = await db_init();
159
159
 
160
160
  try {
161
+ // Create auth tables first (Users, UserSession, OAuthTokens)
162
+ const authTablesModel: Model = {
163
+ id: '__auth_tables__',
164
+ name: '__auth_tables__',
165
+ fields: []
166
+ };
167
+ const authTablesSql = db_migrate(authTablesModel);
168
+
169
+ // Execute each statement separately for auth tables
170
+ const authStatements = authTablesSql.split(';').map(s => s.trim()).filter(s => s.length > 0);
171
+ for (const statement of authStatements) {
172
+ try {
173
+ await db_query(client, statement);
174
+ } catch (error) {
175
+ // Some databases might not support certain syntax, continue with other statements
176
+ if (!statement.includes('CREATE INDEX')) {
177
+ console.error('Error creating auth table:', error);
178
+ }
179
+ }
180
+ }
181
+
161
182
  // Create tables for each model
162
183
  for (const model of models) {
163
184
  const createTableSql = db_migrate(model);
@@ -9,7 +9,7 @@ import { NextResponse } from 'next/server';
9
9
  import * as crypto from 'node:crypto';
10
10
 
11
11
  import { db_init, db_query } from '../../db';
12
- import { upsertUser, ensureAuthTables, storeOAuthToken, validateSession, rotateSession } from '../../db-users';
12
+ import { upsertUser, storeOAuthToken, validateSession, rotateSession } from '../../db-users';
13
13
  import { validateCsrfToken } from '../../csrf';
14
14
 
15
15
  type OAuthProvider = 'google' | 'facebook' | 'apple' | 'github';
@@ -29,9 +29,6 @@ const USER_INFO_ENDPOINTS = {
29
29
  };
30
30
 
31
31
  export async function POST(request: Request) {
32
- // Ensure authentication tables exist
33
- await ensureAuthTables();
34
-
35
32
  const db = await db_init();
36
33
 
37
34
  try {
@@ -214,9 +211,6 @@ export async function POST(request: Request) {
214
211
  }
215
212
 
216
213
  export async function GET() {
217
- // Ensure authentication tables exist
218
- await ensureAuthTables();
219
-
220
214
  try {
221
215
  // Get session token from cookies
222
216
  const sessionCookie = await cookies();
@@ -308,9 +302,6 @@ export async function DELETE(request: Request) {
308
302
  );
309
303
  }
310
304
 
311
- // Ensure authentication tables exist
312
- await ensureAuthTables();
313
-
314
305
  const db = await db_init();
315
306
 
316
307
  try {
@@ -105,6 +105,60 @@ export async function db_query(
105
105
  * @returns SQL string for creating the table
106
106
  */
107
107
  export function db_migrate(model: Model, dbType: string): string {
108
+ // Special handling for auth tables - create them first
109
+ if (model.name === '__auth_tables__') {
110
+ return `-- Users table (required for authentication)
111
+ CREATE TABLE IF NOT EXISTS \`Users\` (
112
+ \`userid\` VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
113
+ \`OAuthID\` VARCHAR(255) NOT NULL UNIQUE,
114
+ \`Source\` VARCHAR(20) NOT NULL CHECK(\`Source\` IN ('google', 'facebook', 'apple', 'github')),
115
+ \`UserName\` VARCHAR(255) NOT NULL,
116
+ \`Email\` VARCHAR(255),
117
+ \`AvatarURL\` TEXT,
118
+ \`UserLevel\` INTEGER NOT NULL DEFAULT 1 CHECK(\`UserLevel\` IN (0, 1, 2)),
119
+ \`UserTier\` INTEGER NOT NULL DEFAULT 0,
120
+ \`LastLoginDate\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
121
+ \`CreatedDate\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
122
+ \`IsActive\` BOOLEAN NOT NULL DEFAULT true
123
+ );
124
+
125
+ -- Indexes for Users table
126
+ CREATE INDEX idx_users_oauthid ON \`Users\`(\`OAuthID\`);
127
+ CREATE INDEX idx_users_email ON \`Users\`(\`Email\`);
128
+ CREATE INDEX idx_users_usertier ON \`Users\`(\`UserTier\`);
129
+
130
+ -- UserSession table
131
+ CREATE TABLE IF NOT EXISTS \`UserSession\` (
132
+ \`ID\` VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
133
+ \`SessionToken\` VARCHAR(255) NOT NULL UNIQUE,
134
+ \`userid\` VARCHAR(36) NOT NULL,
135
+ \`ExpirationDate\` DATETIME NOT NULL,
136
+ FOREIGN KEY (\`userid\`) REFERENCES \`Users\`(\`userid\`) ON DELETE CASCADE
137
+ );
138
+
139
+ -- Indexes for UserSession table
140
+ CREATE INDEX idx_session_token ON \`UserSession\`(\`SessionToken\`);
141
+ CREATE INDEX idx_session_user ON \`UserSession\`(\`userid\`);
142
+ CREATE INDEX idx_session_expiry ON \`UserSession\`(\`ExpirationDate\`);
143
+
144
+ -- OAuthTokens table
145
+ CREATE TABLE IF NOT EXISTS \`OAuthTokens\` (
146
+ \`ID\` VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
147
+ \`userid\` VARCHAR(36) NOT NULL,
148
+ \`Provider\` VARCHAR(20) NOT NULL CHECK(\`Provider\` IN ('google', 'facebook', 'apple', 'github')),
149
+ \`AccessToken\` TEXT NOT NULL,
150
+ \`RefreshToken\` TEXT,
151
+ \`ExpiresAt\` DATETIME,
152
+ \`CreatedAt\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
153
+ \`UpdatedAt\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
154
+ FOREIGN KEY (\`userid\`) REFERENCES \`Users\`(\`userid\`) ON DELETE CASCADE
155
+ );
156
+
157
+ -- Indexes for OAuthTokens table
158
+ CREATE INDEX idx_oauth_user ON \`OAuthTokens\`(\`userid\`);
159
+ CREATE INDEX idx_oauth_provider ON \`OAuthTokens\`(\`userid\`, \`Provider\`);`;
160
+ }
161
+
108
162
  const sanitizedTableName = model.name;
109
163
 
110
164
  // Start with the model's fields
@@ -116,6 +116,60 @@ export async function db_query(
116
116
  * @returns SQL string for creating the table
117
117
  */
118
118
  export function db_migrate(model: Model, dbType: string): string {
119
+ // Special handling for auth tables - create them first
120
+ if (model.name === '__auth_tables__') {
121
+ return `-- Users table (required for authentication)
122
+ CREATE TABLE IF NOT EXISTS "Users" (
123
+ "userid" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
124
+ "OAuthID" TEXT NOT NULL UNIQUE,
125
+ "Source" TEXT NOT NULL CHECK("Source" IN ('google', 'facebook', 'apple', 'github')),
126
+ "UserName" TEXT NOT NULL,
127
+ "Email" TEXT,
128
+ "AvatarURL" TEXT,
129
+ "UserLevel" INTEGER NOT NULL DEFAULT 1 CHECK("UserLevel" IN (0, 1, 2)),
130
+ "UserTier" INTEGER NOT NULL DEFAULT 0,
131
+ "LastLoginDate" TIMESTAMP NOT NULL DEFAULT NOW(),
132
+ "CreatedDate" TIMESTAMP NOT NULL DEFAULT NOW(),
133
+ "IsActive" BOOLEAN NOT NULL DEFAULT true
134
+ );
135
+
136
+ -- Indexes for Users table
137
+ CREATE INDEX IF NOT EXISTS idx_users_oauthid ON "Users"("OAuthID");
138
+ CREATE INDEX IF NOT EXISTS idx_users_email ON "Users"("Email");
139
+ CREATE INDEX IF NOT EXISTS idx_users_usertier ON "Users"("UserTier");
140
+
141
+ -- UserSession table
142
+ CREATE TABLE IF NOT EXISTS "UserSession" (
143
+ "ID" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
144
+ "SessionToken" VARCHAR(255) NOT NULL UNIQUE,
145
+ "userid" UUID NOT NULL,
146
+ "ExpirationDate" TIMESTAMP NOT NULL,
147
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
148
+ );
149
+
150
+ -- Indexes for UserSession table
151
+ CREATE INDEX IF NOT EXISTS idx_session_token ON "UserSession"("SessionToken");
152
+ CREATE INDEX IF NOT EXISTS idx_session_user ON "UserSession"("userid");
153
+ CREATE INDEX IF NOT EXISTS idx_session_expiry ON "UserSession"("ExpirationDate");
154
+
155
+ -- OAuthTokens table
156
+ CREATE TABLE IF NOT EXISTS "OAuthTokens" (
157
+ "ID" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
158
+ "userid" UUID NOT NULL,
159
+ "Provider" VARCHAR(20) NOT NULL CHECK("Provider" IN ('google', 'facebook', 'apple', 'github')),
160
+ "AccessToken" TEXT NOT NULL,
161
+ "RefreshToken" TEXT,
162
+ "ExpiresAt" TIMESTAMP,
163
+ "CreatedAt" TIMESTAMP NOT NULL DEFAULT NOW(),
164
+ "UpdatedAt" TIMESTAMP NOT NULL DEFAULT NOW(),
165
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
166
+ );
167
+
168
+ -- Indexes for OAuthTokens table
169
+ CREATE INDEX IF NOT EXISTS idx_oauth_user ON "OAuthTokens"("userid");
170
+ CREATE INDEX IF NOT EXISTS idx_oauth_provider ON "OAuthTokens"("userid", "Provider");`;
171
+ }
172
+
119
173
  const sanitizedTableName = model.name;
120
174
 
121
175
  // Start with the model's fields
@@ -181,6 +181,60 @@ export async function db_query(
181
181
  * @returns SQL string for creating the table
182
182
  */
183
183
  export function db_migrate(model: Model, dbType: string): string {
184
+ // Special handling for auth tables - create them first
185
+ if (model.name === '__auth_tables__') {
186
+ return `-- Users table (required for authentication)
187
+ CREATE TABLE IF NOT EXISTS "Users" (
188
+ "userid" TEXT PRIMARY KEY,
189
+ "OAuthID" TEXT NOT NULL UNIQUE,
190
+ "Source" TEXT NOT NULL CHECK("Source" IN ('google', 'facebook', 'apple', 'github')),
191
+ "UserName" TEXT NOT NULL,
192
+ "Email" TEXT,
193
+ "AvatarURL" TEXT,
194
+ "UserLevel" INTEGER NOT NULL DEFAULT 1 CHECK("UserLevel" IN (0, 1, 2)),
195
+ "UserTier" INTEGER NOT NULL DEFAULT 0,
196
+ "LastLoginDate" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
197
+ "CreatedDate" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
198
+ "IsActive" INTEGER NOT NULL DEFAULT 1
199
+ );
200
+
201
+ -- Indexes for Users table
202
+ CREATE INDEX IF NOT EXISTS idx_users_oauthid ON "Users"("OAuthID");
203
+ CREATE INDEX IF NOT EXISTS idx_users_email ON "Users"("Email");
204
+ CREATE INDEX IF NOT EXISTS idx_users_usertier ON "Users"("UserTier");
205
+
206
+ -- UserSession table
207
+ CREATE TABLE IF NOT EXISTS "UserSession" (
208
+ "ID" TEXT PRIMARY KEY,
209
+ "SessionToken" TEXT NOT NULL UNIQUE,
210
+ "userid" TEXT NOT NULL,
211
+ "ExpirationDate" TEXT NOT NULL,
212
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
213
+ );
214
+
215
+ -- Indexes for UserSession table
216
+ CREATE INDEX IF NOT EXISTS idx_session_token ON "UserSession"("SessionToken");
217
+ CREATE INDEX IF NOT EXISTS idx_session_user ON "UserSession"("userid");
218
+ CREATE INDEX IF NOT EXISTS idx_session_expiry ON "UserSession"("ExpirationDate");
219
+
220
+ -- OAuthTokens table
221
+ CREATE TABLE IF NOT EXISTS "OAuthTokens" (
222
+ "ID" TEXT PRIMARY KEY,
223
+ "userid" TEXT NOT NULL,
224
+ "Provider" TEXT NOT NULL CHECK("Provider" IN ('google', 'facebook', 'apple', 'github')),
225
+ "AccessToken" TEXT NOT NULL,
226
+ "RefreshToken" TEXT,
227
+ "ExpiresAt" TEXT,
228
+ "CreatedAt" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
229
+ "UpdatedAt" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
230
+ FOREIGN KEY ("userid") REFERENCES "Users"("userid") ON DELETE CASCADE
231
+ );
232
+
233
+ -- Indexes for OAuthTokens table
234
+ CREATE INDEX IF NOT EXISTS idx_oauth_user ON "OAuthTokens"("userid");
235
+ CREATE INDEX IF NOT EXISTS idx_oauth_provider ON "OAuthTokens"("userid", "Provider");`;
236
+ }
237
+
184
238
  const sanitizedTableName = model.name;
185
239
 
186
240
  // Start with the model's fields
@@ -39,147 +39,29 @@ export interface OAuthToken {
39
39
  }
40
40
 
41
41
  /**
42
- * Ensure the Users table exists with the correct schema
42
+ * @deprecated Table creation is now handled by db_migrate in the database implementation files
43
43
  */
44
44
  export async function ensureUsersTable(): Promise<void> {
45
- // Skip table creation during build time
46
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
47
- return;
48
- }
49
-
50
- const client = await db_init();
51
-
52
- // Create or migrate the Users table
53
- const createTableSQL = `
54
- CREATE TABLE IF NOT EXISTS Users (
55
- userid VARCHAR(36) PRIMARY KEY NOT NULL,
56
- OAuthID VARCHAR(255) NOT NULL UNIQUE,
57
- Source VARCHAR(20) NOT NULL CHECK(Source IN ('google', 'facebook', 'apple', 'github')),
58
- UserName VARCHAR(255) NOT NULL,
59
- Email VARCHAR(255),
60
- AvatarURL TEXT,
61
- UserLevel INTEGER NOT NULL DEFAULT 1 CHECK(UserLevel IN (0, 1, 2)),
62
- UserTier INTEGER NOT NULL DEFAULT 0,
63
- LastLoginDate DATETIME NOT NULL,
64
- CreatedDate DATETIME NOT NULL,
65
- IsActive BOOLEAN NOT NULL DEFAULT true
66
- );
67
-
68
- CREATE INDEX IF NOT EXISTS idx_users_oauth ON Users(OAuthID);
69
- CREATE INDEX IF NOT EXISTS idx_users_permission ON Users(UserLevel);
70
- `;
71
-
72
- // Split and execute statements separately for compatibility
73
- const statements = createTableSQL.split(';').map(s => s.trim()).filter(s => s.length > 0);
74
- for (const statement of statements) {
75
- try {
76
- await db_query(client, statement);
77
- } catch (error) {
78
- // Ignore errors for index creation as some databases don't support IF NOT EXISTS for indexes
79
- if (!statement.includes('CREATE INDEX')) {
80
- throw error;
81
- }
82
- }
83
- }
45
+ // No longer needed - Users table is created by db_migrate
46
+ return;
84
47
  }
85
48
 
86
49
  /**
87
- * Ensure the UserSession table exists
50
+ * @deprecated Table creation is now handled by db_migrate in the database implementation files
88
51
  */
89
52
  export async function ensureUserSessionTable(): Promise<void> {
90
- // Skip table creation during build time
91
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
92
- return;
93
- }
94
-
95
- const client = await db_init();
96
-
97
- const createTableSQL = `
98
- CREATE TABLE IF NOT EXISTS UserSession (
99
- ID VARCHAR(36) PRIMARY KEY NOT NULL,
100
- SessionToken VARCHAR(255) NOT NULL UNIQUE,
101
- userid VARCHAR(36) NOT NULL,
102
- ExpirationDate DATETIME NOT NULL,
103
- FOREIGN KEY (userid) REFERENCES Users(userid) ON DELETE CASCADE
104
- );
105
-
106
- CREATE INDEX IF NOT EXISTS idx_session_token ON UserSession(SessionToken);
107
- CREATE INDEX IF NOT EXISTS idx_session_user ON UserSession(userid);
108
- CREATE INDEX IF NOT EXISTS idx_session_expiry ON UserSession(ExpirationDate);
109
- `;
110
-
111
- // Split and execute statements separately for compatibility
112
- const statements = createTableSQL.split(';').map(s => s.trim()).filter(s => s.length > 0);
113
- for (const statement of statements) {
114
- try {
115
- await db_query(client, statement);
116
- } catch (error) {
117
- // Ignore errors for index creation as some databases don't support IF NOT EXISTS for indexes
118
- if (!statement.includes('CREATE INDEX')) {
119
- throw error;
120
- }
121
- }
122
- }
53
+ // No longer needed - UserSession table is created by db_migrate
54
+ return;
123
55
  }
124
56
 
125
57
  /**
126
- * Ensure the OAuthTokens table exists
58
+ * @deprecated Table creation is now handled by db_migrate in the database implementation files
127
59
  */
128
60
  export async function ensureOAuthTokensTable(): Promise<void> {
129
- // Skip table creation during build time
130
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
131
- return;
132
- }
133
-
134
- const client = await db_init();
135
-
136
- const createTableSQL = `
137
- CREATE TABLE IF NOT EXISTS OAuthTokens (
138
- ID VARCHAR(36) PRIMARY KEY NOT NULL,
139
- userid VARCHAR(36) NOT NULL,
140
- Provider VARCHAR(20) NOT NULL CHECK(Provider IN ('google', 'facebook', 'apple', 'github')),
141
- AccessToken TEXT NOT NULL,
142
- RefreshToken TEXT,
143
- ExpiresAt DATETIME,
144
- CreatedAt DATETIME NOT NULL,
145
- UpdatedAt DATETIME NOT NULL,
146
- FOREIGN KEY (userid) REFERENCES Users(userid) ON DELETE CASCADE
147
- );
148
-
149
- CREATE INDEX IF NOT EXISTS idx_oauth_user ON OAuthTokens(userid);
150
- CREATE INDEX IF NOT EXISTS idx_oauth_provider ON OAuthTokens(userid, Provider);
151
- `;
152
-
153
- // Split and execute statements separately for compatibility
154
- const statements = createTableSQL.split(';').map(s => s.trim()).filter(s => s.length > 0);
155
- for (const statement of statements) {
156
- try {
157
- await db_query(client, statement);
158
- } catch (error) {
159
- // Ignore errors for index creation as some databases don't support IF NOT EXISTS for indexes
160
- if (!statement.includes('CREATE INDEX')) {
161
- throw error;
162
- }
163
- }
164
- }
61
+ // No longer needed - OAuthTokens table is created by db_migrate
62
+ return;
165
63
  }
166
64
 
167
- /**
168
- * Ensure all authentication tables exist
169
- */
170
- export async function ensureAuthTables(): Promise<void> {
171
- // Skip table creation during build time
172
- if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
173
- return;
174
- }
175
-
176
- const client = await db_init();
177
-
178
- // IMPORTANT: Create Users table first since UserSession and OAuthTokens have foreign keys to it
179
- await ensureUsersTable();
180
- await ensureUserSessionTable();
181
- await ensureOAuthTokensTable();
182
- }
183
65
 
184
66
  /**
185
67
  * Get all users from the database
@@ -158,6 +158,27 @@ export async function initializeDatabase(
158
158
  const client = await db_init();
159
159
 
160
160
  try {
161
+ // Create auth tables first (Users, UserSession, OAuthTokens)
162
+ const authTablesModel: Model = {
163
+ id: '__auth_tables__',
164
+ name: '__auth_tables__',
165
+ fields: []
166
+ };
167
+ const authTablesSql = db_migrate(authTablesModel);
168
+
169
+ // Execute each statement separately for auth tables
170
+ const authStatements = authTablesSql.split(';').map(s => s.trim()).filter(s => s.length > 0);
171
+ for (const statement of authStatements) {
172
+ try {
173
+ await db_query(client, statement);
174
+ } catch (error) {
175
+ // Some databases might not support certain syntax, continue with other statements
176
+ if (!statement.includes('CREATE INDEX')) {
177
+ console.error('Error creating auth table:', error);
178
+ }
179
+ }
180
+ }
181
+
161
182
  // Create tables for each model
162
183
  for (const model of models) {
163
184
  const createTableSql = db_migrate(model);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sitepaige-mcp-server",
3
- "version": "0.7.7",
3
+ "version": "0.7.8",
4
4
  "type": "module",
5
5
  "description": "MCP server for generating web applications using SitePaige AI. Generate frontend (FREE/12 credits) then optionally add backend (50 credits)",
6
6
  "keywords": [