create-warlock 4.16.0 → 5.0.1

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 (38) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/esm/commands/create-new-app/index.mjs +14 -4
  3. package/esm/commands/create-new-app/index.mjs.map +1 -1
  4. package/esm/commands/create-warlock-app/index.mjs +123 -16
  5. package/esm/commands/create-warlock-app/index.mjs.map +1 -1
  6. package/esm/features/features-map.mjs +6 -0
  7. package/esm/features/features-map.mjs.map +1 -1
  8. package/esm/helpers/app.mjs +74 -3
  9. package/esm/helpers/app.mjs.map +1 -1
  10. package/esm/helpers/exec.mjs +164 -23
  11. package/esm/helpers/exec.mjs.map +1 -1
  12. package/esm/helpers/project-builder-helpers.mjs +22 -12
  13. package/esm/helpers/project-builder-helpers.mjs.map +1 -1
  14. package/esm/helpers/warlock-versions.mjs +166 -0
  15. package/esm/helpers/warlock-versions.mjs.map +1 -0
  16. package/esm/index.mjs +7 -1
  17. package/esm/index.mjs.map +1 -1
  18. package/esm/ui/report.mjs +98 -0
  19. package/esm/ui/report.mjs.map +1 -0
  20. package/esm/ui/spinners.mjs +13 -3
  21. package/esm/ui/spinners.mjs.map +1 -1
  22. package/package.json +2 -2
  23. package/templates/warlock/src/app/auth/controllers/forgot-password.controller.ts +2 -5
  24. package/templates/warlock/src/app/auth/controllers/login.controller.ts +4 -1
  25. package/templates/warlock/src/app/auth/controllers/logout-all.controller.ts +2 -2
  26. package/templates/warlock/src/app/auth/controllers/logout.controller.ts +2 -2
  27. package/templates/warlock/src/app/auth/controllers/me.controller.ts +2 -2
  28. package/templates/warlock/src/app/auth/controllers/refresh-token.controller.ts +2 -5
  29. package/templates/warlock/src/app/auth/controllers/reset-password.controller.ts +2 -2
  30. package/templates/warlock/src/app/posts/controllers/create-new-post.controller.ts +2 -2
  31. package/templates/warlock/src/app/posts/controllers/update-post.controller.ts +2 -2
  32. package/templates/warlock/src/app/shared/controllers/home-page.controller.ts +1 -1
  33. package/templates/warlock/src/app/shared/controllers/home-page.controller.tsx +2 -2
  34. package/templates/warlock/src/app/uploads/controllers/fetch-uploaded-file.controller.ts +1 -1
  35. package/templates/warlock/src/app/users/controllers/create-new-user.controller.ts +2 -2
  36. package/templates/warlock/src/app/users/controllers/list-users.controller.ts +1 -1
  37. package/templates/warlock/src/app/users/services/login-social.ts +13 -3
  38. package/templates/warlock/src/config/cache.ts +4 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.mjs","names":[],"sources":["../../../../../../create-warlock/src/ui/report.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport type { CommandResult } from \"../helpers/exec\";\nimport { tail } from \"../helpers/exec\";\n\n/**\n * Failure reporting for the scaffolder.\n *\n * The house rule this module enforces: a step that did not succeed is never\n * described as if it did, and a failure always carries three things — WHAT ran,\n * HOW it ended (exit code), and ENOUGH of its output to act on. \"Something went\n * wrong, add it later\" is not a report.\n */\n\n/** A step that did not do what the user asked for. */\nexport type Problem = {\n /** The step, e.g. `Dependency install`. */\n step: string;\n /** One-line summary of what is now missing / broken. */\n detail: string;\n /** The command behind the failure, when there was one. */\n result?: CommandResult;\n /** Extra guidance: how to retry, what to check. */\n hints?: string[];\n};\n\nconst bullet = colors.red(\"✖\");\n\n/**\n * The command line, its exit status, and the tail of what it printed.\n */\nfunction describeCommand(result: CommandResult): string[] {\n const lines: string[] = [];\n\n lines.push(`${colors.dim(\"command:\")} ${colors.white(result.command)}`);\n\n if (result.cwd) {\n lines.push(`${colors.dim(\"in:\")} ${colors.white(result.cwd)}`);\n }\n\n if (result.error) {\n lines.push(\n `${colors.dim(\"failed:\")} ${colors.white(result.error.message || String(result.error))}`,\n );\n } else if (result.signal) {\n lines.push(`${colors.dim(\"killed:\")} ${colors.white(result.signal)}`);\n } else {\n lines.push(\n `${colors.dim(\"exited:\")} ${colors.white(`code ${result.code}`)}`,\n );\n }\n\n const output = tail(result.stderr) || tail(result.stdout);\n\n if (output) {\n lines.push(colors.dim(\"output:\"));\n\n for (const line of output.split(\"\\n\")) {\n lines.push(` ${colors.dim(line)}`);\n }\n }\n\n return lines;\n}\n\nfunction printProblem(problem: Problem) {\n console.log(` ${bullet} ${colors.bold(colors.red(problem.step))}`);\n console.log(` ${colors.white(problem.detail)}`);\n\n if (problem.result) {\n for (const line of describeCommand(problem.result)) {\n console.log(` ${line}`);\n }\n }\n\n for (const hint of problem.hints ?? []) {\n console.log(` ${colors.yellow(\"→\")} ${colors.yellow(hint)}`);\n }\n\n console.log();\n}\n\n/**\n * Report a failure the scaffold cannot continue past, and leave the process\n * with a non-zero exit code. Nothing after this point may print a success.\n */\nexport function failFatally(problem: Problem): never {\n console.log();\n console.log(colors.bold(colors.red(\" SCAFFOLD FAILED\")));\n console.log();\n\n printProblem(problem);\n\n console.log(\n colors.dim(\n \" The project directory was left in place so you can inspect it.\",\n ),\n );\n console.log();\n\n process.exit(1);\n}\n\n/**\n * Report the steps that failed on a scaffold that otherwise completed, and say\n * plainly what the project does NOT have as a result.\n */\nexport function showProblems(problems: Problem[]) {\n if (problems.length === 0) return;\n\n console.log();\n console.log(\n colors.bold(\n colors.yellow(\n ` COMPLETED WITH ${problems.length} PROBLEM${problems.length === 1 ? \"\" : \"S\"}`,\n ),\n ),\n );\n console.log();\n\n for (const problem of problems) {\n printProblem(problem);\n }\n}\n\n/** Neutral, non-failing information — e.g. which versions got pinned and why. */\nexport function showNotes(notes: string[]) {\n for (const note of notes) {\n console.log(` ${colors.yellow(\"!\")} ${colors.dim(note)}`);\n }\n\n if (notes.length > 0) console.log();\n}\n\n/**\n * A scaffold that finished with problems still produced a project, so print the\n * same facts the success screen would — minus the celebration, and listing only\n * what is actually installed.\n */\nexport function showPartialScreen(options: {\n projectName: string;\n database: string;\n features: string[];\n missingFeatures: string[];\n packageManager: string;\n}): void {\n const { projectName, database, features, missingFeatures, packageManager } =\n options;\n\n const devCommand =\n packageManager === \"npm\" ? \"npm run dev\" : `${packageManager} dev`;\n\n console.log(\n ` ${colors.bold(colors.yellow(\"⚠ PROJECT CREATED — BUT NOT AS REQUESTED\"))}`,\n );\n console.log();\n console.log(` ${colors.dim(\"Project: \")}${colors.white(projectName)}`);\n console.log(` ${colors.dim(\"Database: \")}${colors.white(database)}`);\n console.log(\n ` ${colors.dim(\"Installed:\")}${colors.white(features.length > 0 ? \" \" + features.join(\", \") : \" none\")}`,\n );\n\n if (missingFeatures.length > 0) {\n console.log(\n ` ${colors.dim(\"Missing: \")}${colors.red(missingFeatures.join(\", \"))}`,\n );\n }\n\n console.log();\n console.log(` ${colors.dim(\"Fix the problems above, then:\")}`);\n console.log();\n console.log(` ${colors.cyan(\"cd\")} ${projectName}`);\n\n if (missingFeatures.length > 0) {\n console.log(\n ` ${colors.cyan(`npx warlock add ${missingFeatures.join(\" \")}`)}`,\n );\n }\n\n console.log(` ${colors.cyan(devCommand)}`);\n console.log();\n}\n\n/**\n * Turn an npm/yarn/pnpm failure into actionable guidance where we can\n * recognise it. `ETARGET` in particular is the signature of a dependency\n * pinned to a version that was never published — the bug this whole reporting\n * path was written for.\n */\nexport function installFailureHints(result: CommandResult | undefined) {\n const hints = [\n \"Nothing was installed. Fix the error above, then run the install again inside the project.\",\n ];\n\n const output = `${result?.stdout ?? \"\"}${result?.stderr ?? \"\"}`;\n\n if (/ETARGET|No matching version found/i.test(output)) {\n hints.push(\n \"A dependency is pinned to a version that does not exist on the registry — check the @warlock.js/* versions in package.json.\",\n );\n }\n\n if (/ENOTFOUND|ETIMEDOUT|ECONNREFUSED|network/i.test(output)) {\n hints.push(\"The registry was unreachable — check your network or proxy.\");\n }\n\n if (/EACCES|EPERM/i.test(output)) {\n hints.push(\n \"Permission denied — check the directory's ownership before retrying.\",\n );\n }\n\n return hints;\n}\n"],"mappings":"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"}
@@ -1,21 +1,31 @@
1
1
  //#region ../create-warlock/src/ui/spinners.ts
2
2
  /**
3
- * Themed spinner messages for the wizard
3
+ * Themed spinner messages for the wizard.
4
+ *
5
+ * Every step has BOTH a success and a failure message, and the orchestrator
6
+ * picks between them from the step's actual result. A spinner that can only
7
+ * stop with a cheerful message is a spinner that lies.
4
8
  */
5
9
  const spinnerMessages = {
6
10
  installingDeps: "Summoning dependencies...",
7
11
  depsInstalled: "Dependencies materialized!",
12
+ depsFailed: "Dependencies could not be installed",
8
13
  initializingGit: "Initializing grimoire (git)...",
9
14
  gitInitialized: "Grimoire initialized!",
15
+ gitFailed: "Git repository was not initialized",
10
16
  generatingJwt: "Forging secret keys...",
11
17
  jwtGenerated: "Secret keys forged!",
18
+ jwtFailed: "Secret keys were NOT generated",
12
19
  warmingCache: "Charging magical circuits...",
13
20
  cacheWarmed: "Circuits charged!",
21
+ cacheWarmFailed: "Cache could not be warmed (harmless — it builds on first run)",
14
22
  addingFeatures: "Weaving in your features...",
15
23
  featuresAdded: "Features woven in!",
16
- featuresFailed: "Some features could not be added add them later with`warlock add`",
24
+ featuresPartial: "Some features were not added",
25
+ featuresFailed: "No features could be added",
17
26
  copyingTemplate: "Preparing your spellbook...",
18
- templateCopied: "Spellbook ready!"
27
+ templateCopied: "Spellbook ready!",
28
+ templateFailed: "The project template could not be copied"
19
29
  };
20
30
 
21
31
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"spinners.mjs","names":[],"sources":["../../../../../../create-warlock/src/ui/spinners.ts"],"sourcesContent":["/**\n * Themed spinner messages for the wizard\n */\nexport const spinnerMessages = {\n installingDeps: \"Summoning dependencies...\",\n depsInstalled: \"Dependencies materialized!\",\n\n initializingGit: \"Initializing grimoire (git)...\",\n gitInitialized: \"Grimoire initialized!\",\n\n generatingJwt: \"Forging secret keys...\",\n jwtGenerated: \"Secret keys forged!\",\n\n warmingCache: \"Charging magical circuits...\",\n cacheWarmed: \"Circuits charged!\",\n\n addingFeatures: \"Weaving in your features...\",\n featuresAdded: \"Features woven in!\",\n featuresFailed:\n \"Some features could not be added add them later with`warlock add`\",\n\n copyingTemplate: \"Preparing your spellbook...\",\n templateCopied: \"Spellbook ready!\",\n} as const;\n"],"mappings":";;;;AAGA,MAAa,kBAAkB;CAC7B,gBAAgB;CAChB,eAAe;CAEf,iBAAiB;CACjB,gBAAgB;CAEhB,eAAe;CACf,cAAc;CAEd,cAAc;CACd,aAAa;CAEb,gBAAgB;CAChB,eAAe;CACf,gBACE;CAEF,iBAAiB;CACjB,gBAAgB;AAClB"}
1
+ {"version":3,"file":"spinners.mjs","names":[],"sources":["../../../../../../create-warlock/src/ui/spinners.ts"],"sourcesContent":["/**\n * Themed spinner messages for the wizard.\n *\n * Every step has BOTH a success and a failure message, and the orchestrator\n * picks between them from the step's actual result. A spinner that can only\n * stop with a cheerful message is a spinner that lies.\n */\nexport const spinnerMessages = {\n installingDeps: \"Summoning dependencies...\",\n depsInstalled: \"Dependencies materialized!\",\n depsFailed: \"Dependencies could not be installed\",\n\n initializingGit: \"Initializing grimoire (git)...\",\n gitInitialized: \"Grimoire initialized!\",\n gitFailed: \"Git repository was not initialized\",\n\n generatingJwt: \"Forging secret keys...\",\n jwtGenerated: \"Secret keys forged!\",\n jwtFailed: \"Secret keys were NOT generated\",\n\n warmingCache: \"Charging magical circuits...\",\n cacheWarmed: \"Circuits charged!\",\n cacheWarmFailed:\n \"Cache could not be warmed (harmless — it builds on first run)\",\n\n addingFeatures: \"Weaving in your features...\",\n featuresAdded: \"Features woven in!\",\n featuresPartial: \"Some features were not added\",\n featuresFailed: \"No features could be added\",\n\n copyingTemplate: \"Preparing your spellbook...\",\n templateCopied: \"Spellbook ready!\",\n templateFailed: \"The project template could not be copied\",\n} as const;\n"],"mappings":";;;;;;;;AAOA,MAAa,kBAAkB;CAC7B,gBAAgB;CAChB,eAAe;CACf,YAAY;CAEZ,iBAAiB;CACjB,gBAAgB;CAChB,WAAW;CAEX,eAAe;CACf,cAAc;CACd,WAAW;CAEX,cAAc;CACd,aAAa;CACb,iBACE;CAEF,gBAAgB;CAChB,eAAe;CACf,iBAAiB;CACjB,gBAAgB;CAEhB,iBAAiB;CACjB,gBAAgB;CAChB,gBAAgB;AAClB"}
package/package.json CHANGED
@@ -12,13 +12,13 @@
12
12
  "dependencies": {
13
13
  "@clack/prompts": "^0.7.0",
14
14
  "@mongez/copper": "^2.1.2",
15
- "@warlock.js/fs": "4.16.0",
15
+ "@warlock.js/fs": "5.0.1",
16
16
  "@mongez/reinforcements": "^4.0.1",
17
17
  "cross-spawn": "^7.0.3",
18
18
  "rimraf": "^6.0.1",
19
19
  "which-pm-runs": "^1.1.0"
20
20
  },
21
- "version": "4.16.0",
21
+ "version": "5.0.1",
22
22
  "type": "module",
23
23
  "main": "./esm/index.mjs",
24
24
  "module": "./esm/index.mjs",
@@ -1,4 +1,4 @@
1
- import { t, type Request, type RequestHandler, type Response } from "@warlock.js/core";
1
+ import { t, type RequestHandler } from "@warlock.js/core";
2
2
  import { v } from "@warlock.js/seal";
3
3
  import { forgotPasswordService } from "../services/forgot-password.service";
4
4
 
@@ -6,10 +6,7 @@ import { forgotPasswordService } from "../services/forgot-password.service";
6
6
  * Forgot password controller
7
7
  * POST /auth/forgot-password
8
8
  */
9
- export const forgotPasswordController: RequestHandler = async (
10
- request: Request,
11
- response: Response,
12
- ) => {
9
+ export const forgotPasswordController: RequestHandler = async ({ request, response }) => {
13
10
  const { email } = request.validated();
14
11
 
15
12
  await forgotPasswordService(email);
@@ -6,7 +6,10 @@ import { loginService } from "../services/auth.service";
6
6
  * Login controller
7
7
  * POST /auth/login
8
8
  */
9
- export const loginController: RequestHandler<Request<LoginSchema>> = async (request, response) => {
9
+ export const loginController: RequestHandler<Request<LoginSchema>> = async ({
10
+ request,
11
+ response,
12
+ }) => {
10
13
  const result = await loginService(request.validated(), {
11
14
  userAgent: request.userAgent,
12
15
  ip: request.ip,
@@ -1,11 +1,11 @@
1
- import { t, type Request, type RequestHandler, type Response } from "@warlock.js/core";
1
+ import { t, type RequestHandler } from "@warlock.js/core";
2
2
  import { logoutAllService } from "../services/auth.service";
3
3
 
4
4
  /**
5
5
  * Logout from all devices controller
6
6
  * POST /auth/logout-all
7
7
  */
8
- export const logoutAllController: RequestHandler = async (request: Request, response: Response) => {
8
+ export const logoutAllController: RequestHandler = async ({ request, response }) => {
9
9
  await logoutAllService(request.user);
10
10
 
11
11
  return response.success({
@@ -1,11 +1,11 @@
1
- import { t, type Request, type RequestHandler, type Response } from "@warlock.js/core";
1
+ import { t, type RequestHandler } from "@warlock.js/core";
2
2
  import { logoutService } from "../services/auth.service";
3
3
 
4
4
  /**
5
5
  * Logout controller
6
6
  * POST /auth/logout
7
7
  */
8
- export const logoutController: RequestHandler = async (request: Request, response: Response) => {
8
+ export const logoutController: RequestHandler = async ({ request, response }) => {
9
9
  await logoutService(request.user);
10
10
 
11
11
  return response.success({
@@ -1,10 +1,10 @@
1
- import { type Request, type RequestHandler, type Response } from "@warlock.js/core";
1
+ import { type RequestHandler } from "@warlock.js/core";
2
2
 
3
3
  /**
4
4
  * Get current user controller
5
5
  * GET /auth/me
6
6
  */
7
- export const meController: RequestHandler = async (request: Request, response: Response) => {
7
+ export const meController: RequestHandler = async ({ request, response }) => {
8
8
  return response.success({
9
9
  user: request.user,
10
10
  });
@@ -1,4 +1,4 @@
1
- import { type Request, type RequestHandler, type Response } from "@warlock.js/core";
1
+ import { type RequestHandler } from "@warlock.js/core";
2
2
  import { v } from "@warlock.js/seal";
3
3
  import { refreshTokensService } from "../services/auth.service";
4
4
 
@@ -6,10 +6,7 @@ import { refreshTokensService } from "../services/auth.service";
6
6
  * Refresh token controller
7
7
  * POST /auth/refresh-token
8
8
  */
9
- export const refreshTokenController: RequestHandler = async (
10
- request: Request,
11
- response: Response,
12
- ) => {
9
+ export const refreshTokenController: RequestHandler = async ({ request, response }) => {
13
10
  const token = request.input("refreshToken");
14
11
 
15
12
  const result = await refreshTokensService(token, {
@@ -5,10 +5,10 @@ import { resetPasswordService } from "../services/reset-password.service";
5
5
  /**
6
6
  * Reset password controller
7
7
  */
8
- export const resetPasswordController: RequestHandler<Request<ResetPasswordSchema>> = async (
8
+ export const resetPasswordController: RequestHandler<Request<ResetPasswordSchema>> = async ({
9
9
  request,
10
10
  response,
11
- ) => {
11
+ }) => {
12
12
  await resetPasswordService(request.validated());
13
13
 
14
14
  return response.success({
@@ -2,10 +2,10 @@ import { type GuardedRequestHandler } from "app/auth/requests/guarded.request";
2
2
  import { Post } from "../models/post/post.model";
3
3
  import { type CreatePostSchema, createPostSchema } from "../schema/create-post.schema";
4
4
 
5
- export const createNewPostController: GuardedRequestHandler<CreatePostSchema> = async (
5
+ export const createNewPostController: GuardedRequestHandler<CreatePostSchema> = async ({
6
6
  request,
7
7
  response,
8
- ) => {
8
+ }) => {
9
9
  const post = await Post.create({
10
10
  ...request.validated(),
11
11
  authorId: request.user.id,
@@ -2,10 +2,10 @@ import { type GuardedRequestHandler } from "app/auth/requests/guarded.request";
2
2
  import { Post } from "../models/post/post.model";
3
3
  import { type UpdatePostSchema, updatePostSchema } from "../schema/update-post.schema";
4
4
 
5
- export const updatePostController: GuardedRequestHandler<UpdatePostSchema> = async (
5
+ export const updatePostController: GuardedRequestHandler<UpdatePostSchema> = async ({
6
6
  request,
7
7
  response,
8
- ) => {
8
+ }) => {
9
9
  const id = request.int("id");
10
10
 
11
11
  if (!id) {
@@ -7,7 +7,7 @@ import { Application, type RequestHandler } from "@warlock.js/core";
7
7
  * page (`home-page.controller.tsx` + `HomePageComponent.tsx`) instead; this
8
8
  * plain controller is removed at scaffold time when React is selected.
9
9
  */
10
- export const homePageController: RequestHandler = async (_request, response) => {
10
+ export const homePageController: RequestHandler = async ({ response }) => {
11
11
  return response.success({
12
12
  message: "Welcome to Warlock 🧙 — your app is up and running!",
13
13
  version: Application.version,
@@ -1,7 +1,7 @@
1
- import { type Request, type RequestHandler, type Response } from "@warlock.js/core";
1
+ import { type RequestHandler } from "@warlock.js/core";
2
2
  import { HomePageComponent } from "../components/HomePageComponent";
3
3
 
4
- export const homePageController: RequestHandler = async (_request: Request, response: Response) => {
4
+ export const homePageController: RequestHandler = async ({ response }) => {
5
5
  return response.render(<HomePageComponent />);
6
6
  };
7
7
 
@@ -3,7 +3,7 @@ import { Image, type RequestHandler, storage } from "@warlock.js/core";
3
3
  import { fileExistsAsync } from "@warlock.js/fs";
4
4
  import { v } from "@warlock.js/seal";
5
5
 
6
- export const fetchUploadedFileController: RequestHandler = async (request, response) => {
6
+ export const fetchUploadedFileController: RequestHandler = async ({ request, response }) => {
7
7
  const absolutePath = storage.root(request.input("*"));
8
8
 
9
9
  const { w: width, h: height } = request.validated();
@@ -2,10 +2,10 @@ import { type GuardedRequestHandler } from "app/auth/requests/guarded.request";
2
2
  import { User } from "../models/user";
3
3
  import { type CreateUserSchema, createUserSchema } from "../schema/create-user.schema";
4
4
 
5
- export const createNewUserController: GuardedRequestHandler<CreateUserSchema> = async (
5
+ export const createNewUserController: GuardedRequestHandler<CreateUserSchema> = async ({
6
6
  request,
7
7
  response,
8
- ) => {
8
+ }) => {
9
9
  const file = request.file("image")!;
10
10
 
11
11
  const output = await file.save("images");
@@ -1,7 +1,7 @@
1
1
  import { type GuardedRequestHandler } from "app/auth/requests/guarded.request";
2
2
  import { usersRepository } from "../repositories/users.repository";
3
3
 
4
- export const listUsersController: GuardedRequestHandler = async (request, response) => {
4
+ export const listUsersController: GuardedRequestHandler = async ({ request, response }) => {
5
5
  const users = await usersRepository.listCached(request.all());
6
6
 
7
7
  return response.success({
@@ -1,6 +1,14 @@
1
- import type { Request, Response } from "@warlock.js/core";
1
+ import type { GuardedRequestHandler } from "app/auth/requests/guarded.request";
2
2
 
3
- export default async function loginSocial(request: Request, response: Response) {
3
+ /**
4
+ * Social login handler.
5
+ *
6
+ * Despite living under `services/`, this is a route handler: it consumes the
7
+ * request and returns a response. It is typed as a `GuardedRequestHandler` so
8
+ * it can be wired straight into a route, and so `request.user` resolves to the
9
+ * app's `User` model rather than core's optional `RequestUser`.
10
+ */
11
+ const loginSocial: GuardedRequestHandler = async ({ request, response }) => {
4
12
  const user = request.user;
5
13
 
6
14
  const auth = await user.generateAccessToken();
@@ -16,4 +24,6 @@ export default async function loginSocial(request: Request, response: Response)
16
24
  userType: user.userType,
17
25
  },
18
26
  });
19
- }
27
+ };
28
+
29
+ export default loginSocial;
@@ -30,7 +30,10 @@ const globalPrefix = () => {
30
30
  };
31
31
 
32
32
  const cacheConfigurations: CacheConfigurations<"database"> = {
33
- default: "redis",
33
+ // Driven by CACHE_DRIVER so the shipped .env (`memory`) actually wins.
34
+ // Hardcoding "redis" made a `--no-db` scaffold hang forever retrying a
35
+ // Redis connection that was never going to exist.
36
+ default: env("CACHE_DRIVER") || "redis",
34
37
  drivers: {
35
38
  file: FileCacheDriver,
36
39
  memory: MemoryCacheDriver,