@techstream/quark-create-app 1.3.0 → 1.4.0
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/package.json +34 -34
- package/src/index.js +23 -16
- package/templates/base-project/apps/web/src/app/api/auth/register/route.js +17 -1
- package/templates/base-project/apps/web/src/app/api/health/route.js +4 -1
- package/templates/base-project/apps/web/src/app/api/posts/[id]/route.js +5 -1
- package/templates/base-project/apps/worker/src/index.js +71 -28
- package/templates/base-project/package.json +7 -1
- package/templates/base-project/packages/db/scripts/seed.js +1 -1
- package/templates/base-project/packages/db/src/client.js +40 -24
- package/templates/base-project/turbo.json +16 -1
- package/templates/base-project/packages/db/src/generated/prisma/browser.ts +0 -53
- package/templates/base-project/packages/db/src/generated/prisma/client.ts +0 -82
- package/templates/base-project/packages/db/src/generated/prisma/commonInputTypes.ts +0 -649
- package/templates/base-project/packages/db/src/generated/prisma/enums.ts +0 -19
- package/templates/base-project/packages/db/src/generated/prisma/internal/class.ts +0 -305
- package/templates/base-project/packages/db/src/generated/prisma/internal/prismaNamespace.ts +0 -1428
- package/templates/base-project/packages/db/src/generated/prisma/internal/prismaNamespaceBrowser.ts +0 -217
- package/templates/base-project/packages/db/src/generated/prisma/models/Account.ts +0 -2098
- package/templates/base-project/packages/db/src/generated/prisma/models/AuditLog.ts +0 -1805
- package/templates/base-project/packages/db/src/generated/prisma/models/Job.ts +0 -1737
- package/templates/base-project/packages/db/src/generated/prisma/models/Post.ts +0 -1762
- package/templates/base-project/packages/db/src/generated/prisma/models/Session.ts +0 -1738
- package/templates/base-project/packages/db/src/generated/prisma/models/User.ts +0 -2298
- package/templates/base-project/packages/db/src/generated/prisma/models/VerificationToken.ts +0 -1450
- package/templates/base-project/packages/db/src/generated/prisma/models.ts +0 -18
package/package.json
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
2
|
+
"name": "@techstream/quark-create-app",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"quark-create-app": "src/index.js",
|
|
7
|
+
"create-quark-app": "src/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"templates",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"chalk": "^5.6.2",
|
|
16
|
+
"commander": "^12.1.0",
|
|
17
|
+
"execa": "^9.6.1",
|
|
18
|
+
"fs-extra": "^11.3.3",
|
|
19
|
+
"prompts": "^2.4.2"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"registry": "https://registry.npmjs.org",
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22"
|
|
27
|
+
},
|
|
28
|
+
"license": "ISC",
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "node test-cli.js",
|
|
31
|
+
"test:e2e": "node test-e2e.js",
|
|
32
|
+
"test:integration": "node test-integration.js",
|
|
33
|
+
"test:all": "node test-all.js"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/index.js
CHANGED
|
@@ -110,7 +110,10 @@ async function copyTemplate(templateName, targetDir, variables = {}) {
|
|
|
110
110
|
let content = await fs.readFile(packageJsonPath, "utf-8");
|
|
111
111
|
|
|
112
112
|
for (const [key, value] of Object.entries(variables)) {
|
|
113
|
-
const pattern = new RegExp(
|
|
113
|
+
const pattern = new RegExp(
|
|
114
|
+
key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
|
|
115
|
+
"g",
|
|
116
|
+
);
|
|
114
117
|
content = content.replace(pattern, value);
|
|
115
118
|
}
|
|
116
119
|
|
|
@@ -175,7 +178,11 @@ function replaceDepsScope(deps, scope, selectedPackages) {
|
|
|
175
178
|
const packageName = key.replace("@techstream/quark-", "");
|
|
176
179
|
delete deps[key];
|
|
177
180
|
// Only keep the dep if the package was selected (or is always required)
|
|
178
|
-
if (
|
|
181
|
+
if (
|
|
182
|
+
packageName === "db" ||
|
|
183
|
+
packageName === "config" ||
|
|
184
|
+
selectedPackages.includes(packageName)
|
|
185
|
+
) {
|
|
179
186
|
deps[`@${scope}/${packageName}`] = value;
|
|
180
187
|
}
|
|
181
188
|
}
|
|
@@ -194,7 +201,11 @@ async function replaceImportsInSourceFiles(dir, scope) {
|
|
|
194
201
|
for (const entry of entries) {
|
|
195
202
|
const fullPath = path.join(dir, entry.name);
|
|
196
203
|
|
|
197
|
-
if (
|
|
204
|
+
if (
|
|
205
|
+
entry.isDirectory() &&
|
|
206
|
+
entry.name !== "node_modules" &&
|
|
207
|
+
entry.name !== ".next"
|
|
208
|
+
) {
|
|
198
209
|
await replaceImportsInSourceFiles(fullPath, scope);
|
|
199
210
|
} else if (entry.isFile() && /\.(js|ts|jsx|tsx|mjs)$/.test(entry.name)) {
|
|
200
211
|
let content = await fs.readFile(fullPath, "utf-8");
|
|
@@ -245,7 +256,9 @@ program
|
|
|
245
256
|
.argument("<project-name>", "Name of the project to create")
|
|
246
257
|
.action(async (projectName) => {
|
|
247
258
|
console.log(
|
|
248
|
-
chalk.blue.bold(
|
|
259
|
+
chalk.blue.bold(
|
|
260
|
+
`\n\uD83D\uDE80 Creating your new Quark project: ${projectName}\n`,
|
|
261
|
+
),
|
|
249
262
|
);
|
|
250
263
|
|
|
251
264
|
const targetDir = validateProjectName(projectName);
|
|
@@ -383,16 +396,13 @@ program
|
|
|
383
396
|
if (await fs.pathExists(pkgPath)) {
|
|
384
397
|
const pkg = await fs.readJSON(pkgPath);
|
|
385
398
|
// Rename package name if it uses @quark/ prefix
|
|
386
|
-
if (pkg.name
|
|
399
|
+
if (pkg.name?.startsWith("@quark/")) {
|
|
387
400
|
const shortName = pkg.name.replace("@quark/", "");
|
|
388
401
|
pkg.name = `@${scope}/${shortName}`;
|
|
389
402
|
}
|
|
390
403
|
replaceDepsScope(pkg.dependencies, scope, features);
|
|
391
404
|
replaceDepsScope(pkg.devDependencies, scope, features);
|
|
392
|
-
await fs.writeFile(
|
|
393
|
-
pkgPath,
|
|
394
|
-
`${JSON.stringify(pkg, null, 2)}\n`,
|
|
395
|
-
);
|
|
405
|
+
await fs.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
396
406
|
}
|
|
397
407
|
}
|
|
398
408
|
|
|
@@ -481,7 +491,8 @@ WORKER_CONCURRENCY=5
|
|
|
481
491
|
const webPort = await findAvailablePort(3000);
|
|
482
492
|
|
|
483
493
|
const portChanges = [];
|
|
484
|
-
if (postgresPort !== 5432)
|
|
494
|
+
if (postgresPort !== 5432)
|
|
495
|
+
portChanges.push(`PostgreSQL: ${postgresPort}`);
|
|
485
496
|
if (redisPort !== 6379) portChanges.push(`Redis: ${redisPort}`);
|
|
486
497
|
if (mailSmtpPort !== 1025) portChanges.push(`Mail SMTP: ${mailSmtpPort}`);
|
|
487
498
|
if (mailUiPort !== 8025) portChanges.push(`Mail UI: ${mailUiPort}`);
|
|
@@ -566,9 +577,7 @@ WORKER_CONCURRENCY=5
|
|
|
566
577
|
console.log(chalk.green(`\n ✓ Dependencies installed`));
|
|
567
578
|
} catch (installError) {
|
|
568
579
|
console.warn(
|
|
569
|
-
chalk.yellow(
|
|
570
|
-
`\n ⚠️ pnpm install failed: ${installError.message}`,
|
|
571
|
-
),
|
|
580
|
+
chalk.yellow(`\n ⚠️ pnpm install failed: ${installError.message}`),
|
|
572
581
|
);
|
|
573
582
|
console.warn(
|
|
574
583
|
chalk.yellow(
|
|
@@ -592,9 +601,7 @@ WORKER_CONCURRENCY=5
|
|
|
592
601
|
),
|
|
593
602
|
);
|
|
594
603
|
console.warn(
|
|
595
|
-
chalk.yellow(
|
|
596
|
-
` Run 'pnpm --filter db db:generate' manually.`,
|
|
597
|
-
),
|
|
604
|
+
chalk.yellow(` Run 'pnpm --filter db db:generate' manually.`),
|
|
598
605
|
);
|
|
599
606
|
}
|
|
600
607
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createQueue,
|
|
3
|
+
hashPassword,
|
|
4
|
+
validateBody,
|
|
5
|
+
} from "@techstream/quark-core";
|
|
2
6
|
import { user, userRegisterSchema } from "@techstream/quark-db";
|
|
7
|
+
import { JOB_NAMES, JOB_QUEUES } from "@techstream/quark-jobs";
|
|
3
8
|
import { NextResponse } from "next/server";
|
|
4
9
|
import { handleError } from "../../error-handler";
|
|
5
10
|
|
|
@@ -29,6 +34,17 @@ export async function POST(request) {
|
|
|
29
34
|
password: hashedPassword,
|
|
30
35
|
});
|
|
31
36
|
|
|
37
|
+
// Enqueue welcome email (fire-and-forget)
|
|
38
|
+
try {
|
|
39
|
+
const emailQueue = createQueue(JOB_QUEUES.EMAIL);
|
|
40
|
+
await emailQueue.add(JOB_NAMES.SEND_WELCOME_EMAIL, {
|
|
41
|
+
userId: newUser.id,
|
|
42
|
+
});
|
|
43
|
+
} catch (emailError) {
|
|
44
|
+
// Don't fail registration if email enqueue fails
|
|
45
|
+
console.error("Failed to enqueue welcome email:", emailError);
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
// Don't return the password
|
|
33
49
|
const { password: _, ...safeUser } = newUser;
|
|
34
50
|
|
|
@@ -29,7 +29,10 @@ export async function GET() {
|
|
|
29
29
|
status: result.status === "ok" ? 200 : 503,
|
|
30
30
|
});
|
|
31
31
|
} catch (error) {
|
|
32
|
-
logger.error("Health check failed", {
|
|
32
|
+
logger.error("Health check failed", {
|
|
33
|
+
error: error.message,
|
|
34
|
+
stack: error.stack,
|
|
35
|
+
});
|
|
33
36
|
return NextResponse.json(
|
|
34
37
|
{
|
|
35
38
|
status: "error",
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
UnauthorizedError,
|
|
3
|
+
validateBody,
|
|
4
|
+
withCsrfProtection,
|
|
5
|
+
} from "@techstream/quark-core";
|
|
2
6
|
import { post, postUpdateSchema } from "@techstream/quark-db";
|
|
3
7
|
import { NextResponse } from "next/server";
|
|
4
8
|
import { requireAuth } from "@/lib/auth-middleware";
|
|
@@ -8,9 +8,11 @@ import {
|
|
|
8
8
|
createEmailService,
|
|
9
9
|
createLogger,
|
|
10
10
|
createWorker,
|
|
11
|
+
passwordResetEmail,
|
|
12
|
+
welcomeEmail,
|
|
11
13
|
} from "@techstream/quark-core";
|
|
12
|
-
import { JOB_NAMES, JOB_QUEUES } from "@techstream/quark-jobs";
|
|
13
14
|
import { prisma } from "@techstream/quark-db";
|
|
15
|
+
import { JOB_NAMES, JOB_QUEUES } from "@techstream/quark-jobs";
|
|
14
16
|
|
|
15
17
|
const logger = createLogger("worker");
|
|
16
18
|
|
|
@@ -20,18 +22,6 @@ const workers = [];
|
|
|
20
22
|
// Initialize email service
|
|
21
23
|
const emailService = createEmailService();
|
|
22
24
|
|
|
23
|
-
/**
|
|
24
|
-
* Escape HTML entities to prevent XSS in email body
|
|
25
|
-
*/
|
|
26
|
-
function escapeHtml(str) {
|
|
27
|
-
return str
|
|
28
|
-
.replace(/&/g, "&")
|
|
29
|
-
.replace(/</g, "<")
|
|
30
|
-
.replace(/>/g, ">")
|
|
31
|
-
.replace(/"/g, """)
|
|
32
|
-
.replace(/'/g, "'");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
25
|
/**
|
|
36
26
|
* Job handler for SEND_WELCOME_EMAIL
|
|
37
27
|
* @param {Job} bullJob - BullMQ job object
|
|
@@ -48,7 +38,6 @@ async function handleSendWelcomeEmail(bullJob) {
|
|
|
48
38
|
userId,
|
|
49
39
|
});
|
|
50
40
|
|
|
51
|
-
// Look up the user's email
|
|
52
41
|
const userRecord = await prisma.user.findUnique({
|
|
53
42
|
where: { id: userId },
|
|
54
43
|
select: { email: true, name: true },
|
|
@@ -58,16 +47,60 @@ async function handleSendWelcomeEmail(bullJob) {
|
|
|
58
47
|
throw new Error(`User ${userId} not found or has no email`);
|
|
59
48
|
}
|
|
60
49
|
|
|
61
|
-
const
|
|
62
|
-
|
|
50
|
+
const template = welcomeEmail({
|
|
51
|
+
name: userRecord.name,
|
|
52
|
+
loginUrl: process.env.APP_URL
|
|
53
|
+
? `${process.env.APP_URL}/api/auth/signin`
|
|
54
|
+
: undefined,
|
|
55
|
+
});
|
|
63
56
|
|
|
64
57
|
await emailService.sendEmail(
|
|
65
58
|
userRecord.email,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
59
|
+
template.subject,
|
|
60
|
+
template.html,
|
|
61
|
+
template.text,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return { success: true, userId, email: userRecord.email };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Job handler for SEND_RESET_PASSWORD_EMAIL
|
|
69
|
+
* @param {Job} bullJob - BullMQ job object
|
|
70
|
+
*/
|
|
71
|
+
async function handleSendResetPasswordEmail(bullJob) {
|
|
72
|
+
const { userId, resetUrl } = bullJob.data;
|
|
73
|
+
|
|
74
|
+
if (!userId || !resetUrl) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"userId and resetUrl are required for SEND_RESET_PASSWORD_EMAIL job",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
logger.info(`Sending password reset email for user ${userId}`, {
|
|
81
|
+
job: JOB_NAMES.SEND_RESET_PASSWORD_EMAIL,
|
|
82
|
+
userId,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const userRecord = await prisma.user.findUnique({
|
|
86
|
+
where: { id: userId },
|
|
87
|
+
select: { email: true, name: true },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (!userRecord?.email) {
|
|
91
|
+
throw new Error(`User ${userId} not found or has no email`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const template = passwordResetEmail({
|
|
95
|
+
name: userRecord.name,
|
|
96
|
+
resetUrl,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await emailService.sendEmail(
|
|
100
|
+
userRecord.email,
|
|
101
|
+
template.subject,
|
|
102
|
+
template.html,
|
|
103
|
+
template.text,
|
|
71
104
|
);
|
|
72
105
|
|
|
73
106
|
return { success: true, userId, email: userRecord.email };
|
|
@@ -79,6 +112,7 @@ async function handleSendWelcomeEmail(bullJob) {
|
|
|
79
112
|
*/
|
|
80
113
|
const jobHandlers = {
|
|
81
114
|
[JOB_NAMES.SEND_WELCOME_EMAIL]: handleSendWelcomeEmail,
|
|
115
|
+
[JOB_NAMES.SEND_RESET_PASSWORD_EMAIL]: handleSendResetPasswordEmail,
|
|
82
116
|
};
|
|
83
117
|
|
|
84
118
|
/**
|
|
@@ -113,11 +147,14 @@ async function startWorker() {
|
|
|
113
147
|
});
|
|
114
148
|
|
|
115
149
|
emailQueueWorker.on("failed", (job, error) => {
|
|
116
|
-
logger.error(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
150
|
+
logger.error(
|
|
151
|
+
`Job ${job.id} (${job.name}) failed after ${job.attemptsMade} attempts`,
|
|
152
|
+
{
|
|
153
|
+
error: error.message,
|
|
154
|
+
jobName: job.name,
|
|
155
|
+
attemptsMade: job.attemptsMade,
|
|
156
|
+
},
|
|
157
|
+
);
|
|
121
158
|
});
|
|
122
159
|
|
|
123
160
|
logger.info(
|
|
@@ -127,7 +164,10 @@ async function startWorker() {
|
|
|
127
164
|
// Ready to process jobs
|
|
128
165
|
logger.info("Worker service ready");
|
|
129
166
|
} catch (error) {
|
|
130
|
-
logger.error("Failed to start worker service", {
|
|
167
|
+
logger.error("Failed to start worker service", {
|
|
168
|
+
error: error.message,
|
|
169
|
+
stack: error.stack,
|
|
170
|
+
});
|
|
131
171
|
process.exit(1);
|
|
132
172
|
}
|
|
133
173
|
}
|
|
@@ -150,7 +190,10 @@ async function shutdown() {
|
|
|
150
190
|
logger.info("All workers closed");
|
|
151
191
|
process.exit(0);
|
|
152
192
|
} catch (error) {
|
|
153
|
-
logger.error("Error during shutdown", {
|
|
193
|
+
logger.error("Error during shutdown", {
|
|
194
|
+
error: error.message,
|
|
195
|
+
stack: error.stack,
|
|
196
|
+
});
|
|
154
197
|
process.exit(1);
|
|
155
198
|
}
|
|
156
199
|
}
|
|
@@ -18,7 +18,13 @@
|
|
|
18
18
|
"license": "ISC",
|
|
19
19
|
"packageManager": "pnpm@10.12.1",
|
|
20
20
|
"pnpm": {
|
|
21
|
-
"onlyBuiltDependencies": [
|
|
21
|
+
"onlyBuiltDependencies": [
|
|
22
|
+
"@prisma/engines",
|
|
23
|
+
"esbuild",
|
|
24
|
+
"msgpackr-extract",
|
|
25
|
+
"prisma",
|
|
26
|
+
"sharp"
|
|
27
|
+
],
|
|
22
28
|
"peerDependencyRules": {
|
|
23
29
|
"allowedVersions": {
|
|
24
30
|
"nodemailer": "*"
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { PrismaPg } from "@prisma/adapter-pg";
|
|
2
2
|
import { PrismaClient } from "./generated/prisma/client.ts";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
if (!
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
4
|
+
/**
|
|
5
|
+
* Builds a Postgres connection string from individual env vars (mirrors prisma.config.ts).
|
|
6
|
+
* Throws if any required variable is missing — but only when actually called,
|
|
7
|
+
* so the module can be safely imported at build time (e.g. during `next build`).
|
|
8
|
+
*/
|
|
9
|
+
function getConnectionString() {
|
|
10
|
+
const user = process.env.POSTGRES_USER;
|
|
11
|
+
if (!user) throw new Error("POSTGRES_USER environment variable is required");
|
|
12
|
+
const password = process.env.POSTGRES_PASSWORD;
|
|
13
|
+
if (!password)
|
|
14
|
+
throw new Error("POSTGRES_PASSWORD environment variable is required");
|
|
15
|
+
const host = process.env.POSTGRES_HOST || "localhost";
|
|
16
|
+
const port = process.env.POSTGRES_PORT || "5432";
|
|
17
|
+
const db = process.env.POSTGRES_DB;
|
|
18
|
+
if (!db) throw new Error("POSTGRES_DB environment variable is required");
|
|
19
|
+
return `postgresql://${user}:${password}@${host}:${port}/${db}?schema=public`;
|
|
20
|
+
}
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* Returns the connection pool configuration for the `pg` driver.
|
|
@@ -26,6 +30,7 @@ const isProduction = process.env.NODE_ENV === "production";
|
|
|
26
30
|
* @returns {{ max: number, idleTimeoutMillis: number, connectionTimeoutMillis: number }}
|
|
27
31
|
*/
|
|
28
32
|
export function getPoolConfig() {
|
|
33
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
29
34
|
return {
|
|
30
35
|
max: Number(process.env.DB_POOL_MAX) || (isProduction ? 10 : 5),
|
|
31
36
|
idleTimeoutMillis: Number(process.env.DB_POOL_IDLE_TIMEOUT) || 30_000,
|
|
@@ -34,19 +39,30 @@ export function getPoolConfig() {
|
|
|
34
39
|
};
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
//
|
|
42
|
+
// Lazy singleton — the client is created on first property access, not at import time.
|
|
43
|
+
// This allows Next.js to import the module at build time without requiring DB env vars.
|
|
38
44
|
const globalForPrisma = globalThis;
|
|
39
|
-
export const prisma =
|
|
40
|
-
globalForPrisma.prisma ||
|
|
41
|
-
new PrismaClient({
|
|
42
|
-
adapter: new PrismaPg({
|
|
43
|
-
connectionString,
|
|
44
|
-
...getPoolConfig(),
|
|
45
|
-
}),
|
|
46
|
-
});
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
globalForPrisma.
|
|
46
|
+
function getPrismaClient() {
|
|
47
|
+
if (!globalForPrisma.__prisma) {
|
|
48
|
+
globalForPrisma.__prisma = new PrismaClient({
|
|
49
|
+
adapter: new PrismaPg({
|
|
50
|
+
connectionString: getConnectionString(),
|
|
51
|
+
...getPoolConfig(),
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return globalForPrisma.__prisma;
|
|
50
56
|
}
|
|
51
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Prisma client singleton. Lazily initialized on first use so the module
|
|
60
|
+
* can be imported safely at build time (no DB env vars needed).
|
|
61
|
+
*/
|
|
62
|
+
export const prisma = new Proxy(/** @type {PrismaClient} */ ({}), {
|
|
63
|
+
get(_target, prop) {
|
|
64
|
+
return getPrismaClient()[prop];
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
52
68
|
export * from "./generated/prisma/client.ts";
|
|
@@ -20,7 +20,22 @@
|
|
|
20
20
|
"dev": {
|
|
21
21
|
"cache": false,
|
|
22
22
|
"persistent": true,
|
|
23
|
-
"passThroughEnv": [
|
|
23
|
+
"passThroughEnv": [
|
|
24
|
+
"PORT",
|
|
25
|
+
"POSTGRES_HOST",
|
|
26
|
+
"POSTGRES_PORT",
|
|
27
|
+
"POSTGRES_USER",
|
|
28
|
+
"POSTGRES_PASSWORD",
|
|
29
|
+
"POSTGRES_DB",
|
|
30
|
+
"REDIS_HOST",
|
|
31
|
+
"REDIS_PORT",
|
|
32
|
+
"MAILHOG_HOST",
|
|
33
|
+
"MAILHOG_SMTP_PORT",
|
|
34
|
+
"MAILHOG_UI_PORT",
|
|
35
|
+
"NEXTAUTH_SECRET",
|
|
36
|
+
"APP_URL",
|
|
37
|
+
"WORKER_CONCURRENCY"
|
|
38
|
+
]
|
|
24
39
|
}
|
|
25
40
|
}
|
|
26
41
|
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
|
2
|
-
/* eslint-disable */
|
|
3
|
-
// biome-ignore-all lint: generated file
|
|
4
|
-
// @ts-nocheck
|
|
5
|
-
/*
|
|
6
|
-
* This file should be your main import to use Prisma-related types and utilities in a browser.
|
|
7
|
-
* Use it to get access to models, enums, and input types.
|
|
8
|
-
*
|
|
9
|
-
* This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
|
|
10
|
-
* See `client.ts` for the standard, server-side entry point.
|
|
11
|
-
*
|
|
12
|
-
* 🟢 You can import this file directly.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import * as Prisma from "./internal/prismaNamespaceBrowser.ts";
|
|
16
|
-
export { Prisma };
|
|
17
|
-
export * as $Enums from "./enums.ts";
|
|
18
|
-
export * from "./enums.ts";
|
|
19
|
-
/**
|
|
20
|
-
* Model User
|
|
21
|
-
*
|
|
22
|
-
*/
|
|
23
|
-
export type User = Prisma.UserModel;
|
|
24
|
-
/**
|
|
25
|
-
* Model Post
|
|
26
|
-
*
|
|
27
|
-
*/
|
|
28
|
-
export type Post = Prisma.PostModel;
|
|
29
|
-
/**
|
|
30
|
-
* Model Account
|
|
31
|
-
*
|
|
32
|
-
*/
|
|
33
|
-
export type Account = Prisma.AccountModel;
|
|
34
|
-
/**
|
|
35
|
-
* Model Session
|
|
36
|
-
*
|
|
37
|
-
*/
|
|
38
|
-
export type Session = Prisma.SessionModel;
|
|
39
|
-
/**
|
|
40
|
-
* Model VerificationToken
|
|
41
|
-
*
|
|
42
|
-
*/
|
|
43
|
-
export type VerificationToken = Prisma.VerificationTokenModel;
|
|
44
|
-
/**
|
|
45
|
-
* Model Job
|
|
46
|
-
*
|
|
47
|
-
*/
|
|
48
|
-
export type Job = Prisma.JobModel;
|
|
49
|
-
/**
|
|
50
|
-
* Model AuditLog
|
|
51
|
-
*
|
|
52
|
-
*/
|
|
53
|
-
export type AuditLog = Prisma.AuditLogModel;
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
|
2
|
-
/* eslint-disable */
|
|
3
|
-
// biome-ignore-all lint: generated file
|
|
4
|
-
// @ts-nocheck
|
|
5
|
-
/*
|
|
6
|
-
* This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
|
|
7
|
-
* If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead.
|
|
8
|
-
*
|
|
9
|
-
* 🟢 You can import this file directly.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
import * as process from "node:process";
|
|
14
|
-
import { fileURLToPath } from "node:url";
|
|
15
|
-
|
|
16
|
-
globalThis["__dirname"] = path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
-
|
|
18
|
-
import * as runtime from "@prisma/client/runtime/client";
|
|
19
|
-
import * as $Enums from "./enums.ts";
|
|
20
|
-
import * as $Class from "./internal/class.ts";
|
|
21
|
-
import * as Prisma from "./internal/prismaNamespace.ts";
|
|
22
|
-
|
|
23
|
-
export * as $Enums from "./enums.ts";
|
|
24
|
-
export * from "./enums.ts";
|
|
25
|
-
/**
|
|
26
|
-
* ## Prisma Client
|
|
27
|
-
*
|
|
28
|
-
* Type-safe database client for TypeScript
|
|
29
|
-
* @example
|
|
30
|
-
* ```
|
|
31
|
-
* const prisma = new PrismaClient()
|
|
32
|
-
* // Fetch zero or more Users
|
|
33
|
-
* const users = await prisma.user.findMany()
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client).
|
|
37
|
-
*/
|
|
38
|
-
export const PrismaClient = $Class.getPrismaClientClass();
|
|
39
|
-
export type PrismaClient<
|
|
40
|
-
LogOpts extends Prisma.LogLevel = never,
|
|
41
|
-
OmitOpts extends
|
|
42
|
-
Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"],
|
|
43
|
-
ExtArgs extends
|
|
44
|
-
runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs,
|
|
45
|
-
> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>;
|
|
46
|
-
export { Prisma };
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Model User
|
|
50
|
-
*
|
|
51
|
-
*/
|
|
52
|
-
export type User = Prisma.UserModel;
|
|
53
|
-
/**
|
|
54
|
-
* Model Post
|
|
55
|
-
*
|
|
56
|
-
*/
|
|
57
|
-
export type Post = Prisma.PostModel;
|
|
58
|
-
/**
|
|
59
|
-
* Model Account
|
|
60
|
-
*
|
|
61
|
-
*/
|
|
62
|
-
export type Account = Prisma.AccountModel;
|
|
63
|
-
/**
|
|
64
|
-
* Model Session
|
|
65
|
-
*
|
|
66
|
-
*/
|
|
67
|
-
export type Session = Prisma.SessionModel;
|
|
68
|
-
/**
|
|
69
|
-
* Model VerificationToken
|
|
70
|
-
*
|
|
71
|
-
*/
|
|
72
|
-
export type VerificationToken = Prisma.VerificationTokenModel;
|
|
73
|
-
/**
|
|
74
|
-
* Model Job
|
|
75
|
-
*
|
|
76
|
-
*/
|
|
77
|
-
export type Job = Prisma.JobModel;
|
|
78
|
-
/**
|
|
79
|
-
* Model AuditLog
|
|
80
|
-
*
|
|
81
|
-
*/
|
|
82
|
-
export type AuditLog = Prisma.AuditLogModel;
|