feat: modular domain driven boilerplate
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
import { ConflictError } from "@platform/relay";
|
||||
|
||||
export class AccountEmailClaimedError extends ConflictError {
|
||||
constructor(email: string) {
|
||||
super(`Email '${email}' is already claimed by another account.`);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import z from "zod";
|
||||
|
||||
export const RoleSchema = z.union([z.literal("user"), z.literal("admin")]);
|
||||
|
||||
export type Role = z.infer<typeof RoleSchema>;
|
||||
@@ -1,30 +0,0 @@
|
||||
import { AccountSchema } from "@platform/models/account.ts";
|
||||
import { NameSchema } from "@platform/models/value-objects/name.ts";
|
||||
import { ForbiddenError, NotFoundError, route, UnauthorizedError } from "@platform/relay";
|
||||
import z from "zod";
|
||||
|
||||
import { AccountEmailClaimedError } from "./errors.ts";
|
||||
|
||||
export const create = route
|
||||
.post("/api/v1/accounts")
|
||||
.body(
|
||||
z.object({
|
||||
name: NameSchema,
|
||||
email: z.email(),
|
||||
}),
|
||||
)
|
||||
.errors([AccountEmailClaimedError])
|
||||
.response(z.uuid());
|
||||
|
||||
export const getById = route
|
||||
.get("/api/v1/accounts/:id")
|
||||
.params({
|
||||
id: z.string(),
|
||||
})
|
||||
.errors([UnauthorizedError, ForbiddenError, NotFoundError])
|
||||
.response(AccountSchema);
|
||||
|
||||
export const routes = {
|
||||
create,
|
||||
getById,
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
import z from "zod";
|
||||
|
||||
const EmailStrategySchema = z.object({
|
||||
type: z.literal("email"),
|
||||
value: z.string(),
|
||||
});
|
||||
|
||||
const PasswordStrategySchema = z.object({
|
||||
type: z.literal("password"),
|
||||
alias: z.string(),
|
||||
password: z.string(),
|
||||
});
|
||||
|
||||
const PasskeyStrategySchema = z.object({
|
||||
type: z.literal("passkey"),
|
||||
credId: z.string(),
|
||||
credPublicKey: z.string(),
|
||||
webauthnUserId: z.string(),
|
||||
counter: z.number(),
|
||||
backupEligible: z.boolean(),
|
||||
backupStatus: z.boolean(),
|
||||
transports: z.string(),
|
||||
createdAt: z.date(),
|
||||
lastUsed: z.date(),
|
||||
});
|
||||
|
||||
export const StrategySchema = z.discriminatedUnion("type", [
|
||||
EmailStrategySchema,
|
||||
PasswordStrategySchema,
|
||||
PasskeyStrategySchema,
|
||||
]);
|
||||
|
||||
export type Strategy = z.infer<typeof StrategySchema>;
|
||||
17
platform/spec/audit/actor.ts
Normal file
17
platform/spec/audit/actor.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import z from "zod";
|
||||
|
||||
import { AuditUserSchema, AuditUserType } from "./user.ts";
|
||||
|
||||
export const AuditActorSchema = z.object({
|
||||
user: AuditUserSchema,
|
||||
});
|
||||
|
||||
export const auditors = {
|
||||
system: AuditActorSchema.parse({
|
||||
user: {
|
||||
typeId: AuditUserType.System,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export type AuditActor = z.infer<typeof AuditActorSchema>;
|
||||
17
platform/spec/audit/user.ts
Normal file
17
platform/spec/audit/user.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import z from "zod";
|
||||
|
||||
export enum AuditUserType {
|
||||
Unknown = 0,
|
||||
Identity = 1,
|
||||
System = 2,
|
||||
Service = 3,
|
||||
Other = 99,
|
||||
}
|
||||
|
||||
export const AuditUserSchema = z.object({
|
||||
typeId: z.enum(AuditUserType).describe("The account type identifier."),
|
||||
uid: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("The unique user identifier. For example, the Windows user SID, ActiveDirectory DN or AWS user ARN."),
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
import { AccountSchema } from "@platform/models/account.ts";
|
||||
import { route, UnauthorizedError } from "@platform/relay";
|
||||
import z from "zod";
|
||||
|
||||
export * from "./errors.ts";
|
||||
export * from "./strategies.ts";
|
||||
|
||||
export const email = route.post("/api/v1/auth/email").body(
|
||||
z.object({
|
||||
base: z.url(),
|
||||
email: z.email(),
|
||||
}),
|
||||
);
|
||||
|
||||
export const password = route.post("/api/v1/auth/password").body(
|
||||
z.object({
|
||||
alias: z.string(),
|
||||
password: z.string(),
|
||||
}),
|
||||
);
|
||||
|
||||
export const code = route
|
||||
.get("/api/v1/auth/code/:accountId/code/:codeId/:value")
|
||||
.params({
|
||||
accountId: z.string(),
|
||||
codeId: z.string(),
|
||||
value: z.string(),
|
||||
})
|
||||
.query({
|
||||
next: z.string().optional(),
|
||||
});
|
||||
|
||||
export const session = route.get("/api/v1/auth/session").response(AccountSchema).errors([UnauthorizedError]);
|
||||
|
||||
export const routes = {
|
||||
email,
|
||||
password,
|
||||
code,
|
||||
session,
|
||||
};
|
||||
@@ -6,6 +6,6 @@
|
||||
"dependencies": {
|
||||
"@platform/models": "workspace:*",
|
||||
"@platform/relay": "workspace:*",
|
||||
"zod": "4"
|
||||
"zod": "4.1.11"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user