create-warlock 4.2.5 → 4.2.7
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/CHANGELOG.md +14 -0
- package/bin/create-app.js +5 -0
- package/package.json +2 -2
- package/templates/warlock/.env.example +36 -0
- package/templates/warlock/.gitattributes +1 -0
- package/templates/warlock/.husky/pre-commit +4 -0
- package/templates/warlock/.prettierignore +4 -0
- package/templates/warlock/.prettierrc.json +10 -0
- package/templates/warlock/.vscode/settings.json +41 -0
- package/templates/warlock/README.md +57 -0
- package/templates/warlock/_.gitignore +6 -0
- package/templates/warlock/docs/new-module.md +551 -0
- package/templates/warlock/eslint.config.js +98 -0
- package/templates/warlock/package.json +74 -0
- package/templates/warlock/public/home.css +523 -0
- package/templates/warlock/skills/api-design/SKILL.md +461 -0
- package/templates/warlock/skills/code-standards/SKILL.md +595 -0
- package/templates/warlock/skills/data-and-persistence/SKILL.md +330 -0
- package/templates/warlock/skills/git-workflow/SKILL.md +282 -0
- package/templates/warlock/skills/module-boundaries/SKILL.md +283 -0
- package/templates/warlock/skills/observability-and-resilience/SKILL.md +306 -0
- package/templates/warlock/skills/security-baseline/SKILL.md +352 -0
- package/templates/warlock/skills/testing-strategy/SKILL.md +323 -0
- package/templates/warlock/src/app/auth/controllers/forgot-password.controller.ts +28 -0
- package/templates/warlock/src/app/auth/controllers/login.controller.ts +22 -0
- package/templates/warlock/src/app/auth/controllers/logout-all.controller.ts +16 -0
- package/templates/warlock/src/app/auth/controllers/logout.controller.ts +16 -0
- package/templates/warlock/src/app/auth/controllers/me.controller.ts +13 -0
- package/templates/warlock/src/app/auth/controllers/refresh-token.controller.ts +29 -0
- package/templates/warlock/src/app/auth/controllers/reset-password.controller.ts +23 -0
- package/templates/warlock/src/app/auth/main.ts +9 -0
- package/templates/warlock/src/app/auth/models/otp/index.ts +1 -0
- package/templates/warlock/src/app/auth/models/otp/migrations/22-12-2025_10-30-20.otp-migration.ts +30 -0
- package/templates/warlock/src/app/auth/models/otp/otp.model.ts +69 -0
- package/templates/warlock/src/app/auth/requests/guarded.request.ts +10 -0
- package/templates/warlock/src/app/auth/routes.ts +22 -0
- package/templates/warlock/src/app/auth/schema/login.schema.ts +8 -0
- package/templates/warlock/src/app/auth/schema/reset-password.schema.ts +9 -0
- package/templates/warlock/src/app/auth/services/auth.service.ts +66 -0
- package/templates/warlock/src/app/auth/services/forgot-password.service.ts +28 -0
- package/templates/warlock/src/app/auth/services/otp.service.ts +173 -0
- package/templates/warlock/src/app/auth/services/reset-password.service.ts +39 -0
- package/templates/warlock/src/app/auth/utils/auth-error-code.ts +6 -0
- package/templates/warlock/src/app/auth/utils/locales.ts +89 -0
- package/templates/warlock/src/app/auth/utils/types.ts +14 -0
- package/templates/warlock/src/app/posts/controllers/create-new-post.controller.ts +21 -0
- package/templates/warlock/src/app/posts/controllers/update-post.controller.ts +30 -0
- package/templates/warlock/src/app/posts/models/post/migrations/09-01-2026_02-07-51-post.migration.ts +15 -0
- package/templates/warlock/src/app/posts/models/post/post.model.ts +23 -0
- package/templates/warlock/src/app/posts/resources/post.resource.ts +14 -0
- package/templates/warlock/src/app/posts/routes.ts +8 -0
- package/templates/warlock/src/app/posts/schema/create-post.schema.ts +9 -0
- package/templates/warlock/src/app/posts/schema/update-post.schema.ts +9 -0
- package/templates/warlock/src/app/shared/components/HomePageComponent.tsx +229 -0
- package/templates/warlock/src/app/shared/controllers/home-page.controller.ts +18 -0
- package/templates/warlock/src/app/shared/controllers/home-page.controller.tsx +8 -0
- package/templates/warlock/src/app/shared/routes.ts +4 -0
- package/templates/warlock/src/app/shared/services/scheduler.service.ts +3 -0
- package/templates/warlock/src/app/shared/tests/infrastructure.test.ts +22 -0
- package/templates/warlock/src/app/shared/utils/global-columns-schema.ts +8 -0
- package/templates/warlock/src/app/shared/utils/locales.ts +766 -0
- package/templates/warlock/src/app/shared/utils/router.ts +30 -0
- package/templates/warlock/src/app/uploads/controllers/fetch-uploaded-file.controller.ts +33 -0
- package/templates/warlock/src/app/uploads/routes.ts +4 -0
- package/templates/warlock/src/app/users/commands/hello-world.command.ts +8 -0
- package/templates/warlock/src/app/users/controllers/create-new-user.controller.ts +27 -0
- package/templates/warlock/src/app/users/controllers/list-users.controller.ts +12 -0
- package/templates/warlock/src/app/users/events/inject-created-by-user.into-model.event.ts +32 -0
- package/templates/warlock/src/app/users/events/sync.ts +5 -0
- package/templates/warlock/src/app/users/main.ts +5 -0
- package/templates/warlock/src/app/users/models/user/index.ts +1 -0
- package/templates/warlock/src/app/users/models/user/migrations/11-12-2025_23-58-03-user.migration.ts +15 -0
- package/templates/warlock/src/app/users/models/user/user.model.ts +64 -0
- package/templates/warlock/src/app/users/repositories/users.repository.ts +23 -0
- package/templates/warlock/src/app/users/resources/user.resource.ts +14 -0
- package/templates/warlock/src/app/users/routes.ts +8 -0
- package/templates/warlock/src/app/users/schema/create-user.schema.ts +11 -0
- package/templates/warlock/src/app/users/seeds/users.seed.ts +21 -0
- package/templates/warlock/src/app/users/services/get-users.service.ts +5 -0
- package/templates/warlock/src/app/users/services/list-users.service.ts +17 -0
- package/templates/warlock/src/app/users/services/login-social.ts +19 -0
- package/templates/warlock/src/config/app.ts +12 -0
- package/templates/warlock/src/config/auth.ts +20 -0
- package/templates/warlock/src/config/cache.ts +59 -0
- package/templates/warlock/src/config/database.ts +65 -0
- package/templates/warlock/src/config/http.ts +23 -0
- package/templates/warlock/src/config/log.ts +22 -0
- package/templates/warlock/src/config/mail.ts +16 -0
- package/templates/warlock/src/config/repository.ts +11 -0
- package/templates/warlock/src/config/storage.ts +34 -0
- package/templates/warlock/src/config/tests.ts +5 -0
- package/templates/warlock/src/config/validation.ts +7 -0
- package/templates/warlock/storage/.gitignore +2 -0
- package/templates/warlock/tsconfig.json +27 -0
- package/templates/warlock/warlock.config.ts +15 -0
- package/templates/warlock/yarn.lock +2332 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { authMiddleware } from "@warlock.js/auth";
|
|
2
|
+
import { router } from "@warlock.js/core";
|
|
3
|
+
|
|
4
|
+
export function publicRoutes(callback: () => void) {
|
|
5
|
+
router.group(
|
|
6
|
+
{
|
|
7
|
+
prefix: "/",
|
|
8
|
+
},
|
|
9
|
+
callback,
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function guardedAdmin(callback: () => void) {
|
|
14
|
+
router.group(
|
|
15
|
+
{
|
|
16
|
+
prefix: "/admin",
|
|
17
|
+
middleware: [authMiddleware([])],
|
|
18
|
+
},
|
|
19
|
+
callback,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function guarded(callback: () => void) {
|
|
24
|
+
router.group(
|
|
25
|
+
{
|
|
26
|
+
middleware: [authMiddleware("user")],
|
|
27
|
+
},
|
|
28
|
+
callback,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CACHE_FOR } from "@warlock.js/cache";
|
|
2
|
+
import { Image, type RequestHandler, storage } from "@warlock.js/core";
|
|
3
|
+
import { fileExistsAsync } from "@warlock.js/fs";
|
|
4
|
+
import { v } from "@warlock.js/seal";
|
|
5
|
+
|
|
6
|
+
export const fetchUploadedFileController: RequestHandler = async (request, response) => {
|
|
7
|
+
const absolutePath = storage.root(request.input("*"));
|
|
8
|
+
|
|
9
|
+
const { w: width, h: height } = request.validated();
|
|
10
|
+
|
|
11
|
+
if (!(await fileExistsAsync(absolutePath))) {
|
|
12
|
+
return response.notFound();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (width || height) {
|
|
16
|
+
const image = new Image(absolutePath);
|
|
17
|
+
image.resize({
|
|
18
|
+
width,
|
|
19
|
+
height,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return response.sendImage(image, CACHE_FOR.ONE_DAY);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return response.sendFile(absolutePath, CACHE_FOR.ONE_YEAR);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
fetchUploadedFileController.validation = {
|
|
29
|
+
schema: v.object({
|
|
30
|
+
w: v.numeric().min(1),
|
|
31
|
+
h: v.numeric().min(1),
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type GuardedRequestHandler } from "app/auth/requests/guarded.request";
|
|
2
|
+
import { User } from "../models/user";
|
|
3
|
+
import { type CreateUserSchema, createUserSchema } from "../schema/create-user.schema";
|
|
4
|
+
|
|
5
|
+
export const createNewUserController: GuardedRequestHandler<CreateUserSchema> = async (
|
|
6
|
+
request,
|
|
7
|
+
response,
|
|
8
|
+
) => {
|
|
9
|
+
const file = request.file("image")!;
|
|
10
|
+
|
|
11
|
+
const output = await file.save("images");
|
|
12
|
+
|
|
13
|
+
const user = await User.create({
|
|
14
|
+
...request.validated(["name", "email", "password"]),
|
|
15
|
+
image: output.path,
|
|
16
|
+
imageMetadata: await file.metadata(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return response.successCreate({
|
|
20
|
+
message: "File uploaded successfully",
|
|
21
|
+
user,
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
createNewUserController.validation = {
|
|
26
|
+
schema: createUserSchema,
|
|
27
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type GuardedRequestHandler } from "app/auth/requests/guarded.request";
|
|
2
|
+
import { usersRepository } from "../repositories/users.repository";
|
|
3
|
+
|
|
4
|
+
export const listUsersController: GuardedRequestHandler = async (request, response) => {
|
|
5
|
+
const users = await usersRepository.listCached(request.all());
|
|
6
|
+
|
|
7
|
+
return response.success({
|
|
8
|
+
users,
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
listUsersController.description = "List Users Controller";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Model } from "@warlock.js/cascade";
|
|
2
|
+
import { useCurrentUser } from "@warlock.js/core";
|
|
3
|
+
|
|
4
|
+
const globalEvents = Model.globalEvents();
|
|
5
|
+
|
|
6
|
+
const saveSubscription = globalEvents.onSaving(async (model, { isInsert }) => {
|
|
7
|
+
const user = useCurrentUser();
|
|
8
|
+
|
|
9
|
+
if (!user) return;
|
|
10
|
+
|
|
11
|
+
if (isInsert) {
|
|
12
|
+
if (model.schemaHas("createdBy")) {
|
|
13
|
+
model.set("createdBy", user);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (model.schemaHas("updatedBy")) {
|
|
18
|
+
model.set("updatedBy", user);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const deleteSubscription = globalEvents.onDeleting(async (model) => {
|
|
23
|
+
const user = useCurrentUser();
|
|
24
|
+
|
|
25
|
+
if (!user) return;
|
|
26
|
+
|
|
27
|
+
if (model.schemaHas("deletedBy")) {
|
|
28
|
+
model.set("deletedBy", user);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const cleanup = [saveSubscription, deleteSubscription];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./user.model";
|
package/templates/warlock/src/app/users/models/user/migrations/11-12-2025_23-58-03-user.migration.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { bool, json, Migration, string, timestamp } from "@warlock.js/cascade";
|
|
2
|
+
import { User } from "../user.model";
|
|
3
|
+
|
|
4
|
+
export default Migration.create(User, {
|
|
5
|
+
name: string(255),
|
|
6
|
+
email: string(255).unique(),
|
|
7
|
+
password: string(255),
|
|
8
|
+
image: string(500).nullable(),
|
|
9
|
+
imageMetadata: json().nullable(),
|
|
10
|
+
isActive: bool(),
|
|
11
|
+
createdBy: json().nullable(),
|
|
12
|
+
updatedBy: json().nullable(),
|
|
13
|
+
deletedBy: json().nullable(),
|
|
14
|
+
deletedAt: timestamp().nullable(),
|
|
15
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Auth } from "@warlock.js/auth";
|
|
2
|
+
import { RegisterModel } from "@warlock.js/cascade";
|
|
3
|
+
import { useHashedPassword } from "@warlock.js/core";
|
|
4
|
+
import { type Infer, v } from "@warlock.js/seal";
|
|
5
|
+
import { globalColumnsSchema } from "app/shared/utils/global-columns-schema";
|
|
6
|
+
import { UserResource } from "app/users/resources/user.resource";
|
|
7
|
+
|
|
8
|
+
export const userSchema = globalColumnsSchema.extend({
|
|
9
|
+
name: v.string().required(),
|
|
10
|
+
email: v.email().requiredIfEmpty("id"),
|
|
11
|
+
image: v.string(),
|
|
12
|
+
password: v.string().min(6).requiredIfEmpty("id").addTransformer(useHashedPassword()),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export type UserSchema = Infer<typeof userSchema>;
|
|
16
|
+
|
|
17
|
+
@RegisterModel()
|
|
18
|
+
export class User extends Auth<UserSchema> {
|
|
19
|
+
/**
|
|
20
|
+
* Collection name
|
|
21
|
+
*/
|
|
22
|
+
public static table = "users";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Model Schema
|
|
26
|
+
*/
|
|
27
|
+
public static schema = userSchema;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Embed fields when saving in another model
|
|
31
|
+
*/
|
|
32
|
+
public static embed = ["id", "name"];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resource to be used when converting the model to JSON
|
|
36
|
+
*/
|
|
37
|
+
public static resource = UserResource;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* User type identifier
|
|
41
|
+
*/
|
|
42
|
+
public get userType(): string {
|
|
43
|
+
return "user";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static {
|
|
47
|
+
// Local scopes
|
|
48
|
+
this.addScope("active", (query) => {
|
|
49
|
+
query.where("isActive", true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
this.addScope("admins", (query) => {
|
|
53
|
+
query.where("role", "admin");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.addScope("verified", (query) => {
|
|
57
|
+
query.where("emailVerified", true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// this.addGlobalScope("active", (query) => {
|
|
61
|
+
// query.where("isActive", true);
|
|
62
|
+
// });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { FilterRules, RepositoryOptions } from "@warlock.js/core";
|
|
2
|
+
import { RepositoryManager } from "@warlock.js/core";
|
|
3
|
+
import { User } from "../models/user";
|
|
4
|
+
|
|
5
|
+
export type UserFilter = {
|
|
6
|
+
email?: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type UsersListOptions = RepositoryOptions & UserFilter;
|
|
12
|
+
|
|
13
|
+
class UsersRepository extends RepositoryManager<User, UserFilter> {
|
|
14
|
+
public source = User;
|
|
15
|
+
|
|
16
|
+
public filterBy: FilterRules = {
|
|
17
|
+
id: "=",
|
|
18
|
+
name: "like",
|
|
19
|
+
email: "=",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const usersRepository = new UsersRepository();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineResource } from "@warlock.js/core";
|
|
2
|
+
|
|
3
|
+
export const UserResource = defineResource({
|
|
4
|
+
schema: {
|
|
5
|
+
id: "number",
|
|
6
|
+
name: "string",
|
|
7
|
+
email: "string",
|
|
8
|
+
image: "storageUrl",
|
|
9
|
+
createdAt: "date",
|
|
10
|
+
updatedAt: "date",
|
|
11
|
+
isActive: "boolean",
|
|
12
|
+
type: () => "user",
|
|
13
|
+
},
|
|
14
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { router } from "@warlock.js/core";
|
|
2
|
+
import { guarded } from "app/shared/utils/router";
|
|
3
|
+
import { createNewUserController } from "./controllers/create-new-user.controller";
|
|
4
|
+
import { listUsersController } from "./controllers/list-users.controller";
|
|
5
|
+
|
|
6
|
+
guarded(() => {
|
|
7
|
+
router.route("/users").list(listUsersController).post(createNewUserController);
|
|
8
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Infer, v } from "@warlock.js/seal";
|
|
2
|
+
import { User } from "../models/user";
|
|
3
|
+
|
|
4
|
+
export const createUserSchema = v.object({
|
|
5
|
+
name: v.string().required(),
|
|
6
|
+
email: v.email().required().unique(User),
|
|
7
|
+
password: v.string().min(6),
|
|
8
|
+
image: v.file().image().required().maxSize({ unit: "MB", size: 1.5 }),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export type CreateUserSchema = Infer<typeof createUserSchema>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Random } from "@mongez/reinforcements";
|
|
2
|
+
import { seeder } from "@warlock.js/core";
|
|
3
|
+
import { User } from "../models/user";
|
|
4
|
+
|
|
5
|
+
export default seeder({
|
|
6
|
+
name: "Seed Users",
|
|
7
|
+
once: true,
|
|
8
|
+
run: async () => {
|
|
9
|
+
for (let i = 0; i < 10; i++) {
|
|
10
|
+
await User.create({
|
|
11
|
+
name: `User ${Random.int()}`,
|
|
12
|
+
email: `user${Random.int()}@gmail.com`,
|
|
13
|
+
password: `password-${Random.int()}`,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
recordsCreated: 10,
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ResourceNotFoundError } from "@warlock.js/core";
|
|
2
|
+
import type { UsersListOptions } from "../repositories/users.repository";
|
|
3
|
+
import { usersRepository } from "../repositories/users.repository";
|
|
4
|
+
|
|
5
|
+
export async function listUsersService(filters: UsersListOptions = {}) {
|
|
6
|
+
return usersRepository.listActiveCached(filters);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function getFirstUserService(filters: UsersListOptions = {}) {
|
|
10
|
+
const user = await usersRepository.firstActiveCached(filters);
|
|
11
|
+
|
|
12
|
+
if (!user) {
|
|
13
|
+
throw new ResourceNotFoundError("No user found");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return user;
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Request, Response } from "@warlock.js/core";
|
|
2
|
+
|
|
3
|
+
export default async function loginSocial(request: Request, response: Response) {
|
|
4
|
+
const user = request.user;
|
|
5
|
+
|
|
6
|
+
const auth = await user.generateAccessToken();
|
|
7
|
+
|
|
8
|
+
user.save({
|
|
9
|
+
lastLogin: new Date(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return response.success({
|
|
13
|
+
user: {
|
|
14
|
+
...(await user.toJSON()),
|
|
15
|
+
accessToken: auth,
|
|
16
|
+
userType: user.userType,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AppConfigurations } from "@warlock.js/core";
|
|
2
|
+
import { env } from "@warlock.js/core";
|
|
3
|
+
|
|
4
|
+
const appConfigurations: AppConfigurations = {
|
|
5
|
+
appName: env("APP_NAME", "Mongez"),
|
|
6
|
+
timezone: env("TIMEZONE", "UTC"),
|
|
7
|
+
baseUrl: env("BASE_URL", "http://localhost:3000"),
|
|
8
|
+
localeCode: env("LOCALE_CODE", "en"),
|
|
9
|
+
localeCodes: ["en", "ar"],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default appConfigurations;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { NO_EXPIRATION, type AuthConfigurations } from "@warlock.js/auth";
|
|
2
|
+
import { env } from "@warlock.js/core";
|
|
3
|
+
import { User } from "app/users/models/user";
|
|
4
|
+
|
|
5
|
+
const authConfigurations: AuthConfigurations = {
|
|
6
|
+
userType: {
|
|
7
|
+
user: User,
|
|
8
|
+
},
|
|
9
|
+
jwt: {
|
|
10
|
+
secret: env("JWT_SECRET"),
|
|
11
|
+
expiresIn: NO_EXPIRATION,
|
|
12
|
+
refresh: {
|
|
13
|
+
expiresIn: "7d",
|
|
14
|
+
enabled: false,
|
|
15
|
+
secret: env("JWT_REFRESH_SECRET"),
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default authConfigurations;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FileCacheDriver,
|
|
3
|
+
MemoryCacheDriver,
|
|
4
|
+
MemoryExtendedCacheDriver,
|
|
5
|
+
RedisCacheDriver,
|
|
6
|
+
type CacheConfigurations,
|
|
7
|
+
} from "@warlock.js/cache";
|
|
8
|
+
import { DatabaseCacheDriver, env, useRequestStore } from "@warlock.js/core";
|
|
9
|
+
|
|
10
|
+
const globalPrefix = () => {
|
|
11
|
+
const { request } = useRequestStore();
|
|
12
|
+
|
|
13
|
+
let cachePrefix = "store";
|
|
14
|
+
|
|
15
|
+
if (!request) return cachePrefix;
|
|
16
|
+
|
|
17
|
+
if (request.client) {
|
|
18
|
+
cachePrefix = `${cachePrefix}.${request.client.get("username")}`;
|
|
19
|
+
|
|
20
|
+
return cachePrefix;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const domain = request.originDomain || request.header("domain") || request.input("domain");
|
|
24
|
+
|
|
25
|
+
if (!domain) return cachePrefix;
|
|
26
|
+
|
|
27
|
+
cachePrefix = `${cachePrefix}.${domain}`;
|
|
28
|
+
|
|
29
|
+
return cachePrefix;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const cacheConfigurations: CacheConfigurations<"database"> = {
|
|
33
|
+
default: "memoryExtended",
|
|
34
|
+
drivers: {
|
|
35
|
+
file: FileCacheDriver,
|
|
36
|
+
memory: MemoryCacheDriver,
|
|
37
|
+
redis: RedisCacheDriver,
|
|
38
|
+
memoryExtended: MemoryExtendedCacheDriver,
|
|
39
|
+
database: DatabaseCacheDriver,
|
|
40
|
+
},
|
|
41
|
+
options: {
|
|
42
|
+
redis: {
|
|
43
|
+
host: env("REDIS_HOST"),
|
|
44
|
+
port: env("REDIS_PORT"),
|
|
45
|
+
url: env("REDIS_URL"),
|
|
46
|
+
globalPrefix,
|
|
47
|
+
},
|
|
48
|
+
memory: {
|
|
49
|
+
globalPrefix,
|
|
50
|
+
ttl: 3 * 60 * 60, // 3 hours
|
|
51
|
+
},
|
|
52
|
+
memoryExtended: {
|
|
53
|
+
globalPrefix,
|
|
54
|
+
ttl: 30 * 60, // 30 minutes
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default cacheConfigurations;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConnectionOptions,
|
|
3
|
+
MongoClientOptions,
|
|
4
|
+
MongoDriverOptions,
|
|
5
|
+
} from "@warlock.js/cascade";
|
|
6
|
+
import { env } from "@warlock.js/core";
|
|
7
|
+
|
|
8
|
+
const databaseConfigurations: ConnectionOptions<MongoDriverOptions, MongoClientOptions> = {
|
|
9
|
+
driver: env("DB_DRIVER", "mongodb"),
|
|
10
|
+
name: "default",
|
|
11
|
+
database: env("DB_NAME"),
|
|
12
|
+
host: env("DB_HOST", "localhost"),
|
|
13
|
+
port: env("DB_PORT", 27017),
|
|
14
|
+
username: env("DB_USERNAME"),
|
|
15
|
+
password: env("DB_PASSWORD"),
|
|
16
|
+
authSource: env("DB_AUTH"),
|
|
17
|
+
uri: env("DB_URL"),
|
|
18
|
+
|
|
19
|
+
driverOptions: {
|
|
20
|
+
autoGenerateId: true,
|
|
21
|
+
counterCollection: "counters",
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
defaultDeleteStrategy: "permanent",
|
|
25
|
+
|
|
26
|
+
clientOptions: {
|
|
27
|
+
replicaSet: env("DB_REPLICA_SET"),
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Model Defaults Configuration
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// These settings override driver defaults and apply to all models.
|
|
34
|
+
// Individual models can override these by setting static properties.
|
|
35
|
+
//
|
|
36
|
+
// Configuration hierarchy (highest to lowest):
|
|
37
|
+
// 1. Model static property (e.g., User.createdAtColumn = "creation_date")
|
|
38
|
+
// 2. modelOptions (below) - Database-wide overrides
|
|
39
|
+
// 3. Driver defaults (PostgreSQL: snake_case, MongoDB: camelCase)
|
|
40
|
+
// 4. Framework defaults
|
|
41
|
+
// ============================================================================
|
|
42
|
+
modelOptions: {
|
|
43
|
+
// ID Generation (for MongoDB)
|
|
44
|
+
randomIncrement: true,
|
|
45
|
+
initialId: 1,
|
|
46
|
+
|
|
47
|
+
// Timestamps - PostgreSQL driver already defaults to snake_case
|
|
48
|
+
// (created_at, updated_at) so these are optional unless overriding
|
|
49
|
+
timestamps: true,
|
|
50
|
+
// createdAtColumn: "created_at", // Already driver default
|
|
51
|
+
// updatedAtColumn: "updated_at", // Already driver default
|
|
52
|
+
|
|
53
|
+
// Deletion Strategy
|
|
54
|
+
// deleteStrategy: "soft", // Uncomment to enable soft deletes globally
|
|
55
|
+
// deletedAtColumn: "deleted_at", // Already driver default
|
|
56
|
+
|
|
57
|
+
// Validation
|
|
58
|
+
strictMode: "strip",
|
|
59
|
+
|
|
60
|
+
// Naming Convention
|
|
61
|
+
// namingConvention: "snake_case", // Already driver default for PostgreSQL
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default databaseConfigurations;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HttpConfigurations } from "@warlock.js/core";
|
|
2
|
+
import { env } from "@warlock.js/core";
|
|
3
|
+
|
|
4
|
+
const httpConfigurations: HttpConfigurations = {
|
|
5
|
+
port: env("HTTP_PORT", 3000),
|
|
6
|
+
host: env("HTTP_HOST", "localhost"),
|
|
7
|
+
log: true,
|
|
8
|
+
fileUploadLimit: 12 * 1024 * 1024 * 1024,
|
|
9
|
+
rateLimit: {
|
|
10
|
+
max: 260,
|
|
11
|
+
duration: 60 * 1000, // 1 minute
|
|
12
|
+
},
|
|
13
|
+
cors: {
|
|
14
|
+
// allowed origins
|
|
15
|
+
// origin: ["127.0.0.1:5173", "localhost:5173"],
|
|
16
|
+
// origin: ["http://127.0.0.1:5173"],
|
|
17
|
+
origin: "*",
|
|
18
|
+
// allowed methods
|
|
19
|
+
methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default httpConfigurations;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type LogConfigurations } from "@warlock.js/core";
|
|
2
|
+
import { ConsoleLog } from "@warlock.js/logger";
|
|
3
|
+
|
|
4
|
+
const consoleLog = new ConsoleLog();
|
|
5
|
+
|
|
6
|
+
const logConfigurations: LogConfigurations = {
|
|
7
|
+
enabled: true,
|
|
8
|
+
development: {
|
|
9
|
+
channels: [consoleLog],
|
|
10
|
+
// channels: [consoleLog],
|
|
11
|
+
// channels: [],
|
|
12
|
+
},
|
|
13
|
+
test: {
|
|
14
|
+
// channels: [consoleLog],
|
|
15
|
+
channels: [consoleLog],
|
|
16
|
+
},
|
|
17
|
+
production: {
|
|
18
|
+
channels: [consoleLog],
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default logConfigurations;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MailConfigurations } from "@warlock.js/core";
|
|
2
|
+
import { env } from "@warlock.js/core";
|
|
3
|
+
|
|
4
|
+
const mailConfigurations: MailConfigurations = {
|
|
5
|
+
host: env("MAIL_HOST"),
|
|
6
|
+
username: env("MAIL_USERNAME"),
|
|
7
|
+
password: env("MAIL_PASSWORD"),
|
|
8
|
+
port: env("MAIL_PORT"),
|
|
9
|
+
secure: env("MAIL_SECURE"),
|
|
10
|
+
from: {
|
|
11
|
+
name: env("MAIL_FROM_NAME"),
|
|
12
|
+
address: env("MAIL_FROM_ADDRESS"),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default mailConfigurations;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
env,
|
|
3
|
+
type StorageConfigurations,
|
|
4
|
+
storageConfigurations,
|
|
5
|
+
uploadsPath,
|
|
6
|
+
} from "@warlock.js/core";
|
|
7
|
+
|
|
8
|
+
const storageOptions: StorageConfigurations = {
|
|
9
|
+
default: "local",
|
|
10
|
+
drivers: {
|
|
11
|
+
local: storageConfigurations.local({
|
|
12
|
+
root: uploadsPath(),
|
|
13
|
+
urlPrefix: "/uploads",
|
|
14
|
+
}),
|
|
15
|
+
aws: storageConfigurations.aws({
|
|
16
|
+
accessKeyId: env("AWS_ACCESS_KEY_ID"),
|
|
17
|
+
secretAccessKey: env("AWS_SECRET_ACCESS_KEY"),
|
|
18
|
+
region: env("AWS_REGION"),
|
|
19
|
+
bucket: env("AWS_BUCKET"),
|
|
20
|
+
}),
|
|
21
|
+
r2: storageConfigurations.r2({
|
|
22
|
+
bucket: env("R2_BUCKET"),
|
|
23
|
+
endpoint: env("R2_ENDPOINT"),
|
|
24
|
+
accessKeyId: env("R2_ACCESS_KEY_ID"),
|
|
25
|
+
secretAccessKey: env("R2_SECRET_ACCESS_KEY"),
|
|
26
|
+
accountId: env("R2_ACCOUNT_ID"),
|
|
27
|
+
region: env("R2_REGION", "auto"),
|
|
28
|
+
publicDomain: env("R2_BASE_URL"),
|
|
29
|
+
prefix: "warlock.js",
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default storageOptions;
|