chore: exclude local resource artifacts from main sync
This commit is contained in:
3
etc/servers/work-server/src/routes/app-config.ts
Executable file → Normal file
3
etc/servers/work-server/src/routes/app-config.ts
Executable file → Normal file
@@ -111,13 +111,12 @@ export async function registerAppConfigRoutes(app: FastifyInstance) {
|
||||
const parsed = z
|
||||
.object({
|
||||
chatTypes: z.array(z.unknown()).optional(),
|
||||
customChatTypes: z.array(z.unknown()).optional(),
|
||||
})
|
||||
.parse(payload ?? {});
|
||||
|
||||
const appOrigin = getRequestAppOrigin(request);
|
||||
const appDomain = getRequestAppDomain(request);
|
||||
const targetChatTypes = parsed.customChatTypes ?? parsed.chatTypes ?? [];
|
||||
const targetChatTypes = parsed.chatTypes ?? [];
|
||||
const savedChatTypeConfig = await upsertChatTypesConfig(targetChatTypes, appOrigin, appDomain);
|
||||
|
||||
return {
|
||||
|
||||
0
etc/servers/work-server/src/routes/board.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/board.ts
Executable file → Normal file
39
etc/servers/work-server/src/routes/chat.ts
Executable file → Normal file
39
etc/servers/work-server/src/routes/chat.ts
Executable file → Normal file
@@ -16,6 +16,7 @@ import {
|
||||
deleteChatConversation,
|
||||
ensureChatConversationTables,
|
||||
getChatConversation,
|
||||
listChatSourceChangeSnapshots,
|
||||
listChatConversationDetailPage,
|
||||
listChatConversations,
|
||||
markChatConversationResponsesRead,
|
||||
@@ -205,6 +206,21 @@ export async function registerChatRoutes(app: FastifyInstance) {
|
||||
};
|
||||
});
|
||||
|
||||
app.get('/api/chat/source-changes', async (request) => {
|
||||
const query = z.object({
|
||||
limit: z.coerce.number().int().min(1).max(500).optional(),
|
||||
}).parse(request.query ?? {});
|
||||
|
||||
const viewerClientId = getClientIdHeader(request);
|
||||
const clientId = canViewAllConversations(request) ? null : viewerClientId;
|
||||
const items = await listChatSourceChangeSnapshots(clientId, query.limit ?? 300);
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
items,
|
||||
};
|
||||
});
|
||||
|
||||
app.get('/api/chat/runtime', async () => {
|
||||
return {
|
||||
ok: true,
|
||||
@@ -380,6 +396,7 @@ export async function registerChatRoutes(app: FastifyInstance) {
|
||||
const payload = z.object({
|
||||
sessionId: z.string().trim().min(1).max(120),
|
||||
title: z.string().trim().max(200).optional(),
|
||||
requestBadgeLabel: z.string().trim().max(120).optional().nullable(),
|
||||
chatTypeId: z.string().trim().max(120).nullable().optional(),
|
||||
lastChatTypeId: z.string().trim().max(120).nullable().optional(),
|
||||
generalSectionName: z.string().trim().max(120).optional().nullable(),
|
||||
@@ -393,6 +410,7 @@ export async function registerChatRoutes(app: FastifyInstance) {
|
||||
sessionId: payload.sessionId,
|
||||
clientId: clientId || null,
|
||||
title: payload.title ?? '새 대화',
|
||||
requestBadgeLabel: payload.requestBadgeLabel ?? null,
|
||||
chatTypeId: payload.chatTypeId ?? null,
|
||||
lastChatTypeId: payload.lastChatTypeId ?? payload.chatTypeId ?? null,
|
||||
generalSectionName: payload.generalSectionName ?? null,
|
||||
@@ -509,6 +527,7 @@ export async function registerChatRoutes(app: FastifyInstance) {
|
||||
}).parse(request.params ?? {});
|
||||
const payload = z.object({
|
||||
title: z.string().trim().min(1).max(200).optional(),
|
||||
requestBadgeLabel: z.string().trim().max(120).optional().nullable(),
|
||||
chatTypeId: z.string().trim().max(120).optional().nullable(),
|
||||
lastChatTypeId: z.string().trim().max(120).optional().nullable(),
|
||||
generalSectionName: z.string().trim().max(120).optional().nullable(),
|
||||
@@ -528,12 +547,22 @@ export async function registerChatRoutes(app: FastifyInstance) {
|
||||
|
||||
const item = await updateChatConversationContext(params.sessionId, {
|
||||
title: payload.title ?? current.title,
|
||||
requestBadgeLabel:
|
||||
Object.prototype.hasOwnProperty.call(payload, 'requestBadgeLabel') ? payload.requestBadgeLabel ?? null : undefined,
|
||||
clientId: current.clientId,
|
||||
chatTypeId: payload.chatTypeId ?? current.chatTypeId,
|
||||
lastChatTypeId: payload.lastChatTypeId ?? current.lastChatTypeId ?? current.chatTypeId,
|
||||
generalSectionName: payload.generalSectionName ?? current.generalSectionName,
|
||||
contextLabel: payload.contextLabel ?? current.contextLabel,
|
||||
contextDescription: payload.contextDescription ?? current.contextDescription,
|
||||
chatTypeId: Object.prototype.hasOwnProperty.call(payload, 'chatTypeId') ? payload.chatTypeId ?? null : undefined,
|
||||
lastChatTypeId:
|
||||
Object.prototype.hasOwnProperty.call(payload, 'lastChatTypeId') ? payload.lastChatTypeId ?? null : undefined,
|
||||
generalSectionName:
|
||||
Object.prototype.hasOwnProperty.call(payload, 'generalSectionName')
|
||||
? payload.generalSectionName ?? null
|
||||
: undefined,
|
||||
contextLabel:
|
||||
Object.prototype.hasOwnProperty.call(payload, 'contextLabel') ? payload.contextLabel ?? null : undefined,
|
||||
contextDescription:
|
||||
Object.prototype.hasOwnProperty.call(payload, 'contextDescription')
|
||||
? payload.contextDescription ?? null
|
||||
: undefined,
|
||||
notifyOffline: payload.notifyOffline ?? current.notifyOffline,
|
||||
});
|
||||
|
||||
|
||||
0
etc/servers/work-server/src/routes/compatibility.test.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/compatibility.test.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/crud.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/crud.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/ddl.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/ddl.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/error-log.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/error-log.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/health.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/health.ts
Executable file → Normal file
56
etc/servers/work-server/src/routes/notification.ts
Executable file → Normal file
56
etc/servers/work-server/src/routes/notification.ts
Executable file → Normal file
@@ -1,21 +1,16 @@
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import { z } from 'zod';
|
||||
import {
|
||||
listIosNotificationTokens,
|
||||
listWebPushSubscriptions,
|
||||
getAutomationNotificationPreference,
|
||||
getWebPushConfig,
|
||||
registerIosNotificationToken,
|
||||
registerAutomationNotificationPreferenceSchema,
|
||||
registerIosTokenSchema,
|
||||
registerWebPushSubscription,
|
||||
registerWebPushSubscriptionSchema,
|
||||
sendNotifications,
|
||||
sendIosNotificationSchema,
|
||||
setupNotificationTables,
|
||||
upsertAutomationNotificationPreference,
|
||||
unregisterIosNotificationToken,
|
||||
unregisterIosTokenSchema,
|
||||
unregisterWebPushSubscription,
|
||||
unregisterWebPushSubscriptionSchema,
|
||||
} from '../services/notification-service.js';
|
||||
@@ -31,14 +26,10 @@ import {
|
||||
} from '../services/notification-message-service.js';
|
||||
|
||||
const automationNotificationPreferenceQuerySchema = z.object({
|
||||
targetKind: z.enum(['client', 'ios-token', 'ios-token-client', 'web-endpoint']).optional(),
|
||||
targetKind: z.enum(['client', 'web-endpoint']).optional(),
|
||||
targetId: z.string().trim().min(1).max(1000).optional(),
|
||||
});
|
||||
|
||||
type AutomationNotificationPreferenceTargetKind = NonNullable<
|
||||
z.infer<typeof automationNotificationPreferenceQuerySchema>['targetKind']
|
||||
>;
|
||||
|
||||
function getClientIdHeader(request: { headers: Record<string, string | string[] | undefined> }) {
|
||||
const rawClientId = request.headers['x-client-id'];
|
||||
const clientId = Array.isArray(rawClientId) ? rawClientId[0] : rawClientId;
|
||||
@@ -48,10 +39,6 @@ function getClientIdHeader(request: { headers: Record<string, string | string[]
|
||||
export async function registerNotificationRoutes(app: FastifyInstance) {
|
||||
app.post('/api/notifications/setup', async () => setupNotificationTables());
|
||||
|
||||
app.get('/api/notifications/tokens', async () => ({
|
||||
items: await listIosNotificationTokens(),
|
||||
}));
|
||||
|
||||
app.get('/api/notifications/subscriptions/web', async () => ({
|
||||
items: await listWebPushSubscriptions(),
|
||||
}));
|
||||
@@ -60,9 +47,10 @@ export async function registerNotificationRoutes(app: FastifyInstance) {
|
||||
|
||||
app.get('/api/notifications/messages', async (request) => {
|
||||
const query = notificationMessageListQuerySchema.parse(request.query ?? {});
|
||||
const clientId = getClientIdHeader(request);
|
||||
return {
|
||||
ok: true,
|
||||
...(await listNotificationMessages(query)),
|
||||
...(await listNotificationMessages(query, clientId)),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -130,7 +118,7 @@ export async function registerNotificationRoutes(app: FastifyInstance) {
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
automation: await getAutomationNotificationPreferenceWithFallback(targetId, targetKind),
|
||||
automation: await getAutomationNotificationPreference(targetId, targetKind),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -154,16 +142,6 @@ export async function registerNotificationRoutes(app: FastifyInstance) {
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/notifications/tokens/ios', async (request) => {
|
||||
const payload = registerIosTokenSchema.parse(request.body ?? {});
|
||||
return registerIosNotificationToken(payload);
|
||||
});
|
||||
|
||||
app.delete('/api/notifications/tokens/ios', async (request) => {
|
||||
const payload = unregisterIosTokenSchema.parse(request.body ?? {});
|
||||
return unregisterIosNotificationToken(payload.token);
|
||||
});
|
||||
|
||||
app.put('/api/notifications/subscriptions/web', async (request) => {
|
||||
const payload = registerWebPushSubscriptionSchema.parse(request.body ?? {});
|
||||
return registerWebPushSubscription(payload);
|
||||
@@ -184,29 +162,3 @@ export async function registerNotificationRoutes(app: FastifyInstance) {
|
||||
return sendNotifications(payload);
|
||||
});
|
||||
}
|
||||
async function getAutomationNotificationPreferenceWithFallback(
|
||||
targetId: string,
|
||||
targetKind: AutomationNotificationPreferenceTargetKind,
|
||||
) {
|
||||
const automation = await getAutomationNotificationPreference(targetId, targetKind);
|
||||
|
||||
if (automation || targetKind !== 'ios-token-client') {
|
||||
return automation;
|
||||
}
|
||||
|
||||
const [token, clientId] = targetId.split('::client::');
|
||||
|
||||
if (token?.trim()) {
|
||||
const tokenAutomation = await getAutomationNotificationPreference(token.trim(), 'ios-token');
|
||||
|
||||
if (tokenAutomation) {
|
||||
return tokenAutomation;
|
||||
}
|
||||
}
|
||||
|
||||
if (clientId?.trim()) {
|
||||
return getAutomationNotificationPreference(clientId.trim(), 'client');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
0
etc/servers/work-server/src/routes/plan.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/plan.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/schema.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/schema.ts
Executable file → Normal file
40
etc/servers/work-server/src/routes/server-command.ts
Executable file → Normal file
40
etc/servers/work-server/src/routes/server-command.ts
Executable file → Normal file
@@ -19,6 +19,36 @@ const restartReservationBodySchema = z.object({
|
||||
autoExecuteDelaySeconds: z.number().int().min(1).max(300).optional(),
|
||||
});
|
||||
|
||||
function getImmediateRestartBlockInfo(
|
||||
key: z.infer<typeof serverCommandParamSchema>['key'],
|
||||
workloadSummary: Awaited<ReturnType<typeof getRestartReservationWorkloadSummary>>,
|
||||
) {
|
||||
const codexPendingCount = workloadSummary.codexRunningCount + workloadSummary.codexQueuedCount;
|
||||
const automationPendingCount = workloadSummary.automationRunningCount + workloadSummary.automationQueuedCount;
|
||||
|
||||
if (key === 'test') {
|
||||
const pendingCount = codexPendingCount + automationPendingCount;
|
||||
|
||||
if (pendingCount > 0) {
|
||||
return {
|
||||
pendingCount,
|
||||
message: `진행 중인 Codex Live/자동화 작업 ${pendingCount}건이 있어 즉시 재기동할 수 없습니다. 재기동 예약을 사용해 주세요.`,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (key === 'work-server' && automationPendingCount > 0) {
|
||||
return {
|
||||
pendingCount: automationPendingCount,
|
||||
message: `진행 중인 자동화 작업 ${automationPendingCount}건이 있어 즉시 재기동할 수 없습니다. 재기동 예약을 사용해 주세요.`,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getRequestAccessToken(request: FastifyRequest) {
|
||||
const tokenHeader = request.headers['x-access-token'];
|
||||
return Array.isArray(tokenHeader) ? tokenHeader[0]?.trim() ?? '' : String(tokenHeader ?? '').trim();
|
||||
@@ -75,17 +105,13 @@ export async function registerServerCommandRoutes(app: FastifyInstance) {
|
||||
|
||||
if (key === 'test' || key === 'work-server') {
|
||||
const workloadSummary = await getRestartReservationWorkloadSummary();
|
||||
const pendingCount =
|
||||
workloadSummary.codexRunningCount
|
||||
+ workloadSummary.codexQueuedCount
|
||||
+ workloadSummary.automationRunningCount
|
||||
+ workloadSummary.automationQueuedCount;
|
||||
const blockInfo = getImmediateRestartBlockInfo(key, workloadSummary);
|
||||
|
||||
if (pendingCount > 0) {
|
||||
if (blockInfo) {
|
||||
reply.status(409);
|
||||
return {
|
||||
ok: false,
|
||||
message: `진행 중인 Codex Live/자동화 작업 ${pendingCount}건이 있어 즉시 재기동할 수 없습니다. 재기동 예약을 사용해 주세요.`,
|
||||
message: blockInfo.message,
|
||||
workloadSummary,
|
||||
};
|
||||
}
|
||||
|
||||
0
etc/servers/work-server/src/routes/visitor-history.ts
Executable file → Normal file
0
etc/servers/work-server/src/routes/visitor-history.ts
Executable file → Normal file
Reference in New Issue
Block a user