1import { z } from "zod";
2import { BLOCK_TYPES } from "../../constants.js";
3
4
15const blockTypeSchema = z
16 .string()
17 .min(1)
18 .transform((t) => t.toUpperCase())
19 .pipe(z.enum(BLOCK_TYPES));
20
21
29const blockContentSchema = z.union([z.string(), z.record(z.unknown())]);
30
31export const CreateBlockDto = z.object({
32 type: blockTypeSchema,
33
34
35
36 content: blockContentSchema.default({}),
37 properties: z.record(z.unknown()).default({}),
38 parentId: z.string().min(1).nullable().optional(),
39 afterBlockId: z.string().min(1).optional(),
40 beforeBlockId: z.string().min(1).optional(),
41 position: z.string().min(1).optional(),
42
49 id: z.string().min(1).max(128).optional()
50});
51export type CreateBlockInput = z.infer<typeof CreateBlockDto>;
52
53export const DuplicateBlockDto = z.object({
54 parentId: z.string().min(1).nullable().optional(),
55 afterBlockId: z.string().min(1).optional()
56});
57export type DuplicateBlockInput = z.infer<typeof DuplicateBlockDto>;
58
59export const UpdateBlockDto = z.object({
60 type: blockTypeSchema.optional(),
61 content: blockContentSchema.optional(),
62 properties: z.record(z.unknown()).optional(),
63 archived: z.boolean().optional(),
64
70 baseVersion: z.number().int().positive().optional()
71});
72export type UpdateBlockInput = z.infer<typeof UpdateBlockDto>;
73
74export const MoveBlockDto = z.object({
75 parentId: z.string().min(1).nullable().optional(),
76 afterBlockId: z.string().min(1).optional(),
77 beforeBlockId: z.string().min(1).optional(),
78 position: z.string().min(1).optional()
79});
80export type MoveBlockInput = z.infer<typeof MoveBlockDto>;
81
82const BatchUpsertOp = z.object({
83 op: z.literal("upsert"),
84 block: CreateBlockDto
85});
86const BatchDeleteOp = z.object({
87 op: z.literal("delete"),
88 blockId: z.string().min(1)
89});
90const BatchMoveOp = z.object({
91 op: z.literal("move"),
92 blockId: z.string().min(1),
93 move: MoveBlockDto
94});
95
105const BatchUpdateOp = z.object({
106 op: z.literal("update"),
107 blockId: z.string().min(1),
108 patch: z
109 .object({
110 type: blockTypeSchema.optional(),
111 content: blockContentSchema.optional(),
112 properties: z.record(z.unknown()).optional(),
113 parentId: z.string().min(1).nullable().optional(),
114 position: z.string().min(1).optional()
115 })
116 .passthrough()
117});
118export const BatchBlocksDto = z.object({
119 pageId: z.string().min(1),
120
121
122
123
124
125
126 baseVersion: z.number().int().min(1).optional(),
127 ops: z.array(
128 z.discriminatedUnion("op", [BatchUpsertOp, BatchUpdateOp, BatchDeleteOp, BatchMoveOp])
129 ).min(1).max(200)
130});
131export type BatchBlocksInput = z.infer<typeof BatchBlocksDto>;
132
133export const ListBlocksQuery = z.object({
134 parentId: z.string().nullable().optional(),
135 depth: z.union([z.enum(["1", "all"]), z.coerce.number().int().min(1)]).optional()
136});
137export type ListBlocksInput = z.infer<typeof ListBlocksQuery>;
138