jcc-express-mvc 1.8.8 → 1.8.21

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 (215) hide show
  1. package/__tests__/MySqlSchemaBlueprint.test.d.ts +2 -0
  2. package/__tests__/MySqlSchemaBlueprint.test.d.ts.map +1 -0
  3. package/__tests__/MySqlSchemaBlueprint.test.js +55 -0
  4. package/__tests__/PostgresTranslator.test.d.ts +2 -0
  5. package/__tests__/PostgresTranslator.test.d.ts.map +1 -0
  6. package/__tests__/PostgresTranslator.test.js +82 -0
  7. package/__tests__/SQLiteTranslator.test.d.ts +2 -0
  8. package/__tests__/SQLiteTranslator.test.d.ts.map +1 -0
  9. package/__tests__/SQLiteTranslator.test.js +125 -0
  10. package/__tests__/SchemaAlterBlueprint.test.d.ts +2 -0
  11. package/__tests__/SchemaAlterBlueprint.test.d.ts.map +1 -0
  12. package/__tests__/SchemaAlterBlueprint.test.js +35 -0
  13. package/global.d.ts +3 -1
  14. package/index.d.ts +28 -3
  15. package/index.d.ts.map +1 -1
  16. package/index.js +33 -75
  17. package/lib/Application/Application.d.ts +1 -1
  18. package/lib/Application/Application.d.ts.map +1 -1
  19. package/lib/Application/Application.js +2 -2
  20. package/lib/Application/ApplicationBuilder.d.ts.map +1 -1
  21. package/lib/Application/ApplicationBuilder.js +9 -2
  22. package/lib/Auth/AuthMiddleware.d.ts.map +1 -1
  23. package/lib/Auth/AuthMiddleware.js +29 -12
  24. package/lib/Auth/index.d.ts +17 -3
  25. package/lib/Auth/index.d.ts.map +1 -1
  26. package/lib/Auth/index.js +128 -26
  27. package/lib/Auth/loginRateLimit.d.ts +6 -0
  28. package/lib/Auth/loginRateLimit.d.ts.map +1 -0
  29. package/lib/Auth/loginRateLimit.js +25 -0
  30. package/lib/Auth/refreshTokenStore.d.ts +24 -0
  31. package/lib/Auth/refreshTokenStore.d.ts.map +1 -0
  32. package/lib/Auth/refreshTokenStore.js +46 -0
  33. package/lib/Command-Line/DBCommand.d.ts.map +1 -1
  34. package/lib/Command-Line/DBCommand.js +9 -3
  35. package/lib/Command-Line/KeyGenerateCommand.d.ts +6 -0
  36. package/lib/Command-Line/KeyGenerateCommand.d.ts.map +1 -0
  37. package/lib/Command-Line/KeyGenerateCommand.js +47 -0
  38. package/lib/Command-Line/NodeArtisanCommand.d.ts +2 -0
  39. package/lib/Command-Line/NodeArtisanCommand.d.ts.map +1 -1
  40. package/lib/Command-Line/NodeArtisanCommand.js +20 -3
  41. package/lib/Command-Line/NodeTinker/Tinker.d.ts +5 -2
  42. package/lib/Command-Line/NodeTinker/Tinker.d.ts.map +1 -1
  43. package/lib/Command-Line/NodeTinker/Tinker.js +13 -3
  44. package/lib/Command-Line/WatchCommand.d.ts +29 -0
  45. package/lib/Command-Line/WatchCommand.d.ts.map +1 -0
  46. package/lib/Command-Line/WatchCommand.js +234 -0
  47. package/lib/Command-Line/files/Models.d.ts.map +1 -1
  48. package/lib/Command-Line/files/Models.js +41 -16
  49. package/lib/Console/Command.d.ts +18 -0
  50. package/lib/Console/Command.d.ts.map +1 -1
  51. package/lib/Console/Command.js +29 -0
  52. package/lib/Container/index.d.ts.map +1 -1
  53. package/lib/Container/index.js +21 -7
  54. package/lib/Database/Database.d.ts +2 -1
  55. package/lib/Database/Database.d.ts.map +1 -1
  56. package/lib/Database/Database.js +6 -5
  57. package/lib/Database/DatabaseServiceProvider.d.ts +0 -4
  58. package/lib/Database/DatabaseServiceProvider.d.ts.map +1 -1
  59. package/lib/Database/DatabaseServiceProvider.js +9 -56
  60. package/lib/Database/Drivers/MongooseDriver.d.ts +2 -0
  61. package/lib/Database/Drivers/MongooseDriver.d.ts.map +1 -1
  62. package/lib/Database/Drivers/MongooseDriver.js +11 -13
  63. package/lib/Database/Drivers/SequelizeDriver.d.ts +9 -1
  64. package/lib/Database/Drivers/SequelizeDriver.d.ts.map +1 -1
  65. package/lib/Database/Drivers/SequelizeDriver.js +43 -18
  66. package/lib/Error/SocialiteAuthError/SocialiteAuthError.d.ts +9 -0
  67. package/lib/Error/SocialiteAuthError/SocialiteAuthError.d.ts.map +1 -0
  68. package/lib/Error/SocialiteAuthError/SocialiteAuthError.js +17 -0
  69. package/lib/Global/helpers.d.ts.map +1 -1
  70. package/lib/Global/helpers.js +6 -4
  71. package/lib/Http/index.d.ts +3 -1
  72. package/lib/Http/index.d.ts.map +1 -1
  73. package/lib/Http/index.js +26 -5
  74. package/lib/Interface/index.d.ts +12 -3
  75. package/lib/Interface/index.d.ts.map +1 -1
  76. package/lib/Jcc-eloquent/lib/Builder.d.ts +12 -1
  77. package/lib/Jcc-eloquent/lib/Builder.d.ts.map +1 -1
  78. package/lib/Jcc-eloquent/lib/Builder.js +116 -4
  79. package/lib/Jcc-eloquent/lib/Interfaces/index.d.ts +37 -2
  80. package/lib/Jcc-eloquent/lib/Interfaces/index.d.ts.map +1 -1
  81. package/lib/Jcc-eloquent/lib/Migration.d.ts +6 -0
  82. package/lib/Jcc-eloquent/lib/Migration.d.ts.map +1 -1
  83. package/lib/Jcc-eloquent/lib/Migration.js +24 -2
  84. package/lib/Jcc-eloquent/lib/Model.d.ts +24 -7
  85. package/lib/Jcc-eloquent/lib/Model.d.ts.map +1 -1
  86. package/lib/Jcc-eloquent/lib/Model.js +35 -2
  87. package/lib/Jcc-eloquent/lib/QueryBuilder.d.ts +2 -1
  88. package/lib/Jcc-eloquent/lib/QueryBuilder.d.ts.map +1 -1
  89. package/lib/Jcc-eloquent/lib/QueryBuilder.js +10 -1
  90. package/lib/Jcc-eloquent/lib/Rollback.d.ts.map +1 -1
  91. package/lib/Jcc-eloquent/lib/Rollback.js +9 -2
  92. package/lib/Jcc-eloquent/lib/Schema/BaseSchemaEntity/index.d.ts.map +1 -1
  93. package/lib/Jcc-eloquent/lib/Schema/BaseSchemaEntity/index.js +3 -3
  94. package/lib/Jcc-eloquent/lib/Schema/BluePrint/index.d.ts +6 -2
  95. package/lib/Jcc-eloquent/lib/Schema/BluePrint/index.d.ts.map +1 -1
  96. package/lib/Jcc-eloquent/lib/Schema/BluePrint/index.js +41 -12
  97. package/lib/Jcc-eloquent/lib/Schema/Translator/Sqlite.d.ts.map +1 -1
  98. package/lib/Jcc-eloquent/lib/Schema/Translator/Sqlite.js +21 -3
  99. package/lib/Jcc-eloquent/lib/Schema/Translator/postgres.d.ts +1 -0
  100. package/lib/Jcc-eloquent/lib/Schema/Translator/postgres.d.ts.map +1 -1
  101. package/lib/Jcc-eloquent/lib/Schema/Translator/postgres.js +70 -14
  102. package/lib/Jcc-eloquent/lib/Schema/index.d.ts +12 -0
  103. package/lib/Jcc-eloquent/lib/Schema/index.d.ts.map +1 -1
  104. package/lib/Jcc-eloquent/lib/Schema/index.js +27 -6
  105. package/lib/Jcc-eloquent/lib/utils/index.d.ts +13 -0
  106. package/lib/Jcc-eloquent/lib/utils/index.d.ts.map +1 -1
  107. package/lib/Jcc-eloquent/lib/utils/index.js +62 -0
  108. package/lib/Middleware/index.d.ts.map +1 -1
  109. package/lib/Middleware/index.js +4 -7
  110. package/lib/Model/Sequelize.d.ts +3 -0
  111. package/lib/Model/Sequelize.d.ts.map +1 -0
  112. package/lib/Model/Sequelize.js +6 -0
  113. package/lib/Providers/SessionServiceProvider.d.ts +12 -0
  114. package/lib/Providers/SessionServiceProvider.d.ts.map +1 -0
  115. package/lib/Providers/SessionServiceProvider.js +47 -0
  116. package/lib/Queue/Controllers/QueueControllers.d.ts +4 -13
  117. package/lib/Queue/Controllers/QueueControllers.d.ts.map +1 -1
  118. package/lib/Queue/Controllers/QueueControllers.js +1 -16
  119. package/lib/Queue/Route/web.js +4 -1
  120. package/lib/Queue/index.d.ts +1 -0
  121. package/lib/Queue/index.d.ts.map +1 -1
  122. package/lib/Queue/index.js +3 -0
  123. package/lib/Queue/middleware/queueDashboardGuard.d.ts +7 -0
  124. package/lib/Queue/middleware/queueDashboardGuard.d.ts.map +1 -0
  125. package/lib/Queue/middleware/queueDashboardGuard.js +43 -0
  126. package/lib/Response/index.d.ts.map +1 -1
  127. package/lib/Response/index.js +6 -1
  128. package/lib/Routes/Route.d.ts +2 -2
  129. package/lib/Routes/Route.d.ts.map +1 -1
  130. package/lib/Routes/RouteBuilder.d.ts +2 -2
  131. package/lib/Routes/RouteBuilder.d.ts.map +1 -1
  132. package/lib/Security/CsrfMiddleware.d.ts.map +1 -1
  133. package/lib/Security/CsrfMiddleware.js +6 -4
  134. package/lib/Session/DatabaseSession.d.ts +9 -3
  135. package/lib/Session/DatabaseSession.d.ts.map +1 -1
  136. package/lib/Session/DatabaseSession.js +38 -36
  137. package/lib/Session/ExpressJccSession.d.ts +23 -0
  138. package/lib/Session/ExpressJccSession.d.ts.map +1 -0
  139. package/lib/Session/ExpressJccSession.js +110 -0
  140. package/lib/Session/RedisSession.d.ts +2 -2
  141. package/lib/Session/RedisSession.d.ts.map +1 -1
  142. package/lib/Session/RedisSession.js +19 -5
  143. package/lib/Session/SessionManager.d.ts +18 -4
  144. package/lib/Session/SessionManager.d.ts.map +1 -1
  145. package/lib/Session/SessionManager.js +53 -17
  146. package/lib/Socialite/AbstractProvider.d.ts +60 -0
  147. package/lib/Socialite/AbstractProvider.d.ts.map +1 -0
  148. package/lib/Socialite/AbstractProvider.js +136 -0
  149. package/lib/Socialite/Drivers/facebook/FacebookDriver.d.ts +9 -0
  150. package/lib/Socialite/Drivers/facebook/FacebookDriver.d.ts.map +1 -0
  151. package/lib/Socialite/Drivers/facebook/FacebookDriver.js +40 -0
  152. package/lib/Socialite/Drivers/facebook/FacebookProvider.d.ts +15 -0
  153. package/lib/Socialite/Drivers/facebook/FacebookProvider.d.ts.map +1 -0
  154. package/lib/Socialite/Drivers/facebook/FacebookProvider.js +28 -0
  155. package/lib/Socialite/Drivers/github/GitHubDriver.d.ts +9 -0
  156. package/lib/Socialite/Drivers/github/GitHubDriver.d.ts.map +1 -0
  157. package/lib/Socialite/Drivers/github/GitHubDriver.js +54 -0
  158. package/lib/Socialite/Drivers/github/GitHubProvider.d.ts +15 -0
  159. package/lib/Socialite/Drivers/github/GitHubProvider.d.ts.map +1 -0
  160. package/lib/Socialite/Drivers/github/GitHubProvider.js +28 -0
  161. package/lib/Socialite/Drivers/gitlab/GitLabDriver.d.ts +10 -0
  162. package/lib/Socialite/Drivers/gitlab/GitLabDriver.d.ts.map +1 -0
  163. package/lib/Socialite/Drivers/gitlab/GitLabDriver.js +37 -0
  164. package/lib/Socialite/Drivers/gitlab/GitLabProvider.d.ts +15 -0
  165. package/lib/Socialite/Drivers/gitlab/GitLabProvider.d.ts.map +1 -0
  166. package/lib/Socialite/Drivers/gitlab/GitLabProvider.js +28 -0
  167. package/lib/Socialite/Drivers/google/GoogleDriver.d.ts +9 -0
  168. package/lib/Socialite/Drivers/google/GoogleDriver.d.ts.map +1 -0
  169. package/lib/Socialite/Drivers/google/GoogleDriver.js +39 -0
  170. package/lib/Socialite/Drivers/google/GoogleProvider.d.ts +15 -0
  171. package/lib/Socialite/Drivers/google/GoogleProvider.d.ts.map +1 -0
  172. package/lib/Socialite/Drivers/google/GoogleProvider.js +28 -0
  173. package/lib/Socialite/Drivers/slack/SlackDriver.d.ts +9 -0
  174. package/lib/Socialite/Drivers/slack/SlackDriver.d.ts.map +1 -0
  175. package/lib/Socialite/Drivers/slack/SlackDriver.js +41 -0
  176. package/lib/Socialite/Drivers/slack/SlackProvider.d.ts +16 -0
  177. package/lib/Socialite/Drivers/slack/SlackProvider.d.ts.map +1 -0
  178. package/lib/Socialite/Drivers/slack/SlackProvider.js +37 -0
  179. package/lib/Socialite/Drivers/twitter/TwitterDriver.d.ts +9 -0
  180. package/lib/Socialite/Drivers/twitter/TwitterDriver.d.ts.map +1 -0
  181. package/lib/Socialite/Drivers/twitter/TwitterDriver.js +57 -0
  182. package/lib/Socialite/Drivers/twitter/TwitterProvider.d.ts +16 -0
  183. package/lib/Socialite/Drivers/twitter/TwitterProvider.d.ts.map +1 -0
  184. package/lib/Socialite/Drivers/twitter/TwitterProvider.js +38 -0
  185. package/lib/Socialite/SocialUser.d.ts +42 -0
  186. package/lib/Socialite/SocialUser.d.ts.map +1 -0
  187. package/lib/Socialite/SocialUser.js +116 -0
  188. package/lib/Socialite/Socialite.d.ts +13 -0
  189. package/lib/Socialite/Socialite.d.ts.map +1 -0
  190. package/lib/Socialite/Socialite.js +41 -0
  191. package/lib/Socialite/SocialiteProvider.d.ts +9 -0
  192. package/lib/Socialite/SocialiteProvider.d.ts.map +1 -0
  193. package/lib/Socialite/SocialiteProvider.js +15 -0
  194. package/lib/Socialite/config.d.ts +7 -0
  195. package/lib/Socialite/config.d.ts.map +1 -0
  196. package/lib/Socialite/config.js +44 -0
  197. package/lib/Socialite/constant.d.ts +18 -0
  198. package/lib/Socialite/constant.d.ts.map +1 -0
  199. package/lib/Socialite/constant.js +20 -0
  200. package/lib/Socialite/index.d.ts +13 -0
  201. package/lib/Socialite/index.d.ts.map +1 -0
  202. package/lib/Socialite/index.js +25 -0
  203. package/lib/Socialite/types.d.ts +13 -0
  204. package/lib/Socialite/types.d.ts.map +1 -0
  205. package/lib/Socialite/types.js +2 -0
  206. package/lib/Type/index.d.ts +1 -0
  207. package/lib/Type/index.d.ts.map +1 -1
  208. package/lib/Validation/Validator/CustomValidation.d.ts.map +1 -1
  209. package/lib/Validation/Validator/CustomValidation.js +2 -2
  210. package/lib/Validation/Validator/helper.d.ts.map +1 -1
  211. package/lib/Validation/Validator/helper.js +8 -1
  212. package/lib/util/index.d.ts +36 -1
  213. package/lib/util/index.d.ts.map +1 -1
  214. package/lib/util/index.js +123 -26
  215. package/package.json +1 -1
@@ -3,22 +3,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.authMiddleware = void 0;
4
4
  const Config_1 = require("../Config/Config");
5
5
  const util_1 = require("../util");
6
- const { User } = (0, util_1.getModel)("User");
7
6
  class AuthMiddleware {
8
7
  /** Middleware: API authentication */
9
8
  async apiAuth(req, res, next) {
9
+ const { User } = (0, util_1.getModel)("User");
10
10
  const token = req.headers.authorization?.split(" ")[1] || req.cookies.auth_token;
11
11
  if (!token)
12
12
  return res.status(401).json({ message: "Not authorized" });
13
13
  try {
14
- const id = (0, util_1.jwtVerify)(token);
15
- const user = Config_1.config.get("DB_ORM") === "mongodb"
14
+ const payload = (0, util_1.jwtVerify)(token);
15
+ if (!(0, util_1.checkJwtAccessTokenPayload)(payload).ok) {
16
+ return res.status(401).json({ message: "Not authorized" });
17
+ }
18
+ const id = (0, util_1.jwtSubjectId)(payload);
19
+ const user = Config_1.config.get("DB_ORM") === "mongodb" ||
20
+ Config_1.config.get("DB_ORM") === "mongoose"
16
21
  ? await User.findById(id)
17
22
  : await User.where("id", id).first();
18
23
  if (!user)
19
24
  return res.status(401).json({ message: "Not authorized" });
20
25
  req.user = user;
21
- req.id = id;
26
+ req.id = String(id);
22
27
  next();
23
28
  }
24
29
  catch (err) {
@@ -26,15 +31,26 @@ class AuthMiddleware {
26
31
  }
27
32
  }
28
33
  async auth(req, res, next) {
34
+ const { User } = (0, util_1.getModel)("User");
29
35
  const token = req.cookies.auth_token;
30
- if (!token)
36
+ if (!token) {
37
+ req.jccSession?.put("redirect", req.url || "/");
31
38
  return res.redirect(`/login?redirect=${req.url || "/"}`);
39
+ }
32
40
  try {
33
41
  const payload = (0, util_1.jwtVerify)(token);
34
- const user = await (0, util_1.findUserById)(User, payload.id);
42
+ if (!(0, util_1.checkJwtAccessTokenPayload)(payload).ok) {
43
+ res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
44
+ res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
45
+ req.jccSession?.put("redirect", req.url || "/");
46
+ return res.redirect(`/login?redirect=${req.url || "/"}`);
47
+ }
48
+ const id = (0, util_1.jwtSubjectId)(payload);
49
+ const user = await (0, util_1.findUserById)(User, id);
35
50
  if (!user) {
36
- res.clearCookie("auth_token");
37
- res.clearCookie("refresh_token");
51
+ res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
52
+ res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
53
+ req.jccSession?.put("redirect", req.url || "/");
38
54
  return res.redirect(`/login?redirect=${req.url || "/"}`);
39
55
  }
40
56
  req.user = user;
@@ -42,8 +58,9 @@ class AuthMiddleware {
42
58
  next();
43
59
  }
44
60
  catch (err) {
45
- res.clearCookie("auth_token");
46
- res.clearCookie("refresh_token");
61
+ res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
62
+ res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
63
+ req.jccSession?.put("redirect", req.url || "/");
47
64
  return res.redirect(`/login?redirect=${req.url || "/"}`);
48
65
  }
49
66
  }
@@ -55,8 +72,8 @@ class AuthMiddleware {
55
72
  return res.redirect(303, req.previousUrls[1]);
56
73
  }
57
74
  else {
58
- res.clearCookie("auth_token");
59
- res.clearCookie("refresh_token");
75
+ res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
76
+ res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
60
77
  return res.redirect(303, req.url);
61
78
  }
62
79
  }
@@ -1,16 +1,30 @@
1
1
  import { AppRequest, AppResponse, AppNext } from "../Interface";
2
+ import { type IRefreshTokenStore } from "./refreshTokenStore";
2
3
  export declare class Authentication {
4
+ private static refreshStore;
5
+ /** Use a shared store (e.g. Redis) when running multiple app instances. */
6
+ static setRefreshTokenStore(store: IRefreshTokenStore): void;
3
7
  /** Get user lookup field (email, phone, username) */
4
8
  private static getCredentials;
5
9
  /** Fetch user from DB (MongoDB, Sequelize, or JCC ORM) */
6
10
  private static getUser;
7
- /** Generate and attach tokens to cookies */
11
+ /** Generate and attach tokens to cookies (refresh is rotated server-side via `jti`). */
8
12
  private static setTokens;
9
13
  /** Handle user login attempt */
10
- static attempt: (req: AppRequest, res: AppResponse, next: AppNext, redirect?: string) => Promise<void | AppResponse>;
14
+ static attempt: (next: AppNext, redirect?: string) => Promise<void>;
15
+ /**
16
+ * After the user is resolved (e.g. OAuth via Socialite), issue JWT cookies
17
+ * and redirect or JSON response like {@link Authentication.attempt}.
18
+ */
19
+ static completeLogin(req: AppRequest, res: AppResponse, userId: string | number, redirect?: string): Promise<void>;
11
20
  /** Refresh token middleware */
12
21
  static refreshToken(req: AppRequest, res: AppResponse, next: AppNext): Promise<AppResponse | undefined>;
13
22
  /** Logout handler */
14
- static logout(req: AppRequest, res: AppResponse): void;
23
+ static logout(): void;
24
+ /** True when the access cookie is a valid, usable JWT (not refresh / disallowed legacy). */
25
+ static check(): boolean;
26
+ static user(): Record<string, any>;
27
+ static id(): any;
28
+ static socialLogin(userId: string | number): Promise<void>;
15
29
  }
16
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAehE,qBAAa,cAAc;IACzB,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,cAAc;IAc7B,0DAA0D;mBACrC,OAAO;IAoB5B,4CAA4C;IAC5C,OAAO,CAAC,MAAM,CAAC,SAAS;IAuBxB,gCAAgC;IAChC,MAAM,CAAC,OAAO,GACZ,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,MAAM,OAAO,EACb,WAAU,MAAgB,iCAuB1B;IAEF,+BAA+B;WAClB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO;IAmB1E,qBAAqB;IACrB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW;CAKhD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAgBhE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAsB7B,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,YAAY,CAAgD;IAE3E,2EAA2E;IAC3E,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAI5D,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,cAAc;IAc7B,0DAA0D;mBACrC,OAAO;IAqB5B,wFAAwF;IACxF,OAAO,CAAC,MAAM,CAAC,SAAS;IA0BxB,gCAAgC;IAChC,MAAM,CAAC,OAAO,GAAU,MAAM,OAAO,EAAE,WAAU,MAAgB,mBAqB/D;IAEF;;;OAGG;WACU,aAAa,CACxB,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,GAAE,MAAgB,GACzB,OAAO,CAAC,IAAI,CAAC;IA4BhB,+BAA+B;WAClB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO;IAsC1E,qBAAqB;IACrB,MAAM,CAAC,MAAM;IAsBb,4FAA4F;IAC5F,MAAM,CAAC,KAAK,IAAI,OAAO;IAWvB,MAAM,CAAC,IAAI;IAIX,MAAM,CAAC,EAAE;WAII,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAGjD"}
package/lib/Auth/index.js CHANGED
@@ -6,8 +6,28 @@ const util_1 = require("../util");
6
6
  const Config_1 = require("../Config/Config");
7
7
  const ValidationException_v2_1 = require("../Error/ValidationException-v2");
8
8
  const Jcc_eloquent_1 = require("../Jcc-eloquent");
9
- const { User } = (0, util_1.getModel)("User");
9
+ const refreshTokenStore_1 = require("./refreshTokenStore");
10
+ const REFRESH_TTL_MS = 7 * 24 * 60 * 60 * 1000;
11
+ const ACCESS_MAX_AGE_MS = 60 * 60 * 1000;
12
+ function clearAuthCookies(res) {
13
+ const base = (0, util_1.authSessionCookieOptions)();
14
+ res.clearCookie("auth_token", base);
15
+ res.clearCookie("refresh_token", base);
16
+ }
17
+ /** Avoid open redirects: only same-origin relative paths. */
18
+ function safeInternalRedirect(url, fallback) {
19
+ if (!url || typeof url !== "string")
20
+ return fallback;
21
+ const t = url.trim();
22
+ if (t.startsWith("/") && !t.startsWith("//") && !t.includes("\\"))
23
+ return t;
24
+ return fallback;
25
+ }
10
26
  class Authentication {
27
+ /** Use a shared store (e.g. Redis) when running multiple app instances. */
28
+ static setRefreshTokenStore(store) {
29
+ _a.refreshStore = store;
30
+ }
11
31
  /** Get user lookup field (email, phone, username) */
12
32
  static getCredentials(data) {
13
33
  const query = {};
@@ -24,12 +44,13 @@ class Authentication {
24
44
  }
25
45
  /** Fetch user from DB (MongoDB, Sequelize, or JCC ORM) */
26
46
  static async getUser(data) {
47
+ const { User } = (0, util_1.getModel)("User");
27
48
  const field = this.getCredentials(data);
28
49
  if (!Object.keys(field).length)
29
50
  return { user: null, field: "email" };
30
51
  let user = null;
31
52
  const orm = Config_1.config.get("DB_ORM");
32
- if (orm === "mongodb") {
53
+ if (orm === "mongodb" || orm === "mongoose") {
33
54
  user = await User.findOne(field).select("+password");
34
55
  }
35
56
  else if (orm === "sequelize") {
@@ -43,54 +64,140 @@ class Authentication {
43
64
  }
44
65
  return { user, field: Object.keys(field)[0] || "email" };
45
66
  }
46
- /** Generate and attach tokens to cookies */
67
+ /** Generate and attach tokens to cookies (refresh is rotated server-side via `jti`). */
47
68
  static setTokens(res, userId) {
48
- const accessToken = (0, util_1.jwtSign)(userId.toString(), { expiresIn: "1h" });
49
- const refreshToken = (0, util_1.jwtSign)(userId.toString(), { expiresIn: "7d" });
50
- const cookieOptions = {
51
- httpOnly: true,
52
- secure: Config_1.config.get("APP_ENV") === "production",
53
- sameSite: "lax",
54
- };
69
+ const id = String(userId);
70
+ const jti = _a.refreshStore.generateJti();
71
+ _a.refreshStore.register(jti, id, REFRESH_TTL_MS);
72
+ const accessToken = (0, util_1.jwtSign)(id, { expiresIn: "1h" });
73
+ const refreshToken = (0, util_1.jwtSign)({ id, typ: "refresh", jti }, { expiresIn: "7d" });
74
+ const cookieOptions = (0, util_1.authSessionCookieOptions)();
55
75
  res.cookie("auth_token", accessToken, {
56
76
  ...cookieOptions,
57
- maxAge: 1000 * 60 * 60, // 1 hour
77
+ maxAge: ACCESS_MAX_AGE_MS,
58
78
  });
59
79
  res.cookie("refresh_token", refreshToken, {
60
80
  ...cookieOptions,
61
- maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
81
+ maxAge: REFRESH_TTL_MS,
62
82
  });
63
83
  return { accessToken, refreshToken };
64
84
  }
85
+ /**
86
+ * After the user is resolved (e.g. OAuth via Socialite), issue JWT cookies
87
+ * and redirect or JSON response like {@link Authentication.attempt}.
88
+ */
89
+ static async completeLogin(req, res, userId, redirect = "/home") {
90
+ const { User } = (0, util_1.getModel)("User");
91
+ const tokens = this.setTokens(res, userId);
92
+ const user = await (0, util_1.findUserById)(User, userId);
93
+ if (!user) {
94
+ if (req.expectsJson() && !req.isInertia()) {
95
+ res.status(401).json({ message: "Unauthorized" });
96
+ }
97
+ else {
98
+ req.jccSession?.flash("error", "Could not sign you in.");
99
+ res.redirect(303, "/login");
100
+ }
101
+ return;
102
+ }
103
+ if (req.expectsJson() && !req.isInertia()) {
104
+ const plain = typeof user?.toObject === "function" ? user.toObject() : user;
105
+ res.status(200).json({
106
+ tokens: { accessToken: tokens.accessToken },
107
+ user: plain,
108
+ });
109
+ return;
110
+ }
111
+ const sessionRedirect = req.jccSession?.get("redirect") || "";
112
+ req.jccSession?.forget("redirect");
113
+ const redirectTo = safeInternalRedirect(sessionRedirect, redirect);
114
+ res.redirect(303, redirectTo);
115
+ }
65
116
  /** Refresh token middleware */
66
117
  static async refreshToken(req, res, next) {
118
+ const { User } = (0, util_1.getModel)("User");
67
119
  try {
68
120
  const refreshToken = req.cookies.refresh_token;
69
121
  if (!refreshToken)
70
122
  throw new Error("No refresh token");
71
- const userId = (0, util_1.jwtVerify)(refreshToken);
123
+ const payload = (0, util_1.jwtVerify)(refreshToken);
124
+ const kind = (0, util_1.jwtTokenType)(payload);
125
+ if (kind === "access") {
126
+ throw new Error("Invalid refresh token");
127
+ }
128
+ const jti = payload != null &&
129
+ typeof payload === "object" &&
130
+ typeof payload.jti === "string"
131
+ ? payload.jti
132
+ : "";
133
+ if (!jti) {
134
+ throw new Error("Invalid refresh token");
135
+ }
136
+ const session = _a.refreshStore.consume(jti);
137
+ const userId = (0, util_1.jwtSubjectId)(payload);
138
+ if (!session || session.userId !== String(userId)) {
139
+ throw new Error("Invalid refresh token");
140
+ }
72
141
  this.setTokens(res, userId);
73
- // Use universal finder
74
142
  req.user = await (0, util_1.findUserById)(User, userId);
75
143
  next();
76
144
  }
77
145
  catch (error) {
78
- res.clearCookie("auth_token");
79
- res.clearCookie("refresh_token");
146
+ clearAuthCookies(res);
80
147
  return res.status(401).json({ message: "Unauthorized" });
81
148
  }
82
149
  }
83
150
  /** Logout handler */
84
- static logout(req, res) {
85
- res.clearCookie("auth_token");
86
- res.clearCookie("refresh_token");
151
+ static logout() {
152
+ const req = request();
153
+ const res = response();
154
+ try {
155
+ const rt = req.cookies?.refresh_token;
156
+ if (rt) {
157
+ const payload = (0, util_1.jwtVerify)(rt);
158
+ if (payload != null &&
159
+ typeof payload === "object" &&
160
+ typeof payload.jti === "string") {
161
+ _a.refreshStore.revoke(payload.jti);
162
+ }
163
+ }
164
+ }
165
+ catch {
166
+ /* expired or malformed */
167
+ }
168
+ clearAuthCookies(res);
87
169
  return res.redirect("/login");
88
170
  }
171
+ /** True when the access cookie is a valid, usable JWT (not refresh / disallowed legacy). */
172
+ static check() {
173
+ const token = request().cookies?.auth_token;
174
+ if (!token)
175
+ return false;
176
+ try {
177
+ const payload = (0, util_1.jwtVerify)(token);
178
+ return (0, util_1.checkJwtAccessTokenPayload)(payload).ok;
179
+ }
180
+ catch {
181
+ return false;
182
+ }
183
+ }
184
+ static user() {
185
+ return request().user;
186
+ }
187
+ static id() {
188
+ return request().user?.id || request().user?._id;
189
+ }
190
+ static async socialLogin(userId) {
191
+ return this.completeLogin(request(), response(), userId, "/home");
192
+ }
89
193
  }
90
194
  exports.Authentication = Authentication;
91
195
  _a = Authentication;
196
+ Authentication.refreshStore = refreshTokenStore_1.defaultRefreshTokenStore;
92
197
  /** Handle user login attempt */
93
- Authentication.attempt = async (req, res, next, redirect = "/home") => {
198
+ Authentication.attempt = async (next, redirect = "/home") => {
199
+ const req = request();
200
+ const res = response();
94
201
  try {
95
202
  const { user, field } = await _a.getUser(req.body);
96
203
  if (!user)
@@ -98,12 +205,7 @@ Authentication.attempt = async (req, res, next, redirect = "/home") => {
98
205
  if (!(await (0, util_1.verifyHash)(req.body.password, user.password))) {
99
206
  throw new ValidationException_v2_1.ValidationException({ [field]: ["Invalid credentials"] });
100
207
  }
101
- const tokens = _a.setTokens(res, user.id || user._id);
102
- if (req.expectsJson() && !req.isInertia()) {
103
- return res.status(200).json({ tokens, user });
104
- }
105
- const redirectTo = req.query.redirect?.toString() || redirect;
106
- return res.redirect(303, redirectTo);
208
+ await _a.completeLogin(req, res, user.id || user._id, redirect);
107
209
  }
108
210
  catch (error) {
109
211
  next(error);
@@ -0,0 +1,6 @@
1
+ import type { RequestHandler } from "express";
2
+ /** Stricter limit for login attempts (per IP). */
3
+ export declare const loginRateLimit: RequestHandler;
4
+ /** Stricter limit for registration (per IP). */
5
+ export declare const registerRateLimit: RequestHandler;
6
+ //# sourceMappingURL=loginRateLimit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loginRateLimit.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/loginRateLimit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,kDAAkD;AAClD,eAAO,MAAM,cAAc,EAAE,cAO3B,CAAC;AAEH,gDAAgD;AAChD,eAAO,MAAM,iBAAiB,EAAE,cAO9B,CAAC"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerRateLimit = exports.loginRateLimit = void 0;
7
+ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
8
+ /** Stricter limit for login attempts (per IP). */
9
+ exports.loginRateLimit = (0, express_rate_limit_1.default)({
10
+ windowMs: 15 * 60 * 1000,
11
+ max: 20,
12
+ message: { message: "Too many login attempts. Try again later." },
13
+ standardHeaders: true,
14
+ legacyHeaders: false,
15
+ validate: { trustProxy: false },
16
+ });
17
+ /** Stricter limit for registration (per IP). */
18
+ exports.registerRateLimit = (0, express_rate_limit_1.default)({
19
+ windowMs: 60 * 60 * 1000,
20
+ max: 10,
21
+ message: { message: "Too many registration attempts. Try again later." },
22
+ standardHeaders: true,
23
+ legacyHeaders: false,
24
+ validate: { trustProxy: false },
25
+ });
@@ -0,0 +1,24 @@
1
+ export type RefreshSession = {
2
+ userId: string;
3
+ expiresAt: number;
4
+ };
5
+ /** Pluggable store for refresh-token `jti` rotation (swap for Redis in multi-instance). */
6
+ export interface IRefreshTokenStore {
7
+ generateJti(): string;
8
+ register(jti: string, userId: string, ttlMs: number): void;
9
+ /** Remove and return the session if `jti` is valid and not expired. */
10
+ consume(jti: string): RefreshSession | undefined;
11
+ revoke(jti: string): void;
12
+ revokeAllForUser(userId: string): void;
13
+ }
14
+ export declare class MemoryRefreshTokenStore implements IRefreshTokenStore {
15
+ private readonly byJti;
16
+ generateJti(): string;
17
+ register(jti: string, userId: string, ttlMs: number): void;
18
+ consume(jti: string): RefreshSession | undefined;
19
+ revoke(jti: string): void;
20
+ revokeAllForUser(userId: string): void;
21
+ private prune;
22
+ }
23
+ export declare const defaultRefreshTokenStore: MemoryRefreshTokenStore;
24
+ //# sourceMappingURL=refreshTokenStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshTokenStore.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/refreshTokenStore.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,WAAW,IAAI,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3D,uEAAuE;IACvE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,qBAAa,uBAAwB,YAAW,kBAAkB;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAE3D,WAAW,IAAI,MAAM;IAIrB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ1D,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAQhD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAMtC,OAAO,CAAC,KAAK;CAMd;AAED,eAAO,MAAM,wBAAwB,yBAAgC,CAAC"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultRefreshTokenStore = exports.MemoryRefreshTokenStore = void 0;
4
+ const crypto_1 = require("crypto");
5
+ class MemoryRefreshTokenStore {
6
+ constructor() {
7
+ this.byJti = new Map();
8
+ }
9
+ generateJti() {
10
+ return (0, crypto_1.randomBytes)(32).toString("hex");
11
+ }
12
+ register(jti, userId, ttlMs) {
13
+ this.prune();
14
+ this.byJti.set(jti, {
15
+ userId,
16
+ expiresAt: Date.now() + ttlMs,
17
+ });
18
+ }
19
+ consume(jti) {
20
+ const row = this.byJti.get(jti);
21
+ if (!row)
22
+ return undefined;
23
+ this.byJti.delete(jti);
24
+ if (Date.now() > row.expiresAt)
25
+ return undefined;
26
+ return row;
27
+ }
28
+ revoke(jti) {
29
+ this.byJti.delete(jti);
30
+ }
31
+ revokeAllForUser(userId) {
32
+ for (const [k, v] of this.byJti) {
33
+ if (v.userId === userId)
34
+ this.byJti.delete(k);
35
+ }
36
+ }
37
+ prune() {
38
+ const now = Date.now();
39
+ for (const [k, v] of this.byJti) {
40
+ if (v.expiresAt < now)
41
+ this.byJti.delete(k);
42
+ }
43
+ }
44
+ }
45
+ exports.MemoryRefreshTokenStore = MemoryRefreshTokenStore;
46
+ exports.defaultRefreshTokenStore = new MemoryRefreshTokenStore();
@@ -1 +1 @@
1
- {"version":3,"file":"DBCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/DBCommand.ts"],"names":[],"mappings":"AAMA,qBAAa,SAAS;IACpB,OAAO,CAAC,WAAW,CAA0C;IAE7D,OAAO,CAAC,YAAY;IAQd,IAAI;IAqBJ,YAAY,CAAC,UAAU,EAAE,MAAM;IAW/B,IAAI;CA+BX"}
1
+ {"version":3,"file":"DBCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/DBCommand.ts"],"names":[],"mappings":"AAMA,qBAAa,SAAS;IACpB,OAAO,CAAC,WAAW,CAA0C;IAE7D,OAAO,CAAC,YAAY;IAad,IAAI;IAqBJ,YAAY,CAAC,UAAU,EAAE,MAAM;IAW/B,IAAI;CA+BX"}
@@ -14,11 +14,17 @@ class DBCommand {
14
14
  this.seedersPath = `${rootPath}/database/seeders`;
15
15
  }
16
16
  getSeederDir(seederFile) {
17
+ const base = `${this.seedersPath}/${seederFile}`;
17
18
  try {
18
- return require(`${this.seedersPath}/${seederFile}`);
19
+ return require(base);
19
20
  }
20
- catch (error) {
21
- console.log(`Can't get the seeder with name of ${seederFile}`);
21
+ catch {
22
+ try {
23
+ return require(`${base}.ts`);
24
+ }
25
+ catch {
26
+ console.log(`Can't get the seeder with name of ${seederFile}`);
27
+ }
22
28
  }
23
29
  }
24
30
  async seed() {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Generate a cryptographically strong secret (64 hex chars = 32 bytes).
3
+ * Default env key: JWT_SECRET (meets production length checks in this framework).
4
+ */
5
+ export declare function runKeyGenerate(firstArg?: string, secondArg?: string): void;
6
+ //# sourceMappingURL=KeyGenerateCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeyGenerateCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/KeyGenerateCommand.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAK,EAAE,SAAS,SAAK,GAAG,IAAI,CAoClE"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runKeyGenerate = runKeyGenerate;
7
+ const crypto_1 = require("crypto");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const app_root_path_1 = __importDefault(require("app-root-path"));
11
+ const colors_1 = __importDefault(require("colors"));
12
+ function escapeRegex(s) {
13
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
14
+ }
15
+ /**
16
+ * Generate a cryptographically strong secret (64 hex chars = 32 bytes).
17
+ * Default env key: JWT_SECRET (meets production length checks in this framework).
18
+ */
19
+ function runKeyGenerate(firstArg = "", secondArg = "") {
20
+ const showOnly = firstArg === "show" ||
21
+ secondArg === "show" ||
22
+ secondArg === "--show";
23
+ const keyName = firstArg && firstArg !== "show" ? firstArg : "JWT_SECRET";
24
+ const value = (0, crypto_1.randomBytes)(32).toString("hex");
25
+ if (showOnly) {
26
+ console.log(colors_1.default.green(`${keyName}=`) + value);
27
+ return;
28
+ }
29
+ const envPath = path_1.default.join(app_root_path_1.default.path, ".env");
30
+ if (!fs_1.default.existsSync(envPath)) {
31
+ console.log(colors_1.default.yellow(".env not found. Add this line to your environment file:\n"));
32
+ console.log(colors_1.default.cyan(`${keyName}=${value}\n`));
33
+ return;
34
+ }
35
+ let contents = fs_1.default.readFileSync(envPath, "utf8");
36
+ const re = new RegExp(`^${escapeRegex(keyName)}=.*$`, "m");
37
+ const line = `${keyName}=${value}`;
38
+ if (re.test(contents)) {
39
+ contents = contents.replace(re, line);
40
+ }
41
+ else {
42
+ contents = contents.replace(/\s*$/, "") + "\n" + line + "\n";
43
+ }
44
+ fs_1.default.writeFileSync(envPath, contents, "utf8");
45
+ console.log(colors_1.default.green(`✓ Set ${keyName} in .env`) +
46
+ colors_1.default.gray(` (${value.length} characters)`));
47
+ }
@@ -9,12 +9,14 @@ export declare class ConsoleKernel {
9
9
  private _make;
10
10
  private _route;
11
11
  private _schedule;
12
+ private _watch;
12
13
  private _app;
13
14
  private get migrate();
14
15
  private get db();
15
16
  private get make();
16
17
  private get route();
17
18
  private get schedule();
19
+ private get watch();
18
20
  private app;
19
21
  constructor();
20
22
  /** Load user commands from app/Console/Command (guarded, non-blocking for missing dir) */
@@ -1 +1 @@
1
- {"version":3,"file":"NodeArtisanCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/NodeArtisanCommand.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCpC,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAK1B;IACF,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,IAAI,CAAc;IAE1B,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,EAAE,GAEb;IAED,OAAO,KAAK,IAAI,GAEf;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,QAAQ,GAEnB;IACD,OAAO,CAAC,GAAG;;IAWX,0FAA0F;IAC1F,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,aAAa;IAOrB,wFAAwF;IACxF,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,aAAa;IAkKrB,OAAO,CAAC,QAAQ;IAwHhB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;CA4BpD"}
1
+ {"version":3,"file":"NodeArtisanCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/NodeArtisanCommand.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAK1B;IACF,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,IAAI,CAAc;IAE1B,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,EAAE,GAEb;IAED,OAAO,KAAK,IAAI,GAEf;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,KAAK,GAEhB;IACD,OAAO,CAAC,GAAG;;IAWX,0FAA0F;IAC1F,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,aAAa;IAOrB,wFAAwF;IACxF,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,aAAa;IAoLrB,OAAO,CAAC,QAAQ;IA+HhB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;CA4BpD"}
@@ -18,7 +18,9 @@ const MakeCommand_1 = require("./MakeCommand");
18
18
  const RouteCommand_1 = require("./RouteCommand");
19
19
  const ScheduleCommand_1 = require("./ScheduleCommand");
20
20
  const InertiaCommand_1 = require("./InertiaCommand");
21
+ const KeyGenerateCommand_1 = require("./KeyGenerateCommand");
21
22
  const Tinker_1 = require("./NodeTinker/Tinker");
23
+ const WatchCommand_1 = require("./WatchCommand");
22
24
  const util_1 = require("../util");
23
25
  /** Parse key=value from secondArg (e.g. steps=2, class=UserSeeder) */
24
26
  const parseOption = (secondArg, key) => {
@@ -43,6 +45,9 @@ class ConsoleKernel {
43
45
  get schedule() {
44
46
  return (this._schedule ??= new ScheduleCommand_1.ScheduleCommand());
45
47
  }
48
+ get watch() {
49
+ return (this._watch ??= new WatchCommand_1.WatchCommand());
50
+ }
46
51
  app() {
47
52
  const bootstrap = require(`${app_root_path_1.default.path}/bootstrap/app`);
48
53
  const app = bootstrap.app;
@@ -57,6 +62,7 @@ class ConsoleKernel {
57
62
  this._make = null;
58
63
  this._route = null;
59
64
  this._schedule = null;
65
+ this._watch = null;
60
66
  this._app = this.app();
61
67
  this.loadCustomCommands();
62
68
  }
@@ -184,13 +190,22 @@ class ConsoleKernel {
184
190
  : undefined;
185
191
  return this.route.display(mw);
186
192
  }));
187
- this.defineCommand("tinker").action(this.runAction(() => Tinker_1.tinker.start(), { exit: false }));
188
- this.defineCommand("inertia:start-ssr").action(this.runAction(() => InertiaCommand_1.InertiaCommand.startInertiaSSR()));
193
+ this.defineCommand("tinker").action(this.runAction(() => (0, Tinker_1.getTinker)().start(), { exit: false }));
194
+ this.defineCommand("inertia:start-ssr").action(this.runAction(() => InertiaCommand_1.InertiaCommand.startInertiaSSR(), { exit: false }));
195
+ this.defineCommand("serve")
196
+ .alias("watch")
197
+ .action(this.runAction((firstArg) => this.watch.run(firstArg || "server.ts"), {
198
+ exit: false,
199
+ }));
189
200
  // ─── schedule (was missing) ─────────────────────────────────────────
190
201
  this.defineCommand("schedule:run").action(this.runAction(() => this.schedule.run(), { exit: false }));
191
202
  this.defineCommand("schedule:list").action(this.runAction(() => this.schedule.list()));
192
203
  // ─── build ──────────────────────────────────────────────────────────
193
204
  this.defineCommand("build").action(this.runAction(() => (0, buildCommand_1.BuildCommand)()));
205
+ // ─── key (JWT / app secrets) ─────────────────────────────────────────
206
+ this.defineCommand("key:generate")
207
+ .description("Generate a random secret (default: JWT_SECRET in .env). Use 'show' to print only.")
208
+ .action(this.runAction((firstArg, secondArg) => (0, KeyGenerateCommand_1.runKeyGenerate)(firstArg ?? "", secondArg ?? "")));
194
209
  // ─── custom user commands ────────────────────────────────────────────
195
210
  for (const { signature, description, CommandClass } of this
196
211
  .customCommands) {
@@ -235,7 +250,9 @@ class ConsoleKernel {
235
250
  console.log(line("route:list [middleware=]", "Display routes (optionally filtered)\n"));
236
251
  console.log(section("⚡ Development Tools:"));
237
252
  console.log(line("tinker", "Start the interactive Tinker REPL"));
238
- console.log(line("build", "Build the application for production\n"));
253
+ console.log(line("serve [entry]", "Watch files and restart app on changes"));
254
+ console.log(line("build", "Build the application for production"));
255
+ console.log(line("key:generate [name] [show]", "Random secret → .env (default JWT_SECRET); name=env key, show=print only") + "\n");
239
256
  console.log(section("⏰ Schedule Commands:"));
240
257
  console.log(line("schedule:run", "Run scheduled tasks (runs continuously)"));
241
258
  console.log(line("schedule:list", "List all scheduled tasks\n"));
@@ -126,6 +126,9 @@ export declare class Tinker {
126
126
  */
127
127
  private exit;
128
128
  }
129
- declare const tinker: Tinker;
130
- export { tinker };
129
+ /**
130
+ * Lazily construct Tinker so importing the artisan kernel does not attach
131
+ * readline to stdin/stdout (which felt like Tinker “running” for every command).
132
+ */
133
+ export declare function getTinker(config?: TinkerConfig): Tinker;
131
134
  //# sourceMappingURL=Tinker.d.ts.map