@techstream/quark-create-app 1.5.3 → 1.7.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.
Files changed (53) hide show
  1. package/package.json +4 -2
  2. package/src/index.js +62 -14
  3. package/templates/base-project/.github/dependabot.yml +12 -0
  4. package/templates/base-project/.github/workflows/ci.yml +97 -0
  5. package/templates/base-project/.github/workflows/dependabot-auto-merge.yml +22 -0
  6. package/templates/base-project/.github/workflows/release.yml +38 -0
  7. package/templates/base-project/apps/web/biome.json +7 -0
  8. package/templates/base-project/apps/web/jsconfig.json +5 -5
  9. package/templates/base-project/apps/web/next.config.js +90 -1
  10. package/templates/base-project/apps/web/package.json +7 -7
  11. package/templates/base-project/apps/web/railway.json +15 -0
  12. package/templates/base-project/apps/web/src/app/api/auth/register/route.js +6 -7
  13. package/templates/base-project/apps/web/src/app/layout.js +3 -4
  14. package/templates/base-project/apps/web/src/app/manifest.js +12 -0
  15. package/templates/base-project/apps/web/src/app/robots.js +21 -0
  16. package/templates/base-project/apps/web/src/app/sitemap.js +20 -0
  17. package/templates/base-project/apps/web/src/lib/seo/indexing.js +23 -0
  18. package/templates/base-project/apps/web/src/lib/seo/site-metadata.js +33 -0
  19. package/templates/base-project/apps/web/src/proxy.js +1 -2
  20. package/templates/base-project/apps/worker/package.json +5 -5
  21. package/templates/base-project/apps/worker/railway.json +13 -0
  22. package/templates/base-project/apps/worker/src/index.js +30 -12
  23. package/templates/base-project/apps/worker/src/index.test.js +296 -15
  24. package/templates/base-project/biome.json +44 -0
  25. package/templates/base-project/docker-compose.yml +7 -4
  26. package/templates/base-project/package.json +1 -1
  27. package/templates/base-project/packages/db/package.json +1 -1
  28. package/templates/base-project/packages/db/prisma/schema.prisma +1 -17
  29. package/templates/base-project/packages/db/prisma.config.ts +8 -10
  30. package/templates/base-project/packages/db/scripts/seed.js +117 -30
  31. package/templates/base-project/packages/db/src/client.js +1 -18
  32. package/templates/base-project/packages/db/src/connection.js +44 -0
  33. package/templates/base-project/packages/db/src/connection.test.js +119 -0
  34. package/templates/base-project/packages/db/src/queries.js +52 -118
  35. package/templates/base-project/packages/db/src/queries.test.js +0 -29
  36. package/templates/base-project/packages/db/src/schemas.js +0 -12
  37. package/templates/base-project/pnpm-workspace.yaml +4 -0
  38. package/templates/base-project/turbo.json +5 -3
  39. package/templates/config/package.json +2 -0
  40. package/templates/config/src/environment.js +270 -0
  41. package/templates/config/src/index.js +13 -18
  42. package/templates/config/src/load-config.js +135 -0
  43. package/templates/config/src/validate-env.js +123 -16
  44. package/templates/jobs/package.json +2 -2
  45. package/templates/jobs/src/definitions.test.js +34 -0
  46. package/templates/jobs/src/index.js +1 -1
  47. package/templates/ui/package.json +4 -4
  48. package/templates/ui/src/button.test.js +23 -0
  49. package/templates/ui/src/index.js +1 -3
  50. package/templates/base-project/apps/web/src/app/api/posts/[id]/route.js +0 -65
  51. package/templates/base-project/apps/web/src/app/api/posts/route.js +0 -95
  52. package/templates/ui/src/card.js +0 -14
  53. package/templates/ui/src/input.js +0 -11
@@ -1,40 +1,127 @@
1
+ import { faker } from "@faker-js/faker";
1
2
  import bcrypt from "bcryptjs";
2
- import { PrismaClient } from "../src/generated/prisma/client.js";
3
+ import { prisma } from "../src/index.js";
3
4
 
4
- const prisma = new PrismaClient();
5
+ // Deterministic output change this integer to get a different but consistent dataset
6
+ faker.seed(42);
5
7
 
6
- async function main() {
7
- console.log("Seeding database...");
8
-
9
- const email = "test@example.com";
10
- const password = await bcrypt.hash("Password1", 12);
11
-
12
- const user = await prisma.user.upsert({
13
- where: { email },
14
- update: {},
15
- create: {
16
- email,
17
- name: "Test User",
18
- password,
19
- image: "https://api.dicebear.com/7.x/avataaars/svg?seed=test",
20
- posts: {
21
- create: [
22
- {
23
- title: "Hello World",
24
- content: "This is a seeded post. Welcome to Quark!",
25
- published: true,
26
- },
27
- {
28
- title: "Draft Post",
29
- content: "This is a draft post. It is not published yet.",
30
- published: false,
31
- },
32
- ],
8
+ const PROFILE = process.env.SEED_PROFILE ?? "dev";
9
+ const VALID_PROFILES = ["minimal", "dev"];
10
+
11
+ if (!VALID_PROFILES.includes(PROFILE)) {
12
+ console.error(
13
+ `Unknown SEED_PROFILE "${PROFILE}". Valid options: ${VALID_PROFILES.join(", ")}`,
14
+ );
15
+ process.exit(1);
16
+ }
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Seeders
20
+ // ---------------------------------------------------------------------------
21
+
22
+ async function seedUsers() {
23
+ const users = [
24
+ {
25
+ email: "admin@example.com",
26
+ name: "Admin User",
27
+ role: "admin",
28
+ password: "Password1",
29
+ },
30
+ {
31
+ email: "viewer@example.com",
32
+ name: "Viewer User",
33
+ role: "viewer",
34
+ password: "Password1",
35
+ },
36
+ ];
37
+
38
+ const seeded = [];
39
+ for (const userData of users) {
40
+ // Skip hashing if the user already exists — upsert update:{} won't use it anyway.
41
+ const existing = await prisma.user.findUnique({
42
+ where: { email: userData.email },
43
+ });
44
+ const hashed =
45
+ existing?.password ?? (await bcrypt.hash(userData.password, 12));
46
+ const user = await prisma.user.upsert({
47
+ where: { email: userData.email },
48
+ // update:{} intentionally leaves existing users unchanged on re-seed.
49
+ // To reset a user's password or role, delete the row first or update the create block.
50
+ update: {},
51
+ create: {
52
+ email: userData.email,
53
+ name: userData.name,
54
+ role: userData.role,
55
+ password: hashed,
56
+ image: `https://api.dicebear.com/7.x/avataaars/svg?seed=${userData.email}`,
33
57
  },
58
+ });
59
+ seeded.push(user);
60
+ console.log(` ✓ User: ${user.email} (${user.role})`);
61
+ }
62
+ return seeded;
63
+ }
64
+
65
+ async function seedDevData(users) {
66
+ // Audit logs — representative actions per user
67
+ const actions = ["user.login", "user.update", "file.upload"];
68
+ const userIds = users.map((u) => u.id);
69
+ // Scoped to seeded user IDs so real audit entries in a shared dev DB are not wiped.
70
+ await prisma.auditLog.deleteMany({
71
+ where: { userId: { in: userIds }, action: { in: actions } },
72
+ });
73
+ for (const user of users) {
74
+ for (const action of actions) {
75
+ await prisma.auditLog.create({
76
+ data: {
77
+ userId: user.id,
78
+ action,
79
+ entity: "User",
80
+ entityId: user.id,
81
+ metadata: {
82
+ ip: faker.internet.ip(),
83
+ userAgent: faker.internet.userAgent(),
84
+ },
85
+ },
86
+ });
87
+ }
88
+ }
89
+ console.log(` ✓ AuditLogs: ${users.length * actions.length} rows`);
90
+
91
+ // A sample pending job so the worker dashboard has something to show
92
+ await prisma.job.deleteMany({ where: { name: "seed-example-job" } });
93
+ await prisma.job.create({
94
+ data: {
95
+ queue: "default",
96
+ name: "seed-example-job",
97
+ data: { message: "Hello from seed" },
98
+ status: "PENDING",
34
99
  },
35
100
  });
101
+ console.log(" ✓ Job: seed-example-job (PENDING)");
102
+ }
103
+
104
+ // ---------------------------------------------------------------------------
105
+ // Add your own model seeders below and call them from main()
106
+ // Example:
107
+ // async function seedTeams(users) {
108
+ // await prisma.team.upsert({ where: { slug: "acme" }, update: {}, create: { ... } });
109
+ // }
110
+ // ---------------------------------------------------------------------------
111
+
112
+ async function main() {
113
+ console.log(`\nSeeding database [profile: ${PROFILE}]...\n`);
114
+
115
+ const users = await seedUsers();
116
+
117
+ if (PROFILE === "dev") {
118
+ await seedDevData(users);
119
+ }
120
+
121
+ // Add your seeders here:
122
+ // await seedTeams(users);
36
123
 
37
- console.log("Seeded user:", user.email);
124
+ console.log("\nDone.\n");
38
125
  }
39
126
 
40
127
  main()
@@ -1,24 +1,7 @@
1
1
  import { PrismaPg } from "@prisma/adapter-pg";
2
+ import { getConnectionString } from "./connection.js";
2
3
  import { PrismaClient } from "./generated/prisma/client.ts";
3
4
 
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
- }
21
-
22
5
  /**
23
6
  * Returns the connection pool configuration for the `pg` driver.
24
7
  *
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Shared connection string builder for PostgreSQL.
3
+ * Used by both the Prisma client (client.js) and Prisma CLI (prisma.config.ts).
4
+ *
5
+ * Priority: DATABASE_URL env var → assembled from POSTGRES_* env vars.
6
+ *
7
+ * @param {{ throwOnMissing?: boolean }} [options]
8
+ * - throwOnMissing=true (default) — runtime: throws if credentials are missing.
9
+ * - throwOnMissing=false — CLI/CI: returns a placeholder URL so `prisma generate` works.
10
+ * @returns {string} PostgreSQL connection string
11
+ */
12
+ export function getConnectionString({ throwOnMissing = true } = {}) {
13
+ // 1. Prefer an explicit DATABASE_URL if set
14
+ if (process.env.DATABASE_URL) {
15
+ return process.env.DATABASE_URL;
16
+ }
17
+
18
+ // 2. Assemble from individual POSTGRES_* vars
19
+ const user = process.env.POSTGRES_USER;
20
+ const password = process.env.POSTGRES_PASSWORD;
21
+ const host = process.env.POSTGRES_HOST || "localhost";
22
+ const port = process.env.POSTGRES_PORT || "5432";
23
+ const db = process.env.POSTGRES_DB;
24
+
25
+ const hasCredentials = user && password && db;
26
+
27
+ if (!hasCredentials) {
28
+ if (throwOnMissing) {
29
+ const missing = [];
30
+ if (!user) missing.push("POSTGRES_USER");
31
+ if (!password) missing.push("POSTGRES_PASSWORD");
32
+ if (!db) missing.push("POSTGRES_DB");
33
+ throw new Error(
34
+ `Missing required database environment variables: ${missing.join(", ")}. ` +
35
+ "Set DATABASE_URL or the individual POSTGRES_* variables.",
36
+ );
37
+ }
38
+
39
+ // Placeholder for prisma generate / CI — will fail at connect time, not at config time.
40
+ return "postgresql://placeholder:placeholder@localhost:5432/placeholder?schema=public";
41
+ }
42
+
43
+ return `postgresql://${user}:${password}@${host}:${port}/${db}?schema=public`;
44
+ }
@@ -0,0 +1,119 @@
1
+ import assert from "node:assert";
2
+ import { afterEach, beforeEach, describe, test } from "node:test";
3
+ import { getConnectionString } from "./connection.js";
4
+
5
+ describe("getConnectionString", () => {
6
+ const originalEnv = { ...process.env };
7
+
8
+ beforeEach(() => {
9
+ // Clear all DB-related env vars before each test
10
+ delete process.env.DATABASE_URL;
11
+ delete process.env.POSTGRES_USER;
12
+ delete process.env.POSTGRES_PASSWORD;
13
+ delete process.env.POSTGRES_HOST;
14
+ delete process.env.POSTGRES_PORT;
15
+ delete process.env.POSTGRES_DB;
16
+ });
17
+
18
+ afterEach(() => {
19
+ // Restore original env
20
+ process.env = { ...originalEnv };
21
+ });
22
+
23
+ test("returns DATABASE_URL when set", () => {
24
+ process.env.DATABASE_URL =
25
+ "postgresql://user:pass@remote:5433/mydb?schema=public";
26
+ const url = getConnectionString();
27
+ assert.strictEqual(url, process.env.DATABASE_URL);
28
+ });
29
+
30
+ test("DATABASE_URL takes priority over individual POSTGRES_* vars", () => {
31
+ process.env.DATABASE_URL =
32
+ "postgresql://url_user:url_pass@remote:5433/url_db?schema=public";
33
+ process.env.POSTGRES_USER = "individual_user";
34
+ process.env.POSTGRES_PASSWORD = "individual_pass";
35
+ process.env.POSTGRES_DB = "individual_db";
36
+
37
+ const url = getConnectionString();
38
+ assert.strictEqual(url, process.env.DATABASE_URL);
39
+ });
40
+
41
+ test("assembles from POSTGRES_* vars when DATABASE_URL is not set", () => {
42
+ process.env.POSTGRES_USER = "test_user";
43
+ process.env.POSTGRES_PASSWORD = "test_pass";
44
+ process.env.POSTGRES_DB = "test_db";
45
+
46
+ const url = getConnectionString();
47
+ assert.strictEqual(
48
+ url,
49
+ "postgresql://test_user:test_pass@localhost:5432/test_db?schema=public",
50
+ );
51
+ });
52
+
53
+ test("uses custom host and port when provided", () => {
54
+ process.env.POSTGRES_USER = "user";
55
+ process.env.POSTGRES_PASSWORD = "pass";
56
+ process.env.POSTGRES_HOST = "db.example.com";
57
+ process.env.POSTGRES_PORT = "5433";
58
+ process.env.POSTGRES_DB = "mydb";
59
+
60
+ const url = getConnectionString();
61
+ assert.strictEqual(
62
+ url,
63
+ "postgresql://user:pass@db.example.com:5433/mydb?schema=public",
64
+ );
65
+ });
66
+
67
+ test("throws when POSTGRES_USER is missing (throwOnMissing=true)", () => {
68
+ process.env.POSTGRES_PASSWORD = "pass";
69
+ process.env.POSTGRES_DB = "db";
70
+
71
+ assert.throws(() => getConnectionString(), {
72
+ message: /POSTGRES_USER/,
73
+ });
74
+ });
75
+
76
+ test("throws when POSTGRES_PASSWORD is missing (throwOnMissing=true)", () => {
77
+ process.env.POSTGRES_USER = "user";
78
+ process.env.POSTGRES_DB = "db";
79
+
80
+ assert.throws(() => getConnectionString(), {
81
+ message: /POSTGRES_PASSWORD/,
82
+ });
83
+ });
84
+
85
+ test("throws when POSTGRES_DB is missing (throwOnMissing=true)", () => {
86
+ process.env.POSTGRES_USER = "user";
87
+ process.env.POSTGRES_PASSWORD = "pass";
88
+
89
+ assert.throws(() => getConnectionString(), {
90
+ message: /POSTGRES_DB/,
91
+ });
92
+ });
93
+
94
+ test("lists all missing vars in error message", () => {
95
+ assert.throws(() => getConnectionString(), {
96
+ message: /POSTGRES_USER.*POSTGRES_PASSWORD.*POSTGRES_DB/,
97
+ });
98
+ });
99
+
100
+ test("returns placeholder when throwOnMissing=false and vars missing", () => {
101
+ const url = getConnectionString({ throwOnMissing: false });
102
+ assert.strictEqual(
103
+ url,
104
+ "postgresql://placeholder:placeholder@localhost:5432/placeholder?schema=public",
105
+ );
106
+ });
107
+
108
+ test("still assembles correctly with throwOnMissing=false when vars present", () => {
109
+ process.env.POSTGRES_USER = "user";
110
+ process.env.POSTGRES_PASSWORD = "pass";
111
+ process.env.POSTGRES_DB = "db";
112
+
113
+ const url = getConnectionString({ throwOnMissing: false });
114
+ assert.strictEqual(
115
+ url,
116
+ "postgresql://user:pass@localhost:5432/db?schema=public",
117
+ );
118
+ });
119
+ });
@@ -15,6 +15,8 @@ const USER_SAFE_SELECT = {
15
15
  updatedAt: true,
16
16
  };
17
17
 
18
+ export { USER_SAFE_SELECT };
19
+
18
20
  // User queries
19
21
  export const user = {
20
22
  findById: (id) => {
@@ -23,12 +25,7 @@ export const user = {
23
25
  select: USER_SAFE_SELECT,
24
26
  });
25
27
  },
26
- findByIdWithPosts: (id) => {
27
- return prisma.user.findUnique({
28
- where: { id },
29
- select: { ...USER_SAFE_SELECT, posts: true },
30
- });
31
- },
28
+
32
29
  /**
33
30
  * findByEmail returns ALL fields including password.
34
31
  * Only use for internal auth — never expose the result directly to clients.
@@ -67,69 +64,6 @@ export const user = {
67
64
  },
68
65
  };
69
66
 
70
- /**
71
- * Safe author include — returns author without sensitive fields.
72
- */
73
- const AUTHOR_SAFE_INCLUDE = { author: { select: USER_SAFE_SELECT } };
74
-
75
- // Post queries
76
- export const post = {
77
- findById: (id) => {
78
- return prisma.post.findUnique({
79
- where: { id },
80
- include: AUTHOR_SAFE_INCLUDE,
81
- });
82
- },
83
- findAll: (options = {}) => {
84
- const { skip = 0, take = 10, where, orderBy } = options;
85
- return prisma.post.findMany({
86
- where,
87
- skip,
88
- take,
89
- include: AUTHOR_SAFE_INCLUDE,
90
- orderBy: orderBy || { createdAt: "desc" },
91
- });
92
- },
93
- findPublished: (options = {}) => {
94
- const { skip = 0, take = 10 } = options;
95
- return prisma.post.findMany({
96
- where: { published: true },
97
- skip,
98
- take,
99
- include: AUTHOR_SAFE_INCLUDE,
100
- orderBy: { createdAt: "desc" },
101
- });
102
- },
103
- findByAuthor: (authorId, options = {}) => {
104
- const { skip = 0, take = 10 } = options;
105
- return prisma.post.findMany({
106
- where: { authorId },
107
- skip,
108
- take,
109
- include: AUTHOR_SAFE_INCLUDE,
110
- orderBy: { createdAt: "desc" },
111
- });
112
- },
113
- create: (data) => {
114
- return prisma.post.create({
115
- data,
116
- include: AUTHOR_SAFE_INCLUDE,
117
- });
118
- },
119
- update: (id, data) => {
120
- return prisma.post.update({
121
- where: { id },
122
- data,
123
- include: AUTHOR_SAFE_INCLUDE,
124
- });
125
- },
126
- delete: (id) => {
127
- return prisma.post.delete({
128
- where: { id },
129
- });
130
- },
131
- };
132
-
133
67
  // Note: Job tracking is handled by BullMQ's built-in Redis persistence.
134
68
  // The Prisma Job model is retained in the schema for optional audit/reporting
135
69
  // but these query helpers have been removed to avoid confusion with BullMQ.
@@ -231,6 +165,55 @@ export const verificationToken = {
231
165
  },
232
166
  };
233
167
 
168
+ // AuditLog queries
169
+ export const auditLog = {
170
+ findAll: (options = {}) => {
171
+ const { skip = 0, take = 50 } = options;
172
+ return prisma.auditLog.findMany({
173
+ skip,
174
+ take,
175
+ include: { user: { select: { id: true, email: true, name: true } } },
176
+ orderBy: { createdAt: "desc" },
177
+ });
178
+ },
179
+ findByUserId: (userId, options = {}) => {
180
+ const { skip = 0, take = 50 } = options;
181
+ return prisma.auditLog.findMany({
182
+ where: { userId },
183
+ skip,
184
+ take,
185
+ include: { user: { select: { id: true, email: true, name: true } } },
186
+ orderBy: { createdAt: "desc" },
187
+ });
188
+ },
189
+ findByEntity: (entity, options = {}) => {
190
+ const { skip = 0, take = 50 } = options;
191
+ return prisma.auditLog.findMany({
192
+ where: { entity },
193
+ skip,
194
+ take,
195
+ include: { user: { select: { id: true, email: true, name: true } } },
196
+ orderBy: { createdAt: "desc" },
197
+ });
198
+ },
199
+ findByAction: (action, options = {}) => {
200
+ const { skip = 0, take = 50 } = options;
201
+ return prisma.auditLog.findMany({
202
+ where: { action },
203
+ skip,
204
+ take,
205
+ include: { user: { select: { id: true, email: true, name: true } } },
206
+ orderBy: { createdAt: "desc" },
207
+ });
208
+ },
209
+ create: (data) => {
210
+ return prisma.auditLog.create({
211
+ data,
212
+ include: { user: { select: { id: true, email: true, name: true } } },
213
+ });
214
+ },
215
+ };
216
+
234
217
  // File queries
235
218
  export const file = {
236
219
  create: (data) => {
@@ -285,52 +268,3 @@ export const file = {
285
268
  return prisma.file.count({ where });
286
269
  },
287
270
  };
288
-
289
- // AuditLog queries
290
- export const auditLog = {
291
- findAll: (options = {}) => {
292
- const { skip = 0, take = 50 } = options;
293
- return prisma.auditLog.findMany({
294
- skip,
295
- take,
296
- include: { user: { select: { id: true, email: true, name: true } } },
297
- orderBy: { createdAt: "desc" },
298
- });
299
- },
300
- findByUserId: (userId, options = {}) => {
301
- const { skip = 0, take = 50 } = options;
302
- return prisma.auditLog.findMany({
303
- where: { userId },
304
- skip,
305
- take,
306
- include: { user: { select: { id: true, email: true, name: true } } },
307
- orderBy: { createdAt: "desc" },
308
- });
309
- },
310
- findByEntity: (entity, options = {}) => {
311
- const { skip = 0, take = 50 } = options;
312
- return prisma.auditLog.findMany({
313
- where: { entity },
314
- skip,
315
- take,
316
- include: { user: { select: { id: true, email: true, name: true } } },
317
- orderBy: { createdAt: "desc" },
318
- });
319
- },
320
- findByAction: (action, options = {}) => {
321
- const { skip = 0, take = 50 } = options;
322
- return prisma.auditLog.findMany({
323
- where: { action },
324
- skip,
325
- take,
326
- include: { user: { select: { id: true, email: true, name: true } } },
327
- orderBy: { createdAt: "desc" },
328
- });
329
- },
330
- create: (data) => {
331
- return prisma.auditLog.create({
332
- data,
333
- include: { user: { select: { id: true, email: true, name: true } } },
334
- });
335
- },
336
- };
@@ -7,10 +7,6 @@ const _mockPrisma = {
7
7
  findUnique: async (params) => params,
8
8
  create: async (params) => params,
9
9
  },
10
- post: {
11
- create: async (params) => params,
12
- findMany: async (params) => params,
13
- },
14
10
  };
15
11
 
16
12
  // Mock module for queries
@@ -31,15 +27,6 @@ const mockQueries = {
31
27
  ...data,
32
28
  }),
33
29
  },
34
- post: {
35
- create: async (data) => ({
36
- id: "1",
37
- ...data,
38
- }),
39
- findPublished: async () => [
40
- { id: "1", title: "Published", published: true },
41
- ],
42
- },
43
30
  };
44
31
 
45
32
  test("User Queries - findById calls prisma with correct params", async () => {
@@ -61,19 +48,3 @@ test("User Queries - create calls prisma with correct params", async () => {
61
48
  assert.strictEqual(result.email, "new@example.com");
62
49
  assert.strictEqual(result.name, "New User");
63
50
  });
64
-
65
- test("Post Queries - create calls prisma with correct params", async () => {
66
- const result = await mockQueries.post.create({
67
- title: "Test Post",
68
- authorId: "1",
69
- });
70
- assert.strictEqual(result.title, "Test Post");
71
- assert.strictEqual(result.authorId, "1");
72
- });
73
-
74
- test("Post Queries - findPublished returns only published posts", async () => {
75
- const result = await mockQueries.post.findPublished();
76
- assert.ok(Array.isArray(result));
77
- assert.strictEqual(result.length, 1);
78
- assert.strictEqual(result[0].published, true);
79
- });
@@ -23,18 +23,6 @@ export const userUpdateSchema = z.object({
23
23
  image: z.string().url().optional(),
24
24
  });
25
25
 
26
- export const postCreateSchema = z.object({
27
- title: z.string().min(1, "Title is required"),
28
- content: z.string().optional(),
29
- published: z.boolean().optional(),
30
- });
31
-
32
- export const postUpdateSchema = z.object({
33
- title: z.string().min(1, "Title is required").optional(),
34
- content: z.string().optional(),
35
- published: z.boolean().optional(),
36
- });
37
-
38
26
  export const fileUploadSchema = z.object({
39
27
  filename: z.string().min(1, "Filename is required"),
40
28
  mimeType: z.string().min(1, "MIME type is required"),
@@ -5,3 +5,7 @@ packages:
5
5
  onlyBuiltDependencies:
6
6
  - '@prisma/engines'
7
7
  - prisma
8
+ - esbuild
9
+ - msgpackr-extract
10
+ - sharp
11
+ - simple-git-hooks
@@ -26,9 +26,11 @@
26
26
  "db:seed": {
27
27
  "cache": false
28
28
  },
29
- "db:studio": {
30
- "cache": false,
31
- "persistent": true
29
+ "sync-templates": {
30
+ "cache": false
31
+ },
32
+ "sync-templates:check": {
33
+ "cache": false
32
34
  },
33
35
  "dev": {
34
36
  "cache": false,
@@ -5,6 +5,8 @@
5
5
  "exports": {
6
6
  ".": "./src/index.js",
7
7
  "./app-url": "./src/app-url.js",
8
+ "./environment": "./src/environment.js",
9
+ "./load-config": "./src/load-config.js",
8
10
  "./validate-env": "./src/validate-env.js"
9
11
  }
10
12
  }