create-ej-app 2.1.0 → 2.3.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/cli.js CHANGED
@@ -6,81 +6,84 @@ const path = require('path')
6
6
  const { prompt } = require('enquirer')
7
7
  const copydir = require('copy-dir')
8
8
 
9
- program
10
- .version('2.1.0')
11
- .description('CLI tool to bootstrap a Next.js App')
12
- .action(async () => {
13
- const response = await prompt([
14
- {
15
- type: 'input',
16
- name: 'projectName',
17
- message: 'Enter the project name:',
18
- initial: 'ej-app'
19
- },
20
- {
21
- type: 'input',
22
- name: 'description',
23
- message: 'Enter a description for the project:',
24
- initial: 'A Legendary Next.js App'
25
- },
26
- {
27
- type: 'select',
28
- name: 'template',
29
- message: 'Select a template:',
30
- choices: [
31
- { name: 'Base', value: 'base' },
32
- {
33
- name: 'With User Types and ACLs (roles & permissions)',
34
- value: 'advanced'
35
- }
36
- ],
37
- initial: 0
38
- }
39
- ])
40
-
41
- const { projectName, description, template } = response
42
-
43
- // Create a directory with the project name
44
- const projectDir = path.join(process.cwd(), projectName)
45
-
46
- if (fs.existsSync(projectDir)) {
47
- console.error(`Error: Directory '${projectName}' already exists.`)
48
- process.exit(1)
9
+ program.action(async () => {
10
+ const response = await prompt([
11
+ {
12
+ type: 'input',
13
+ name: 'projectName',
14
+ message: 'Enter the project name:',
15
+ initial: 'ej-app'
16
+ },
17
+ {
18
+ type: 'input',
19
+ name: 'description',
20
+ message: 'Enter a description for the project:',
21
+ initial: 'A Legendary App'
22
+ },
23
+ {
24
+ type: 'select',
25
+ name: 'template',
26
+ message: 'Select a template:',
27
+ choices: [
28
+ {
29
+ name: 'base',
30
+ message: 'Base setup with ts, shadcn, prisma, auth, editor.js'
31
+ },
32
+ {
33
+ name: 'advanced',
34
+ message:
35
+ 'Advanced setup with User Types and ACLs (roles & permissions)'
36
+ }
37
+ ]
49
38
  }
39
+ ])
50
40
 
51
- fs.mkdirSync(projectDir)
41
+ const { projectName, description, template } = response
52
42
 
53
- // Copy all files and subdirectories from your template folder to the new project directory
54
- const templateDir = path.join(__dirname, 'template', template)
55
- copydir.sync(templateDir, projectDir)
43
+ // Create a directory with the project name
44
+ const projectDir = path.join(process.cwd(), projectName)
56
45
 
57
- // Modify package.json in the new project directory to set the project name and description
58
- const packageJsonFile = path.join(projectDir, 'package.json')
59
- const packageJson = JSON.parse(fs.readFileSync(packageJsonFile, 'utf-8'))
60
- packageJson.name = projectName
61
- packageJson.description = description
62
- fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2))
46
+ if (fs.existsSync(projectDir)) {
47
+ console.error(`Error: Directory '${projectName}' already exists.`)
48
+ process.exit(1)
49
+ }
63
50
 
64
- // Modify src/lib/siteConfig.ts in the new project directory to set the project name and description
65
- const siteConfigFile = path.join(projectDir, 'src', 'lib', 'siteConfig.ts')
66
- let siteConfig = fs.readFileSync(siteConfigFile, 'utf-8')
67
- siteConfig = siteConfig.replace('Project Name', projectName)
68
- siteConfig = siteConfig.replace('Project Description', description)
69
- fs.writeFileSync(siteConfigFile, siteConfig)
51
+ fs.mkdirSync(projectDir)
70
52
 
71
- // Copy .env.example to .env
72
- const envExampleFile = path.join(projectDir, '.env.example')
73
- const envExample = fs.readFileSync(envExampleFile, 'utf-8')
74
- fs.writeFileSync(path.join(projectDir, '.env'), envExample)
53
+ // Copy all files and subdirectories from your template folder to the new project directory
54
+ const templateDir = path.join(__dirname, 'template', template)
55
+ copydir.sync(templateDir, projectDir)
75
56
 
76
- console.log(`Created a new Next.js app called '${projectName}'
57
+ // Modify package.json in the new project directory to set the project name and description
58
+ const packageJsonFile = path.join(projectDir, 'package.json')
59
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonFile, 'utf-8'))
60
+ packageJson.name = projectName
61
+ packageJson.description = description
62
+ fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2))
63
+
64
+ // Modify src/lib/siteConfig.ts in the new project directory to set the project name and description
65
+ const siteConfigFile = path.join(projectDir, 'src', 'lib', 'siteConfig.ts')
66
+ let siteConfig = fs.readFileSync(siteConfigFile, 'utf-8')
67
+ siteConfig = siteConfig.replace('Project Name', projectName)
68
+ siteConfig = siteConfig.replace('Project Description', description)
69
+ fs.writeFileSync(siteConfigFile, siteConfig)
70
+
71
+ // Copy .env.example to .env
72
+ const envExampleFile = path.join(projectDir, '.env.example')
73
+ const envExample = fs.readFileSync(envExampleFile, 'utf-8')
74
+ fs.writeFileSync(path.join(projectDir, '.env'), envExample)
75
+
76
+ console.log(`Created a new app called '${projectName}' 🎉
77
77
 
78
78
 
79
79
  To get started, run the following commands:
80
80
 
81
81
  cd ${projectName}
82
+
82
83
  npm install
83
- npm run dev`)
84
- })
84
+
85
+ npm run dev
86
+ `)
87
+ })
85
88
 
86
89
  program.parse(process.argv)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ej-app",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "Bootstrap a next.js app with my preferred setup",
5
5
  "main": "cli.js",
6
6
  "scripts": {
@@ -149,5 +149,6 @@ model Resource {
149
149
  createdAt DateTime @default(now()) @db.Timestamptz()
150
150
  updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
151
151
 
152
+ @@index([taskId])
152
153
  @@map("Resources")
153
154
  }
@@ -5,8 +5,41 @@ import { revalidatePath } from 'next/cache'
5
5
 
6
6
  import { authGuard } from '@/lib/auth'
7
7
  import { prisma } from '@/lib/db'
8
+ import { storageClient } from '@/lib/storageClient'
8
9
  import { UnwrapPromise } from '@/types/UnwrapPromise'
9
10
 
11
+ const handleImages = async (imageIds: string[], taskId: string) => {
12
+ const prevImages = await prisma.resource.findMany({
13
+ where: {
14
+ taskId
15
+ }
16
+ })
17
+
18
+ for (const p of prevImages) {
19
+ if (imageIds.includes(p.id)) continue
20
+ await Promise.all([
21
+ storageClient.deleteFile(p.newFilename),
22
+ prisma.resource.delete({
23
+ where: {
24
+ id: p.id
25
+ }
26
+ })
27
+ ])
28
+ }
29
+
30
+ if (imageIds.length)
31
+ await prisma.resource.updateMany({
32
+ where: {
33
+ id: {
34
+ in: imageIds
35
+ }
36
+ },
37
+ data: {
38
+ taskId
39
+ }
40
+ })
41
+ }
42
+
10
43
  export const getTask = async (id: string) => {
11
44
  const session = await authGuard(['Root', 'Normal'], 'TaskView')
12
45
  if (!session) throw new Error('Unauthorized')
@@ -57,25 +90,7 @@ export const createTask = async ({
57
90
  updatedById: session.user.id
58
91
  }
59
92
  })
60
- await prisma.resource.updateMany({
61
- where: {
62
- taskId: id
63
- },
64
- data: {
65
- taskId: null
66
- }
67
- })
68
- if (imageIds.length)
69
- await prisma.resource.updateMany({
70
- where: {
71
- id: {
72
- in: imageIds
73
- }
74
- },
75
- data: {
76
- taskId: id
77
- }
78
- })
93
+ await handleImages(imageIds, id)
79
94
 
80
95
  revalidatePath('/tasks')
81
96
  revalidatePath(`/tasks/${id}`)
@@ -110,25 +125,7 @@ export const updateTask = async ({
110
125
  updatedById: session.user.id
111
126
  }
112
127
  })
113
- await prisma.resource.updateMany({
114
- where: {
115
- taskId: id
116
- },
117
- data: {
118
- taskId: null
119
- }
120
- })
121
- if (imageIds.length)
122
- await prisma.resource.updateMany({
123
- where: {
124
- id: {
125
- in: imageIds
126
- }
127
- },
128
- data: {
129
- taskId: id
130
- }
131
- })
128
+ await handleImages(imageIds, id)
132
129
 
133
130
  revalidatePath('/tasks')
134
131
  revalidatePath(`/tasks/${id}`)
@@ -138,6 +135,7 @@ export const deleteTask = async (id: string) => {
138
135
  const session = await authGuard(['Root', 'Normal'], 'TaskDelete')
139
136
  if (!session) throw new Error('Unauthorized')
140
137
 
138
+ await handleImages([], id)
141
139
  await prisma.task.delete({
142
140
  where: {
143
141
  id
@@ -1,17 +1,8 @@
1
- import { GCPStorageClient } from '@ejekanshjain/cloud-storage'
2
1
  import { NextRequest, NextResponse } from 'next/server'
3
2
 
4
- import { env } from '@/env.mjs'
5
3
  import { getAuthSession } from '@/lib/auth'
6
4
  import { prisma } from '@/lib/db'
7
-
8
- const storageClient = GCPStorageClient({
9
- projectId: env.FIREBASE_PROJECT_ID!,
10
- privateKey: env.FIREBASE_PRIVATE_KEY!,
11
- clientEmail: env.FIREBASE_CLIENT_EMAIL!,
12
- bucket: env.FIREBASE_STORAGE_BUCKET!,
13
- defaultMediaPublic: true
14
- })
5
+ import { storageClient } from '@/lib/storageClient'
15
6
 
16
7
  export async function POST(request: NextRequest) {
17
8
  const session = await getAuthSession()
@@ -0,0 +1,11 @@
1
+ import { GCPStorageClient } from '@ejekanshjain/cloud-storage'
2
+
3
+ import { env } from '@/env.mjs'
4
+
5
+ export const storageClient = GCPStorageClient({
6
+ projectId: env.FIREBASE_PROJECT_ID!,
7
+ privateKey: env.FIREBASE_PRIVATE_KEY!,
8
+ clientEmail: env.FIREBASE_CLIENT_EMAIL!,
9
+ bucket: env.FIREBASE_STORAGE_BUCKET!,
10
+ defaultMediaPublic: true
11
+ })
@@ -111,5 +111,6 @@ model Resource {
111
111
  createdAt DateTime @default(now()) @db.Timestamptz()
112
112
  updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
113
113
 
114
+ @@index([taskId])
114
115
  @@map("Resources")
115
116
  }
@@ -5,8 +5,41 @@ import { revalidatePath } from 'next/cache'
5
5
 
6
6
  import { getAuthSession } from '@/lib/auth'
7
7
  import { prisma } from '@/lib/db'
8
+ import { storageClient } from '@/lib/storageClient'
8
9
  import { UnwrapPromise } from '@/types/UnwrapPromise'
9
10
 
11
+ const handleImages = async (imageIds: string[], taskId: string) => {
12
+ const prevImages = await prisma.resource.findMany({
13
+ where: {
14
+ taskId
15
+ }
16
+ })
17
+
18
+ for (const p of prevImages) {
19
+ if (imageIds.includes(p.id)) continue
20
+ await Promise.all([
21
+ storageClient.deleteFile(p.newFilename),
22
+ prisma.resource.delete({
23
+ where: {
24
+ id: p.id
25
+ }
26
+ })
27
+ ])
28
+ }
29
+
30
+ if (imageIds.length)
31
+ await prisma.resource.updateMany({
32
+ where: {
33
+ id: {
34
+ in: imageIds
35
+ }
36
+ },
37
+ data: {
38
+ taskId
39
+ }
40
+ })
41
+ }
42
+
10
43
  export const getTask = async (id: string) => {
11
44
  const session = await getAuthSession()
12
45
  if (!session) throw new Error('Unauthorized')
@@ -57,25 +90,7 @@ export const createTask = async ({
57
90
  updatedById: session.user.id
58
91
  }
59
92
  })
60
- await prisma.resource.updateMany({
61
- where: {
62
- taskId: id
63
- },
64
- data: {
65
- taskId: null
66
- }
67
- })
68
- if (imageIds.length)
69
- await prisma.resource.updateMany({
70
- where: {
71
- id: {
72
- in: imageIds
73
- }
74
- },
75
- data: {
76
- taskId: id
77
- }
78
- })
93
+ await handleImages(imageIds, id)
79
94
 
80
95
  revalidatePath('/tasks')
81
96
  revalidatePath(`/tasks/${id}`)
@@ -110,25 +125,7 @@ export const updateTask = async ({
110
125
  updatedById: session.user.id
111
126
  }
112
127
  })
113
- await prisma.resource.updateMany({
114
- where: {
115
- taskId: id
116
- },
117
- data: {
118
- taskId: null
119
- }
120
- })
121
- if (imageIds.length)
122
- await prisma.resource.updateMany({
123
- where: {
124
- id: {
125
- in: imageIds
126
- }
127
- },
128
- data: {
129
- taskId: id
130
- }
131
- })
128
+ await handleImages(imageIds, id)
132
129
 
133
130
  revalidatePath('/tasks')
134
131
  revalidatePath(`/tasks/${id}`)
@@ -138,6 +135,7 @@ export const deleteTask = async (id: string) => {
138
135
  const session = await getAuthSession()
139
136
  if (!session) throw new Error('Unauthorized')
140
137
 
138
+ await handleImages([], id)
141
139
  await prisma.task.delete({
142
140
  where: {
143
141
  id
@@ -1,17 +1,8 @@
1
- import { GCPStorageClient } from '@ejekanshjain/cloud-storage'
2
1
  import { NextRequest, NextResponse } from 'next/server'
3
2
 
4
- import { env } from '@/env.mjs'
5
3
  import { getAuthSession } from '@/lib/auth'
6
4
  import { prisma } from '@/lib/db'
7
-
8
- const storageClient = GCPStorageClient({
9
- projectId: env.FIREBASE_PROJECT_ID!,
10
- privateKey: env.FIREBASE_PRIVATE_KEY!,
11
- clientEmail: env.FIREBASE_CLIENT_EMAIL!,
12
- bucket: env.FIREBASE_STORAGE_BUCKET!,
13
- defaultMediaPublic: true
14
- })
5
+ import { storageClient } from '@/lib/storageClient'
15
6
 
16
7
  export async function POST(request: NextRequest) {
17
8
  const session = await getAuthSession()
@@ -0,0 +1,11 @@
1
+ import { GCPStorageClient } from '@ejekanshjain/cloud-storage'
2
+
3
+ import { env } from '@/env.mjs'
4
+
5
+ export const storageClient = GCPStorageClient({
6
+ projectId: env.FIREBASE_PROJECT_ID!,
7
+ privateKey: env.FIREBASE_PRIVATE_KEY!,
8
+ clientEmail: env.FIREBASE_CLIENT_EMAIL!,
9
+ bucket: env.FIREBASE_STORAGE_BUCKET!,
10
+ defaultMediaPublic: true
11
+ })