nsgm-cli 2.1.10 → 2.1.12

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/README.md CHANGED
@@ -16,26 +16,29 @@ A full-stack development framework with code template generation capabilities, h
16
16
  - Rapid development workflow
17
17
  - Integrated GraphQL API
18
18
  - MySQL database support
19
+ - Secure login system with bcrypt encryption
19
20
 
20
21
  ## Command Line Tools
21
22
 
22
23
  ### Basic Commands
23
24
 
24
- | Command | Description |
25
- |------|------|
26
- | `nsgm init` | Initialize project |
27
- | `nsgm upgrade` | Upgrade project base files |
28
- | `nsgm create` | Create template page |
29
- | `nsgm delete` | Delete template page |
30
- | `nsgm deletedb` | Delete template page and database table |
31
- | `nsgm dev` | Development mode |
32
- | `nsgm start` | Production mode |
33
- | `nsgm build` | Build project |
34
- | `nsgm export` | Export static pages |
25
+ | Command | Description |
26
+ | -------------------- | --------------------------------------- |
27
+ | `nsgm init` | Initialize project |
28
+ | `nsgm upgrade` | Upgrade project base files |
29
+ | `nsgm create` | Create template page |
30
+ | `nsgm delete` | Delete template page |
31
+ | `nsgm deletedb` | Delete template page and database table |
32
+ | `nsgm password` | Generate password hash |
33
+ | `nsgm dev` | Development mode |
34
+ | `nsgm start` | Production mode |
35
+ | `nsgm build` | Build project |
36
+ | `nsgm export` | Export static pages |
35
37
 
36
38
  ### Parameter Description
37
39
 
38
40
  - **dictionary**: Used with `export`/`init` commands, default value is `webapp`
41
+
39
42
  ```
40
43
  nsgm init dictionary=webapp
41
44
  # or simplified as
@@ -43,6 +46,7 @@ A full-stack development framework with code template generation capabilities, h
43
46
  ```
44
47
 
45
48
  - **controller**: Used with `create`/`delete` commands, required parameter
49
+
46
50
  ```
47
51
  nsgm create math
48
52
  ```
@@ -52,6 +56,38 @@ A full-stack development framework with code template generation capabilities, h
52
56
  nsgm create math test
53
57
  ```
54
58
 
59
+ - **password**: Used with `password` command, optional parameter
60
+ ```
61
+ nsgm password yourSecurePassword
62
+ ```
63
+
64
+ ## Security Configuration
65
+
66
+ For security setup and login configuration, please refer to [SECURITY.md](./SECURITY.md).
67
+
68
+ ### Quick Setup
69
+
70
+ 1. Generate password hash:
71
+
72
+ ```bash
73
+ # Using npm script
74
+ npm run generate-password yourSecurePassword
75
+
76
+ # Or using nsgm directly
77
+ nsgm password yourSecurePassword
78
+ ```
79
+
80
+ 2. Create `.env` file:
81
+
82
+ ```bash
83
+ LOGIN_USERNAME=admin
84
+ LOGIN_PASSWORD_HASH=your_generated_hash_here
85
+ ```
86
+
87
+ 3. Make sure `.env` is in your `.gitignore` file.
88
+
89
+ **⚠️ Important:** Never commit passwords or `.env` files to version control.
90
+
55
91
  ## Project Configuration
56
92
 
57
93
  ### next.config.js
@@ -60,14 +96,17 @@ A full-stack development framework with code template generation capabilities, h
60
96
  const { nextConfig } = require('nsgm-cli')
61
97
  const projectConfig = require('./project.config')
62
98
 
63
- const { version, prefix, protocol, host } = projectConfig
99
+ const { version, prefix, protocol, host } = projectConfig
64
100
 
65
101
  module.exports = (phase, defaultConfig) => {
66
- let configObj = nextConfig(phase, defaultConfig, {
67
- version, prefix, protocol, host
68
- })
102
+ let configObj = nextConfig(phase, defaultConfig, {
103
+ version,
104
+ prefix,
105
+ protocol,
106
+ host
107
+ })
69
108
 
70
- return configObj
109
+ return configObj
71
110
  }
72
111
  ```
73
112
 
@@ -79,13 +118,13 @@ const { mysqlOptions } = mysqlConfig
79
118
  const { user, password, host, port, database } = mysqlOptions
80
119
 
81
120
  module.exports = {
82
- mysqlOptions: {
83
- user,
84
- password,
85
- host,
86
- port,
87
- database
88
- }
121
+ mysqlOptions: {
122
+ user,
123
+ password,
124
+ host,
125
+ port,
126
+ database
127
+ }
89
128
  }
90
129
  ```
91
130
 
@@ -99,11 +138,11 @@ const { prefix, protocol, host, port } = projectConfig
99
138
  const { version } = pkg
100
139
 
101
140
  module.exports = {
102
- version,
103
- prefix,
104
- protocol,
105
- host,
106
- port
141
+ version,
142
+ prefix,
143
+ protocol,
144
+ host,
145
+ port
107
146
  }
108
147
  ```
109
148
 
@@ -116,11 +155,11 @@ The `server` folder in the project root contains the following:
116
155
  - `apis/` - Stores REST API interfaces
117
156
  - `modules/` - Stores GraphQL resolvers and schemas
118
157
  - `plugins/` - Stores GraphQL plugins
119
- - `*.js` - Route files, e.g., `test.js` handles requests to `/test/*` and `${prefix}/test/*`
158
+ - `*.js` - Route files
120
159
 
121
160
  ### Example Code
122
161
 
123
- #### Route File Example (server/test.js)
162
+ #### Route File Example (server/csrf-test.js)
124
163
 
125
164
  ```javascript
126
165
  const express = require('express')
@@ -129,14 +168,14 @@ const moment = require('moment')
129
168
  const router = express.Router()
130
169
 
131
170
  router.use((req, res, next) => {
132
- const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl
133
- console.log(moment().format('YYYY-MM-DD HH:mm:ss') + ' ' + fullUrl)
134
- next()
171
+ const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl
172
+ console.log(moment().format('YYYY-MM-DD HH:mm:ss') + ' ' + fullUrl)
173
+ next()
135
174
  })
136
175
 
137
176
  router.get('/*', (req, res) => {
138
- res.statusCode = 200
139
- res.json({ name: 'TEST' })
177
+ res.statusCode = 200
178
+ res.json({ name: 'TEST' })
140
179
  })
141
180
 
142
181
  module.exports = router
@@ -149,8 +188,8 @@ const express = require('express')
149
188
  const router = express.Router()
150
189
 
151
190
  router.get('/*', (req, res) => {
152
- res.statusCode = 200
153
- res.json({ name: 'Hello' })
191
+ res.statusCode = 200
192
+ res.json({ name: 'Hello' })
154
193
  })
155
194
 
156
195
  module.exports = router
@@ -160,15 +199,15 @@ module.exports = router
160
199
 
161
200
  ```javascript
162
201
  module.exports = {
163
- query: `
202
+ query: `
164
203
  link: String
165
204
  `,
166
- mutation: `
205
+ mutation: `
167
206
  linkUpdate(link: Date): String
168
207
  `,
169
- subscription: ``,
170
- type: ``
171
- }
208
+ subscription: ``,
209
+ type: ``
210
+ }
172
211
  ```
173
212
 
174
213
  #### GraphQL Resolver Example (server/modules/link/resolver.js)
@@ -177,14 +216,14 @@ module.exports = {
177
216
  let localLink = ''
178
217
 
179
218
  module.exports = {
180
- link: () => {
181
- return localLink
182
- },
183
- linkUpdate: ({ link }) => {
184
- console.log('link', link)
185
- localLink = link
186
- return localLink
187
- }
219
+ link: () => {
220
+ return localLink
221
+ },
222
+ linkUpdate: ({ link }) => {
223
+ console.log('link', link)
224
+ localLink = link
225
+ return localLink
226
+ }
188
227
  }
189
228
  ```
190
229
 
@@ -196,14 +235,12 @@ const { Kind } = require('graphql/language')
196
235
  const { GraphQLScalarType } = require('graphql')
197
236
 
198
237
  const customScalarDate = new GraphQLScalarType({
199
- name: 'Date',
200
- description: 'Date custom scalar type',
201
- parseValue: value => moment(value).valueOf(),
202
- serialize: value => moment(value).format('YYYY-MM-DD HH:mm:ss:SSS'),
203
- parseLiteral: ast => (ast.kind === Kind.INT)
204
- ? parseInt(ast.value, 10)
205
- : null
238
+ name: 'Date',
239
+ description: 'Date custom scalar type',
240
+ parseValue: (value) => moment(value).valueOf(),
241
+ serialize: (value) => moment(value).format('YYYY-MM-DD HH:mm:ss:SSS'),
242
+ parseLiteral: (ast) => (ast.kind === Kind.INT ? parseInt(ast.value, 10) : null)
206
243
  })
207
244
 
208
245
  module.exports = { Date: customScalarDate }
209
- ```
246
+ ```
@@ -15,6 +15,19 @@ if (reducersKeysLen > 0) {
15
15
 
16
16
  export type RootState = ReturnType<typeof combineReducer>
17
17
 
18
+ // 创建一个临时 store 实例来获取正确的 dispatch 类型
19
+ const tempStore = configureStore({
20
+ reducer: combineReducer,
21
+ middleware: (getDefaultMiddleware) =>
22
+ getDefaultMiddleware({
23
+ serializableCheck: {
24
+ ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
25
+ },
26
+ }),
27
+ })
28
+
29
+ export type AppDispatch = typeof tempStore.dispatch
30
+
18
31
  function initStore(initialState?: any): EnhancedStore {
19
32
  return configureStore({
20
33
  reducer: combineReducer,
@@ -1,11 +1,9 @@
1
1
  import * as types from './types'
2
2
  import { getTemplateService, addTemplateService, updateTemplateService, deleteTemplateService, searchTemplateService, batchDeleteTemplateService } from '@/service/template/manage'
3
+ import { AppDispatch } from '@/redux/store'
3
4
 
4
5
  export const getTemplate = (page=0, pageSize=10) => (
5
- dispatch: (arg0: {
6
- type: string
7
- payload?: { template: any }
8
- }) => void
6
+ dispatch: AppDispatch
9
7
  ) => {
10
8
  dispatch({
11
9
  type: types.GET_TEMPLATE
@@ -30,10 +28,7 @@ export const getTemplate = (page=0, pageSize=10) => (
30
28
  }
31
29
 
32
30
  export const searchTemplate = (page=0, pageSize=10, data: any) => (
33
- dispatch: (arg0: {
34
- type: string
35
- payload?: { template: any }
36
- }) => void
31
+ dispatch: AppDispatch
37
32
  ) => {
38
33
  dispatch({
39
34
  type: types.SEARCH_TEMPLATE
@@ -58,10 +53,7 @@ export const searchTemplate = (page=0, pageSize=10, data: any) => (
58
53
  }
59
54
 
60
55
  export const updateSSRTemplate = (template: any) => (
61
- dispatch: (arg0: {
62
- type: string
63
- payload?: { template: any }
64
- }) => void
56
+ dispatch: AppDispatch
65
57
  ) => {
66
58
  dispatch({
67
59
  type: types.UPDATE_SSR_TEMPLATE,
@@ -72,10 +64,7 @@ export const updateSSRTemplate = (template: any) => (
72
64
  }
73
65
 
74
66
  export const addTemplate = (obj:any) => (
75
- dispatch: (arg0: {
76
- type: string
77
- payload?: { template: any }
78
- }) => void
67
+ dispatch: AppDispatch
79
68
  ) => {
80
69
  dispatch({
81
70
  type: types.ADD_TEMPLATE
@@ -104,10 +93,7 @@ export const addTemplate = (obj:any) => (
104
93
  }
105
94
 
106
95
  export const modTemplate = (id: number, obj: any) => (
107
- dispatch: (arg0: {
108
- type: string
109
- payload?: { template: any }
110
- }) => void
96
+ dispatch: AppDispatch
111
97
  ) => {
112
98
  dispatch({
113
99
  type: types.MOD_TEMPLATE
@@ -135,10 +121,7 @@ export const modTemplate = (id: number, obj: any) => (
135
121
  }
136
122
 
137
123
  export const delTemplate = (id: number) => (
138
- dispatch: (arg0: {
139
- type: string
140
- payload?: { id: number }
141
- }) => void
124
+ dispatch: AppDispatch
142
125
  ) => {
143
126
  dispatch({
144
127
  type: types.DEL_TEMPLATE
@@ -163,10 +146,7 @@ export const delTemplate = (id: number) => (
163
146
  }
164
147
 
165
148
  export const batchDelTemplate = (ids:any) => (
166
- dispatch: (arg0: {
167
- type: string
168
- payload?: { ids: any }
169
- }) => void
149
+ dispatch: AppDispatch
170
150
  ) => {
171
151
  dispatch({
172
152
  type: types.BATCH_DEL_TEMPLATE
@@ -12,7 +12,7 @@ export const getTemplateService = (page = 0, pageSize = 10) => {
12
12
  return getLocalGraphql(getTemplateQuery, {
13
13
  page,
14
14
  pageSize
15
- })
15
+ }, true) // 启用缓存,因为这是查询操作
16
16
  }
17
17
 
18
18
  export const searchTemplateByIdService = (id: number) => {
@@ -24,7 +24,7 @@ export const searchTemplateByIdService = (id: number) => {
24
24
 
25
25
  return getLocalGraphql(searchTemplateByIdQuery, {
26
26
  id
27
- })
27
+ }, true) // 启用缓存,因为这是查询操作
28
28
  }
29
29
 
30
30
  export const searchTemplateService = (page = 0, pageSize = 10, data: any) => {
@@ -44,7 +44,7 @@ export const searchTemplateService = (page = 0, pageSize = 10, data: any) => {
44
44
  data: {
45
45
  name
46
46
  }
47
- })
47
+ }, true) // 启用缓存,因为这是查询操作
48
48
  }
49
49
 
50
50
  export const addTemplateService = (data: any) => {
@@ -56,7 +56,7 @@ export const addTemplateService = (data: any) => {
56
56
  data: {
57
57
  name
58
58
  }
59
- })
59
+ }, false) // 不使用缓存,因为这是变更操作,会自动添加 CSRF token
60
60
  }
61
61
 
62
62
  export const updateTemplateService = (id: number, data: any) => {
@@ -69,7 +69,7 @@ export const updateTemplateService = (id: number, data: any) => {
69
69
  data: {
70
70
  name
71
71
  }
72
- })
72
+ }, false) // 不使用缓存,因为这是变更操作,会自动添加 CSRF token
73
73
  }
74
74
 
75
75
  export const deleteTemplateService = (id: number) => {
@@ -77,7 +77,7 @@ export const deleteTemplateService = (id: number) => {
77
77
 
78
78
  return getLocalGraphql(deleteTemplateQuery, {
79
79
  id
80
- })
80
+ }, false) // 不使用缓存,因为这是变更操作,会自动添加 CSRF token
81
81
  }
82
82
 
83
83
  export const batchAddTemplateService = (datas: any) => {
@@ -85,7 +85,7 @@ export const batchAddTemplateService = (datas: any) => {
85
85
 
86
86
  return getLocalGraphql(batchAddTemplateQuery, {
87
87
  datas
88
- })
88
+ }, false) // 不使用缓存,因为这是变更操作,会自动添加 CSRF token
89
89
  }
90
90
 
91
91
  export const batchDeleteTemplateService = (ids: any) => {
@@ -93,5 +93,5 @@ export const batchDeleteTemplateService = (ids: any) => {
93
93
 
94
94
  return getLocalGraphql(batchDeleteTemplateQuery, {
95
95
  ids
96
- })
96
+ }, false) // 不使用缓存,因为这是变更操作,会自动添加 CSRF token
97
97
  }
@@ -18,8 +18,8 @@ export const getLocalApiPrefix = () => {
18
18
 
19
19
  if(!isExport){
20
20
  if (typeof window !== 'undefined') {
21
+ // 客户端:使用当前页面的 location
21
22
  const location = window.location
22
- // console.log('location', location)
23
23
 
24
24
  protocol = location.protocol
25
25
  if (protocol.indexOf(':') != -1) {
@@ -28,10 +28,10 @@ export const getLocalApiPrefix = () => {
28
28
  host = location.hostname
29
29
  port = location.port || (protocol.indexOf('https') !== -1 ? "443" : "80")
30
30
  }
31
+ // 服务器端:直接使用配置中的值,无需额外处理
31
32
  }
32
33
 
33
34
  localApiPrefix = protocol + '://' + host + ':' + port + prefix
34
- // console.log('localApiPrefix', localApiPrefix)
35
35
  return localApiPrefix
36
36
  }
37
37