sitepaige-mcp-server 1.1.0 → 1.2.1
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.
- package/components/headerlogin.tsx +10 -28
- package/components/profile.tsx +302 -46
- package/components/slideshow.tsx +1 -9
- package/defaultapp/api/Auth/resend-verification/route.ts +3 -3
- package/defaultapp/api/Auth/route.ts +2 -2
- package/defaultapp/api/Auth/signup/route.ts +3 -3
- package/defaultapp/api/Auth/verify-email/route.ts +5 -5
- package/defaultapp/api/admin/users/route.ts +3 -3
- package/defaultapp/{db-users.ts → api/db-users.ts} +1 -1
- package/defaultapp/api/profile/route.ts +154 -0
- package/defaultapp/profile/page.tsx +6 -0
- package/dist/blueprintWriter.js.map +1 -1
- package/dist/components/headerlogin.tsx +10 -28
- package/dist/components/profile.tsx +302 -46
- package/dist/components/slideshow.tsx +1 -9
- package/dist/defaultapp/api/Auth/resend-verification/route.ts +3 -3
- package/dist/defaultapp/api/Auth/route.ts +2 -2
- package/dist/defaultapp/api/Auth/signup/route.ts +3 -3
- package/dist/defaultapp/api/Auth/verify-email/route.ts +5 -5
- package/dist/defaultapp/api/admin/users/route.ts +3 -3
- package/dist/defaultapp/api/csrf.ts +111 -0
- package/dist/defaultapp/api/db-mysql.ts +183 -0
- package/dist/defaultapp/api/db-password-auth.ts +362 -0
- package/dist/defaultapp/api/db-postgres.ts +189 -0
- package/dist/defaultapp/api/db-sqlite.ts +335 -0
- package/dist/defaultapp/api/db-users.ts +520 -0
- package/dist/defaultapp/api/db.ts +149 -0
- package/dist/defaultapp/api/profile/route.ts +154 -0
- package/dist/defaultapp/api/storage/email.ts +162 -0
- package/dist/defaultapp/api/storage/files.ts +160 -0
- package/dist/defaultapp/db-users.ts +1 -1
- package/dist/defaultapp/profile/page.tsx +6 -0
- package/dist/generators/env-example-template.txt +4 -3
- package/dist/generators/skeleton.js +3 -5
- package/dist/generators/skeleton.js.map +1 -1
- package/dist/generators/sql.js +60 -0
- package/dist/generators/sql.js.map +1 -1
- package/dist/sitepaige.js +2 -1
- package/dist/sitepaige.js.map +1 -1
- package/package.json +1 -1
- package/defaultapp/admin/page.tsx +0 -6
- package/defaultapp/api/example-secure/route.ts +0 -100
- package/defaultapp/migrate.ts +0 -142
- /package/defaultapp/{csrf.ts → api/csrf.ts} +0 -0
- /package/defaultapp/{db-mysql.ts → api/db-mysql.ts} +0 -0
- /package/defaultapp/{db-password-auth.ts → api/db-password-auth.ts} +0 -0
- /package/defaultapp/{db-postgres.ts → api/db-postgres.ts} +0 -0
- /package/defaultapp/{db-sqlite.ts → api/db-sqlite.ts} +0 -0
- /package/defaultapp/{db.ts → api/db.ts} +0 -0
- /package/defaultapp/{storage → api/storage}/email.ts +0 -0
- /package/defaultapp/{storage → api/storage}/files.ts +0 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Sitepaige v1.0.0
|
|
3
|
+
SQLite database implementation
|
|
4
|
+
WARNING: This file is automatically generated and should not be modified.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Database from 'better-sqlite3';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import { promises as fsPromises } from 'fs';
|
|
11
|
+
import type { Model, ModelField } from './db';
|
|
12
|
+
|
|
13
|
+
// Map to store multiple database connections by path
|
|
14
|
+
const dbConnections: Map<string, Database.Database> = new Map();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the default database path
|
|
18
|
+
*/
|
|
19
|
+
function getDefaultDbPath(): string {
|
|
20
|
+
// First check if DATABASE_URL is provided
|
|
21
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
22
|
+
if (databaseUrl) {
|
|
23
|
+
// DATABASE_URL can be either a direct file path or a sqlite:// URL
|
|
24
|
+
if (databaseUrl.startsWith('sqlite://')) {
|
|
25
|
+
// Remove the sqlite:// prefix and return the path
|
|
26
|
+
return databaseUrl.slice(9);
|
|
27
|
+
} else {
|
|
28
|
+
// Assume it's a direct file path
|
|
29
|
+
return databaseUrl;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Use EFS_MOUNT_PATH for production (in container with EFS)
|
|
34
|
+
// Use SQLITE_DIR for local development
|
|
35
|
+
const efsMountPath = process.env.EFS_MOUNT_PATH;
|
|
36
|
+
const sqliteDir = process.env.SQLITE_DIR || '.';
|
|
37
|
+
|
|
38
|
+
if (efsMountPath) {
|
|
39
|
+
// In production with EFS
|
|
40
|
+
return path.join(efsMountPath, 'data', 'app.db');
|
|
41
|
+
} else {
|
|
42
|
+
// In local development
|
|
43
|
+
return path.join(sqliteDir, 'app.db');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize database connection
|
|
49
|
+
* Uses DATABASE_URL if provided, otherwise uses default database path based on
|
|
50
|
+
* EFS_MOUNT_PATH (production) or SQLITE_DIR (development).
|
|
51
|
+
* If the file doesn't exist, it will be created automatically.
|
|
52
|
+
* @returns Database client
|
|
53
|
+
*/
|
|
54
|
+
export async function db_init(): Promise<Database.Database> {
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
// Always use the default path - no parameter needed
|
|
58
|
+
const actualPath = getDefaultDbPath();
|
|
59
|
+
|
|
60
|
+
// Check if we already have a connection to this database
|
|
61
|
+
const existingConnection = dbConnections.get(actualPath);
|
|
62
|
+
if (existingConnection) {
|
|
63
|
+
return existingConnection;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
// Ensure the directory exists (using async method)
|
|
68
|
+
const dir = path.dirname(actualPath);
|
|
69
|
+
if (dir && dir !== '.' && dir !== '/') {
|
|
70
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create database connection (SQLite will create the file if it doesn't exist)
|
|
74
|
+
const newDb = new Database(actualPath);
|
|
75
|
+
|
|
76
|
+
// Enable foreign keys for proper constraint enforcement
|
|
77
|
+
newDb.pragma('foreign_keys = ON');
|
|
78
|
+
|
|
79
|
+
// Store the connection
|
|
80
|
+
dbConnections.set(actualPath, newDb);
|
|
81
|
+
|
|
82
|
+
return newDb;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Execute a SQL query using the provided SQLite database client
|
|
90
|
+
* @param client Database client from db_init()
|
|
91
|
+
* @param query SQL query string (SQLite syntax with ? parameter placeholders)
|
|
92
|
+
* @param params Optional array of parameters for the query
|
|
93
|
+
* @returns Array of selected rows or execution results
|
|
94
|
+
*/
|
|
95
|
+
export async function db_query(
|
|
96
|
+
client: Database.Database,
|
|
97
|
+
query: string,
|
|
98
|
+
params?: any[]
|
|
99
|
+
): Promise<any[]> {
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
// Convert booleans to integers for SQLite3 compatibility
|
|
104
|
+
const queryParams = (params || []).map(param =>
|
|
105
|
+
typeof param === 'boolean' ? (param ? 1 : 0) : param
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Check if the query contains multiple statements (separated by semicolons)
|
|
109
|
+
const statements = query.split(';').map(s => s.trim()).filter(s => s.length > 0);
|
|
110
|
+
|
|
111
|
+
if (statements.length > 1) {
|
|
112
|
+
// Handle multiple statements
|
|
113
|
+
const results: any[] = [];
|
|
114
|
+
|
|
115
|
+
for (const statement of statements) {
|
|
116
|
+
const queryType = statement.trim().toUpperCase().split(' ')[0];
|
|
117
|
+
|
|
118
|
+
if (queryType === 'SELECT') {
|
|
119
|
+
// For SELECT queries, return results array
|
|
120
|
+
const stmt = client.prepare(statement);
|
|
121
|
+
const stmtResults = stmt.all(...queryParams);
|
|
122
|
+
results.push(...stmtResults);
|
|
123
|
+
} else {
|
|
124
|
+
// For INSERT, UPDATE, DELETE queries, execute and return info
|
|
125
|
+
const stmt = client.prepare(statement);
|
|
126
|
+
const result = stmt.run(...queryParams);
|
|
127
|
+
|
|
128
|
+
// Add standardized result info
|
|
129
|
+
results.push({
|
|
130
|
+
changes: result.changes,
|
|
131
|
+
lastInsertRowid: result.lastInsertRowid
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return results;
|
|
137
|
+
} else {
|
|
138
|
+
// Handle single statement (original logic)
|
|
139
|
+
const singleQuery = statements[0] || query.trim();
|
|
140
|
+
const queryType = singleQuery.trim().toUpperCase().split(' ')[0];
|
|
141
|
+
|
|
142
|
+
if (queryType === 'SELECT') {
|
|
143
|
+
// For SELECT queries, return results array
|
|
144
|
+
const stmt = client.prepare(singleQuery);
|
|
145
|
+
const results = stmt.all(...queryParams);
|
|
146
|
+
return results;
|
|
147
|
+
} else {
|
|
148
|
+
// For INSERT, UPDATE, DELETE queries, execute and return info
|
|
149
|
+
const stmt = client.prepare(singleQuery);
|
|
150
|
+
const result = stmt.run(...queryParams);
|
|
151
|
+
|
|
152
|
+
// Return standardized result info
|
|
153
|
+
return [{
|
|
154
|
+
changes: result.changes,
|
|
155
|
+
lastInsertRowid: result.lastInsertRowid
|
|
156
|
+
}];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
// If table doesn't exist for SELECT, return empty array
|
|
162
|
+
if (error instanceof Error && error.message.includes('no such table') && query.trim().toUpperCase().startsWith('SELECT')) {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generates a CREATE TABLE SQL string for the specified table and fields
|
|
171
|
+
* @param model The model definition
|
|
172
|
+
* @param dbType Database type (for compatibility, not used in SQLite)
|
|
173
|
+
* @returns SQL string for creating the table
|
|
174
|
+
*/
|
|
175
|
+
export function db_migrate(model: Model, dbType: string): string {
|
|
176
|
+
// Special handling for auth tables - create them first
|
|
177
|
+
|
|
178
|
+
const sanitizedTableName = model.name.toLowerCase().replace(/\s+/g, '_');
|
|
179
|
+
|
|
180
|
+
// Start with the model's fields
|
|
181
|
+
let fields = [...model.fields];
|
|
182
|
+
|
|
183
|
+
// Add userid field if data is user specific
|
|
184
|
+
if (model.data_is_user_specific === "true") {
|
|
185
|
+
fields.push({
|
|
186
|
+
name: 'userid',
|
|
187
|
+
datatype: 'TEXT',
|
|
188
|
+
datatypesize: null,
|
|
189
|
+
key: 'foreign',
|
|
190
|
+
required: 'true',
|
|
191
|
+
default: undefined
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Map SQL data types for SQLite
|
|
196
|
+
const sqlTypeMap: { [key: string]: string } = {
|
|
197
|
+
'UUID': 'TEXT',
|
|
198
|
+
'TINYINT': 'INTEGER',
|
|
199
|
+
'SMALLINT': 'INTEGER',
|
|
200
|
+
'BIGINT': 'INTEGER',
|
|
201
|
+
'INT128': 'TEXT',
|
|
202
|
+
'VARCHAR': 'TEXT',
|
|
203
|
+
'TEXT': 'TEXT',
|
|
204
|
+
'BINARY': 'BLOB',
|
|
205
|
+
'DATE': 'TEXT',
|
|
206
|
+
'TIME': 'TEXT',
|
|
207
|
+
'DATETIME': 'TEXT',
|
|
208
|
+
'DOUBLE': 'REAL',
|
|
209
|
+
'FLOAT': 'REAL',
|
|
210
|
+
'BOOLEAN': 'INTEGER'
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Build column definitions
|
|
214
|
+
const columnDefs = fields.sort((a, b) => (b.key === 'primary' ? 1 : 0) - (a.key === 'primary' ? 1 : 0)).map(field => {
|
|
215
|
+
let def = `"${field.name}" ${sqlTypeMap[field.datatype.toUpperCase()]}`;
|
|
216
|
+
|
|
217
|
+
// Add NOT NULL if required
|
|
218
|
+
if (field.required === "true") {
|
|
219
|
+
def += ' NOT NULL';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Add default if specified
|
|
223
|
+
if (field.default !== undefined) {
|
|
224
|
+
if (field.datatype === 'VARCHAR' || field.datatype === 'TEXT') {
|
|
225
|
+
def += ` DEFAULT '${field.default}'`;
|
|
226
|
+
} else {
|
|
227
|
+
def += ` DEFAULT ${field.default}`;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Add primary key constraint
|
|
232
|
+
if (field.key === 'primary') {
|
|
233
|
+
def += ' PRIMARY KEY';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return def;
|
|
237
|
+
}).join(',\n ');
|
|
238
|
+
|
|
239
|
+
// Build the CREATE TABLE statement
|
|
240
|
+
const sql = `CREATE TABLE IF NOT EXISTS "${sanitizedTableName}" (\n ${columnDefs}\n);`;
|
|
241
|
+
|
|
242
|
+
return sql;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get or create a database connection for the specified path
|
|
247
|
+
* This is a convenience wrapper for working with arbitrary database files
|
|
248
|
+
* Note: For the main application database, use db_init() instead
|
|
249
|
+
* @param dbPath Path to the database file (including database name)
|
|
250
|
+
* @returns Database client ready for use
|
|
251
|
+
*/
|
|
252
|
+
export async function getDatabase(dbPath: string): Promise<Database.Database> {
|
|
253
|
+
// Skip database operations during build time
|
|
254
|
+
if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
|
|
255
|
+
return {} as Database.Database;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Check if we already have a connection to this database
|
|
259
|
+
const existingConnection = dbConnections.get(dbPath);
|
|
260
|
+
if (existingConnection) {
|
|
261
|
+
return existingConnection;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
// Ensure the directory exists (using async method)
|
|
266
|
+
const dir = path.dirname(dbPath);
|
|
267
|
+
if (dir && dir !== '.' && dir !== '/') {
|
|
268
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Create database connection
|
|
272
|
+
const newDb = new Database(dbPath);
|
|
273
|
+
newDb.pragma('foreign_keys = ON');
|
|
274
|
+
dbConnections.set(dbPath, newDb);
|
|
275
|
+
|
|
276
|
+
return newDb;
|
|
277
|
+
} catch (error) {
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Check if a database file exists at the specified path
|
|
284
|
+
* @param dbPath Path to the database file
|
|
285
|
+
* @returns true if the database file exists, false otherwise
|
|
286
|
+
*/
|
|
287
|
+
export async function databaseExists(dbPath: string): Promise<boolean> {
|
|
288
|
+
try {
|
|
289
|
+
await fsPromises.access(dbPath, fs.constants.F_OK);
|
|
290
|
+
return true;
|
|
291
|
+
} catch (error) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Get information about the database at the specified path
|
|
298
|
+
* @param dbPath Path to the database file
|
|
299
|
+
* @returns Object with database information or null if database doesn't exist
|
|
300
|
+
*/
|
|
301
|
+
export async function getDatabaseInfo(dbPath: string): Promise<{
|
|
302
|
+
exists: boolean;
|
|
303
|
+
tables?: string[];
|
|
304
|
+
size?: number;
|
|
305
|
+
} | null> {
|
|
306
|
+
// Skip during build time
|
|
307
|
+
if (typeof window === 'undefined' && !process.env.HOSTNAME && process.env.NODE_ENV === 'production') {
|
|
308
|
+
return { exists: false };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const exists = await databaseExists(dbPath);
|
|
312
|
+
|
|
313
|
+
if (!exists) {
|
|
314
|
+
return { exists: false };
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
const stats = await fsPromises.stat(dbPath);
|
|
319
|
+
const client = await getDatabase(dbPath);
|
|
320
|
+
|
|
321
|
+
// Get list of tables
|
|
322
|
+
const tables = await db_query(
|
|
323
|
+
client,
|
|
324
|
+
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
exists: true,
|
|
329
|
+
tables: tables.map(t => t.name),
|
|
330
|
+
size: stats.size
|
|
331
|
+
};
|
|
332
|
+
} catch (error) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
}
|