Merge redesign/ui-v2 into main: full v2 rewrite (Vite SPA + Hono API + Bun worker)
Resolved conflicts in web-legacy pages and report schema by taking v2 side. v2 is the deployed, current architecture; v1 paths preserved under apps/web-legacy.
This commit is contained in:
@@ -5,7 +5,8 @@
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./schema": "./src/schema.ts"
|
||||
"./schema": "./src/schema.ts",
|
||||
"./client": "./src/client.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"drizzle-orm": "^0.45.1",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { drizzle } from "drizzle-orm/postgres-js";
|
||||
import postgres from "postgres";
|
||||
import * as schema from "./schema";
|
||||
|
||||
const databaseUrl = process.env.DATABASE_URL;
|
||||
|
||||
if (!databaseUrl) {
|
||||
throw new Error("DATABASE_URL is required.");
|
||||
}
|
||||
|
||||
export const sql = postgres(databaseUrl, { max: 10 });
|
||||
export const db = drizzle(sql, { schema });
|
||||
export { schema };
|
||||
@@ -57,6 +57,7 @@ export const domains = pgTable(
|
||||
slug: text('slug').notNull().unique(),
|
||||
color: text('color'),
|
||||
icon: text('icon'),
|
||||
ownerId: uuid('owner_id').references(() => users.id, { onDelete: 'cascade' }),
|
||||
parentId: uuid('parent_id').references((): any => domains.id, { onDelete: 'set null' }),
|
||||
sortOrder: integer('sort_order').default(0),
|
||||
customFields: jsonb('custom_fields').$type<Record<string, unknown>>().default({}),
|
||||
@@ -553,3 +554,280 @@ export const apiKeys = pgTable(
|
||||
index('api_keys_active_idx').on(table.active),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Agents ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const agents = pgTable(
|
||||
'agents',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
name: text('name').notNull(),
|
||||
description: text('description'),
|
||||
status: text('status').notNull().default('active'),
|
||||
permissionTier: text('permission_tier').notNull().default('read_only'),
|
||||
customPermissions: text('custom_permissions').array().default([]),
|
||||
apiKey: text('api_key'),
|
||||
lastActiveAt: timestamp('last_active_at', { withTimezone: true }),
|
||||
domainId: uuid('domain_id')
|
||||
.notNull()
|
||||
.references((): any => domains.id, { onDelete: 'cascade' }),
|
||||
tags: text('tags').array().default([]),
|
||||
config: jsonb('config').$type<Record<string, unknown>>().default({}),
|
||||
customFields: jsonb('custom_fields').$type<Record<string, unknown>>().default({}),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('agents_domain_id_idx').on(table.domainId),
|
||||
index('agents_status_idx').on(table.status),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Agent Activity ──────────────────────────────────────────────────────────────
|
||||
|
||||
export const agentActivity = pgTable(
|
||||
'agent_activity',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
agentId: uuid('agent_id')
|
||||
.notNull()
|
||||
.references((): any => agents.id, { onDelete: 'cascade' }),
|
||||
action: text('action').notNull(),
|
||||
entityType: text('entity_type'),
|
||||
entityId: uuid('entity_id'),
|
||||
details: jsonb('details').$type<Record<string, unknown>>().default({}),
|
||||
success: boolean('success').default(true),
|
||||
errorMessage: text('error_message'),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('agent_activity_agent_id_idx').on(table.agentId),
|
||||
index('agent_activity_created_at_idx').on(table.createdAt),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Agent Tasks ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export const agentTasks = pgTable(
|
||||
'agent_tasks',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
agentId: uuid('agent_id')
|
||||
.notNull()
|
||||
.references((): any => agents.id, { onDelete: 'cascade' }),
|
||||
taskType: text('task_type').notNull(),
|
||||
input: jsonb('input').$type<Record<string, unknown>>().default({}),
|
||||
status: text('status').notNull().default('pending'),
|
||||
output: jsonb('output').$type<Record<string, unknown>>(),
|
||||
errorMessage: text('error_message'),
|
||||
startedAt: timestamp('started_at', { withTimezone: true }),
|
||||
completedAt: timestamp('completed_at', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('agent_tasks_agent_id_idx').on(table.agentId),
|
||||
index('agent_tasks_status_idx').on(table.status),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Canvases ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const canvases = pgTable(
|
||||
'canvases',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
name: text('name').notNull(),
|
||||
description: text('description'),
|
||||
mode: text('mode').notNull().default('freeform'),
|
||||
domainId: uuid('domain_id')
|
||||
.notNull()
|
||||
.references((): any => domains.id, { onDelete: 'cascade' }),
|
||||
tags: text('tags').array().default([]),
|
||||
viewport: jsonb('viewport').$type<{ x: number; y: number; zoom: number }>().default({ x: 0, y: 0, zoom: 1 }),
|
||||
background: text('background'),
|
||||
customFields: jsonb('custom_fields').$type<Record<string, unknown>>().default({}),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('canvases_domain_id_idx').on(table.domainId),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Canvas Cards ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export const canvasCards = pgTable(
|
||||
'canvas_cards',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
canvasId: uuid('canvas_id')
|
||||
.notNull()
|
||||
.references((): any => canvases.id, { onDelete: 'cascade' }),
|
||||
type: text('type').notNull().default('note'),
|
||||
entityId: uuid('entity_id'),
|
||||
title: text('title'),
|
||||
content: text('content'),
|
||||
x: integer('x').default(0),
|
||||
y: integer('y').default(0),
|
||||
width: integer('width').default(200),
|
||||
height: integer('height').default(150),
|
||||
rotation: integer('rotation').default(0),
|
||||
color: text('color'),
|
||||
zIndex: integer('z_index').default(0),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('canvas_cards_canvas_id_idx').on(table.canvasId),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Canvas Connections ───────────────────────────────────────────────────────────
|
||||
|
||||
export const canvasConnections = pgTable(
|
||||
'canvas_connections',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
canvasId: uuid('canvas_id')
|
||||
.notNull()
|
||||
.references((): any => canvases.id, { onDelete: 'cascade' }),
|
||||
sourceCardId: uuid('source_card_id')
|
||||
.notNull()
|
||||
.references((): any => canvasCards.id, { onDelete: 'cascade' }),
|
||||
targetCardId: uuid('target_card_id')
|
||||
.notNull()
|
||||
.references((): any => canvasCards.id, { onDelete: 'cascade' }),
|
||||
label: text('label'),
|
||||
style: text('style').notNull().default('solid'),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('canvas_connections_canvas_id_idx').on(table.canvasId),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Calendar Events ──────────────────────────────────────────────────────────────
|
||||
|
||||
export const calendarEvents = pgTable(
|
||||
'calendar_events',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
title: text('title').notNull(),
|
||||
description: text('description'),
|
||||
startTime: timestamp('start_time', { withTimezone: true }).notNull(),
|
||||
endTime: timestamp('end_time', { withTimezone: true }),
|
||||
allDay: boolean('all_day').default(false),
|
||||
color: text('color'),
|
||||
domainId: uuid('domain_id')
|
||||
.notNull()
|
||||
.references((): any => domains.id, { onDelete: 'cascade' }),
|
||||
entityType: text('entity_type'),
|
||||
entityId: uuid('entity_id'),
|
||||
recurrenceRule: text('recurrence_rule'),
|
||||
customFields: jsonb('custom_fields').$type<Record<string, unknown>>().default({}),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('calendar_events_domain_id_idx').on(table.domainId),
|
||||
index('calendar_events_start_time_idx').on(table.startTime),
|
||||
index('calendar_events_end_time_idx').on(table.endTime),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Dashboard Widgets ────────────────────────────────────────────────────────────
|
||||
|
||||
export const dashboardWidgets = pgTable(
|
||||
'dashboard_widgets',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
userId: uuid('user_id')
|
||||
.notNull()
|
||||
.references((): any => users.id, { onDelete: 'cascade' }),
|
||||
type: text('type').notNull(),
|
||||
title: text('title'),
|
||||
config: jsonb('config').$type<Record<string, unknown>>().default({}),
|
||||
layout: jsonb('layout').$type<{ x: number; y: number; w: number; h: number }>().default({ x: 0, y: 0, w: 2, h: 2 }),
|
||||
domainId: uuid('domain_id')
|
||||
.notNull()
|
||||
.references((): any => domains.id, { onDelete: 'cascade' }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('dashboard_widgets_user_id_idx').on(table.userId),
|
||||
index('dashboard_widgets_domain_id_idx').on(table.domainId),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Daily Notes ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export const dailyNotes = pgTable(
|
||||
'daily_notes',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
date: timestamp('date', { withTimezone: true }).notNull(),
|
||||
content: text('content'),
|
||||
domainId: uuid('domain_id')
|
||||
.notNull()
|
||||
.references((): any => domains.id, { onDelete: 'cascade' }),
|
||||
mood: integer('mood'),
|
||||
energy: integer('energy'),
|
||||
customFields: jsonb('custom_fields').$type<Record<string, unknown>>().default({}),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('daily_notes_domain_id_idx').on(table.domainId),
|
||||
index('daily_notes_date_idx').on(table.date),
|
||||
uniqueIndex('daily_notes_date_domain_idx').on(table.date, table.domainId),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Custom Fields ────────────────────────────────────────────────────────────────
|
||||
|
||||
export const customFields = pgTable(
|
||||
'custom_fields',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
name: text('name').notNull(),
|
||||
type: text('type').notNull().default('text'),
|
||||
entityType: text('entity_type').notNull(),
|
||||
domainId: uuid('domain_id')
|
||||
.notNull()
|
||||
.references((): any => domains.id, { onDelete: 'cascade' }),
|
||||
required: boolean('required').default(false),
|
||||
options: jsonb('options').$type<string[]>().default([]),
|
||||
defaultValue: jsonb('default_value'),
|
||||
sortOrder: integer('sort_order').default(0),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('custom_fields_domain_id_idx').on(table.domainId),
|
||||
index('custom_fields_entity_type_idx').on(table.entityType),
|
||||
]
|
||||
);
|
||||
|
||||
// ── Error Logs ───────────────────────────────────────────────────────────────────
|
||||
|
||||
export const errorLogs = pgTable(
|
||||
'error_logs',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
level: text('level').notNull().default('error'),
|
||||
source: text('source').notNull(),
|
||||
message: text('message').notNull(),
|
||||
stackTrace: text('stack_trace'),
|
||||
metadata: jsonb('metadata').$type<Record<string, unknown>>().default({}),
|
||||
resolved: boolean('resolved').default(false),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('error_logs_level_idx').on(table.level),
|
||||
index('error_logs_created_at_idx').on(table.createdAt),
|
||||
index('error_logs_resolved_idx').on(table.resolved),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -36,9 +36,9 @@ export const agentTaskSchema = z.object({
|
||||
id: z.string(),
|
||||
agent_id: z.string(),
|
||||
task_type: z.string(),
|
||||
input: z.record(z.unknown()),
|
||||
input: z.record(z.string(), z.unknown()),
|
||||
status: z.enum(['pending', 'running', 'completed', 'failed']).default('pending'),
|
||||
output: z.record(z.unknown()).optional(),
|
||||
output: z.record(z.string(), z.unknown()).optional(),
|
||||
error_message: z.string().optional(),
|
||||
started_at: z.string().datetime().optional(),
|
||||
completed_at: z.string().datetime().optional(),
|
||||
@@ -70,8 +70,8 @@ export const agentSchema = z.object({
|
||||
last_active_at: z.string().datetime().optional(),
|
||||
domain: z.string(),
|
||||
tags: z.array(z.string()).default([]),
|
||||
config: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
config: z.record(z.string(), z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@ export const canvasSchema = z.object({
|
||||
zoom: z.number().positive().default(1),
|
||||
}).optional(),
|
||||
background: z.string().optional(),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
@@ -110,7 +110,7 @@ export const errorLogSchema = z.object({
|
||||
source: z.string(),
|
||||
message: z.string(),
|
||||
stack_trace: z.string().optional(),
|
||||
metadata: z.record(z.unknown()).optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
resolved: z.boolean().default(false),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
@@ -134,11 +134,11 @@ export const queueJobSchema = z.object({
|
||||
id: z.string(),
|
||||
queue: z.string(),
|
||||
type: z.string(),
|
||||
payload: z.record(z.unknown()),
|
||||
payload: z.record(z.string(), z.unknown()),
|
||||
status: queueJobStatusEnum.default('pending'),
|
||||
attempts: z.number().int().nonnegative().default(0),
|
||||
max_attempts: z.number().int().positive().default(3),
|
||||
result: z.record(z.unknown()).optional(),
|
||||
result: z.record(z.string(), z.unknown()).optional(),
|
||||
error_message: z.string().optional(),
|
||||
scheduled_at: z.string().datetime().optional(),
|
||||
started_at: z.string().datetime().optional(),
|
||||
|
||||
@@ -62,7 +62,7 @@ export const habitSchema = z.object({
|
||||
score_config: habitScoreConfigSchema.optional(),
|
||||
active: z.boolean().default(true),
|
||||
tags: z.array(z.string()).default([]),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ export const milestoneSchema = z.object({
|
||||
completed_at: z.string().datetime().optional(),
|
||||
tasks: z.array(z.string()).default([]),
|
||||
dependencies: z.array(milestoneDependencySchema).default([]),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ export const noteSchema = z.object({
|
||||
size: z.number(),
|
||||
url: z.string(),
|
||||
})).default([]),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ export const projectSettingsSchema = z.object({
|
||||
pomodoro_focus_minutes: z.number().int().positive().default(25),
|
||||
pomodoro_break_minutes: z.number().int().positive().default(5),
|
||||
notifications_enabled: z.boolean().default(true),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
});
|
||||
|
||||
// ── Project Schema ───────────────────────────────────────────────────────────
|
||||
@@ -33,7 +33,7 @@ export const projectSchema = z.object({
|
||||
target_date: z.string().datetime().optional(),
|
||||
completed_at: z.string().datetime().optional(),
|
||||
settings: projectSettingsSchema.optional(),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ export const reportTemplateSchema = z.object({
|
||||
sections: z.array(z.object({
|
||||
title: z.string(),
|
||||
type: z.enum(['summary', 'chart', 'table', 'list', 'text']).default('text'),
|
||||
config: z.record(z.unknown()).optional(),
|
||||
config: z.record(z.string(), z.unknown()).optional(),
|
||||
sort_order: z.number().int().nonnegative().default(0),
|
||||
})).default([]),
|
||||
created: z.string().datetime(),
|
||||
@@ -27,24 +27,36 @@ export const createReportTemplateSchema = reportTemplateSchema.omit({
|
||||
updated: true,
|
||||
});
|
||||
|
||||
// ── Report Schema (matches frontend field names) ────────────────────────────
|
||||
// ── Report Schema ────────────────────────────────────────────────────────────
|
||||
|
||||
export const reportSchema = z.object({
|
||||
id: z.string(),
|
||||
title: z.string().min(1, 'Report title is required').default('Untitled report'),
|
||||
content: z.string().optional().default(''),
|
||||
report_type: reportTypeEnum.default('custom'),
|
||||
date_range_start: z.string().datetime().optional(),
|
||||
date_range_end: z.string().datetime().optional(),
|
||||
domain: z.string().default('personal'),
|
||||
project_id: z.string().optional(),
|
||||
title: z.string().min(1, 'Report title is required'),
|
||||
type: reportTypeEnum,
|
||||
template_id: z.string().optional(),
|
||||
domain: z.string(),
|
||||
date_range: z.object({
|
||||
start: z.string().datetime(),
|
||||
end: z.string().datetime(),
|
||||
}),
|
||||
sections: z.array(z.object({
|
||||
title: z.string(),
|
||||
content: z.string().optional(),
|
||||
data: z.record(z.string(), z.unknown()).optional(),
|
||||
sort_order: z.number().int().nonnegative().default(0),
|
||||
})).default([]),
|
||||
summary: z.string().optional(),
|
||||
is_draft: z.boolean().default(true),
|
||||
generated_at: z.string().datetime().optional(),
|
||||
tags: z.array(z.string()).default([]),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
export const createReportSchema = reportSchema.omit({
|
||||
id: true,
|
||||
generated_at: true,
|
||||
created: true,
|
||||
updated: true,
|
||||
});
|
||||
@@ -57,4 +69,4 @@ export type Report = z.infer<typeof reportSchema>;
|
||||
export type CreateReport = z.infer<typeof createReportSchema>;
|
||||
export type UpdateReport = z.infer<typeof updateReportSchema>;
|
||||
export type ReportTemplate = z.infer<typeof reportTemplateSchema>;
|
||||
export type CreateReportTemplate = z.infer<typeof createReportTemplateSchema>;
|
||||
export type CreateReportTemplate = z.infer<typeof createReportTemplateSchema>;
|
||||
|
||||
@@ -47,7 +47,7 @@ export const taskSchema = z.object({
|
||||
attachments: z.array(attachmentSchema).default([]),
|
||||
dependencies: z.array(z.string()).default([]),
|
||||
subtasks: z.array(subtaskSchema).default([]),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
completed_at: z.string().datetime().optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
|
||||
@@ -6,7 +6,7 @@ export const webhookDeliverySchema = z.object({
|
||||
id: z.string(),
|
||||
webhook_id: z.string(),
|
||||
event: z.string(),
|
||||
payload: z.record(z.unknown()),
|
||||
payload: z.record(z.string(), z.unknown()),
|
||||
status: z.enum(['success', 'failed', 'pending']).default('pending'),
|
||||
status_code: z.number().int().optional(),
|
||||
response_body: z.string().optional(),
|
||||
@@ -27,10 +27,10 @@ export const webhookSchema = z.object({
|
||||
secret: z.string().optional(),
|
||||
active: z.boolean().default(true),
|
||||
domain: z.string(),
|
||||
headers: z.record(z.string()).optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
retry_count: z.number().int().nonnegative().default(3),
|
||||
last_triggered_at: z.string().datetime().optional(),
|
||||
custom_fields: z.record(z.unknown()).optional(),
|
||||
custom_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
created: z.string().datetime(),
|
||||
updated: z.string().datetime(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user