chore: exclude local resource artifacts from main sync

This commit is contained in:
2026-05-15 10:16:45 +09:00
parent 442879313f
commit d38d022872
504 changed files with 17074 additions and 3642 deletions

View File

@@ -1,20 +1,21 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {
mergeDefaultChatTypes,
migrateLegacyChatTypeContexts,
stripBuiltInChatTypes,
sanitizePersistedChatTypes,
resolveAppConfigByOrigin,
resolveCanonicalChatTypesFromConfig,
resolveCanonicalChatContextSettingsFromConfig,
stripChatContextSettingsFromScopedAppConfigs,
stripSharedContextDataFromScopedAppConfigs,
} from './app-config-service.js';
test('mergeDefaultChatTypes preserves saved edits for built-in chat types', () => {
const merged = mergeDefaultChatTypes([
test('sanitizePersistedChatTypes keeps saved chat type edits as-is', () => {
const merged = sanitizePersistedChatTypes([
{
id: 'general-request',
name: '일반 요청',
sortOrder: 3,
description: '사용자가 수정한 일반 요청 문맥',
permissions: ['guest', 'token-user'],
enabled: true,
@@ -27,13 +28,15 @@ test('mergeDefaultChatTypes preserves saved edits for built-in chat types', () =
assert.ok(generalRequest);
assert.equal(generalRequest.description, '사용자가 수정한 일반 요청 문맥');
assert.deepEqual(generalRequest.permissions, ['guest', 'token-user']);
assert.equal(generalRequest.sortOrder, 1);
});
test('mergeDefaultChatTypes preserves saved edits for layout editor execution', () => {
const merged = mergeDefaultChatTypes([
test('sanitizePersistedChatTypes keeps saved layout editor execution entries', () => {
const merged = sanitizePersistedChatTypes([
{
id: 'layout-editor-execution',
name: 'Layout editor 실행',
sortOrder: 2,
description: '호출 가능한 API 요청만 처리합니다.',
permissions: ['token-user'],
enabled: true,
@@ -45,13 +48,15 @@ test('mergeDefaultChatTypes preserves saved edits for layout editor execution',
assert.ok(layoutEditorExecution);
assert.equal(layoutEditorExecution.description, '호출 가능한 API 요청만 처리합니다.');
assert.equal(layoutEditorExecution.sortOrder, 1);
});
test('mergeDefaultChatTypes preserves saved edits for guided layout editor execution', () => {
const merged = mergeDefaultChatTypes([
test('sanitizePersistedChatTypes keeps saved guided layout editor entries', () => {
const merged = sanitizePersistedChatTypes([
{
id: 'layout-editor-guided-execution',
name: 'Layout editor 단계별 실행',
sortOrder: 4,
description: '사용자가 정리한 단계별 Layout 실행 문맥',
permissions: ['token-user'],
enabled: true,
@@ -63,24 +68,48 @@ test('mergeDefaultChatTypes preserves saved edits for guided layout editor execu
assert.ok(guidedLayoutEditorExecution);
assert.equal(guidedLayoutEditorExecution.description, '사용자가 정리한 단계별 Layout 실행 문맥');
assert.equal(guidedLayoutEditorExecution.sortOrder, 1);
});
test('mergeDefaultChatTypes still appends missing built-in chat types', () => {
const merged = mergeDefaultChatTypes([]);
test('sanitizePersistedChatTypes returns empty list when nothing is saved', () => {
const merged = sanitizePersistedChatTypes([]);
assert.ok(merged.some((item) => item.id === 'general-request'));
assert.ok(merged.some((item) => item.id === 'layout-editor-execution'));
assert.ok(merged.some((item) => item.id === 'api-request-template'));
assert.ok(merged.some((item) => item.id === 'general-inquiry'));
assert.ok(!merged.some((item) => item.id === 'plan-checklist-execution'));
assert.ok(!merged.some((item) => item.id === 'layout-editor-guided-execution'));
assert.deepEqual(merged, []);
});
test('stripBuiltInChatTypes removes built-in chat type ids from saved list', () => {
const stripped = stripBuiltInChatTypes([
test('sanitizePersistedChatTypes keeps saved chat type list without backfilling removed entries', () => {
const merged = sanitizePersistedChatTypes([
{
id: 'general-request',
name: '일반 요청',
sortOrder: 2,
description: '사용자가 수정한 일반 요청 문맥',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
{
id: 'custom-support-flow',
name: '운영 문의 전용',
sortOrder: 1,
description: 'custom',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
]);
assert.ok(!merged.some((item) => item.id === 'layout-editor-guided-execution'));
assert.ok(!merged.some((item) => item.id === 'layout-editor-execution'));
assert.ok(merged.some((item) => item.id === 'custom-support-flow'));
});
test('sanitizePersistedChatTypes keeps all saved chat types without special filtering', () => {
const stripped = sanitizePersistedChatTypes([
{
id: 'general-request',
name: '일반 요청',
sortOrder: 2,
description: 'builtin',
permissions: ['token-user'],
enabled: true,
@@ -89,6 +118,7 @@ test('stripBuiltInChatTypes removes built-in chat type ids from saved list', ()
{
id: 'plan-checklist-execution',
name: 'Plan 체크리스트 실행',
sortOrder: 3,
description: 'custom-seeded',
permissions: ['token-user'],
enabled: true,
@@ -97,6 +127,7 @@ test('stripBuiltInChatTypes removes built-in chat type ids from saved list', ()
{
id: 'custom-support-flow',
name: '운영 문의 전용',
sortOrder: 1,
description: 'custom',
permissions: ['token-user'],
enabled: true,
@@ -104,7 +135,7 @@ test('stripBuiltInChatTypes removes built-in chat type ids from saved list', ()
},
]);
assert.deepEqual(stripped.map((item) => item.id), ['custom-support-flow', 'plan-checklist-execution']);
assert.deepEqual(stripped.map((item) => item.id), ['custom-support-flow', 'general-request', 'plan-checklist-execution']);
});
test('migrateLegacyChatTypeContexts moves legacy plan checklist chat type into default context settings', () => {
@@ -124,6 +155,7 @@ test('migrateLegacyChatTypeContexts moves legacy plan checklist chat type into d
{
id: 'plan-checklist-execution',
name: 'Plan 체크리스트 실행',
sortOrder: 1,
description: 'legacy plan context',
permissions: ['token-user'],
enabled: true,
@@ -178,7 +210,7 @@ test('resolveAppConfigByOrigin falls back to legacy global config when scoped co
receiveRoomNotifications: true,
},
},
'https://test.sm-home.cloud',
'https://preview.sm-home.cloud',
) as {
chat?: { receiveRoomNotifications?: boolean };
};
@@ -208,7 +240,7 @@ test('resolveCanonicalChatContextSettingsFromConfig prefers global chat context
],
},
scopedAppConfigs: {
'https://test.sm-home.cloud': {
'https://preview.sm-home.cloud': {
config: {
chatContextSettings: {
defaultContexts: [
@@ -225,7 +257,7 @@ test('resolveCanonicalChatContextSettingsFromConfig prefers global chat context
},
},
},
'https://test.sm-home.cloud',
'https://preview.sm-home.cloud',
);
assert.deepEqual(
@@ -234,11 +266,76 @@ test('resolveCanonicalChatContextSettingsFromConfig prefers global chat context
);
});
test('resolveCanonicalChatContextSettingsFromConfig keeps saved default context sort order and renumbers gaps', () => {
const resolved = resolveCanonicalChatContextSettingsFromConfig({
chatContextSettings: {
defaultContexts: [
{
id: 'context-b',
title: 'B 문맥',
sortOrder: 3,
content: 'b',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
{
id: 'context-a',
title: 'A 문맥',
sortOrder: 1,
content: 'a',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
},
});
assert.deepEqual(
resolved.defaultContexts.map((item) => ({ id: item.id, sortOrder: item.sortOrder })),
[
{ id: 'context-a', sortOrder: 1 },
{ id: 'context-b', sortOrder: 2 },
],
);
});
test('resolveCanonicalChatContextSettingsFromConfig appends unsorted default contexts after sorted entries', () => {
const resolved = resolveCanonicalChatContextSettingsFromConfig({
chatContextSettings: {
defaultContexts: [
{
id: 'context-b',
title: 'B 문맥',
content: 'b',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
{
id: 'context-a',
title: 'A 문맥',
sortOrder: 1,
content: 'a',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
},
});
assert.deepEqual(
resolved.defaultContexts.map((item) => ({ id: item.id, sortOrder: item.sortOrder })),
[
{ id: 'context-a', sortOrder: 1 },
{ id: 'context-b', sortOrder: 2 },
],
);
});
test('resolveCanonicalChatContextSettingsFromConfig falls back to scoped settings only when global settings are empty', () => {
const resolved = resolveCanonicalChatContextSettingsFromConfig(
{
scopedAppConfigs: {
'https://test.sm-home.cloud': {
'https://preview.sm-home.cloud': {
config: {
chatContextSettings: {
defaultContexts: [
@@ -255,7 +352,7 @@ test('resolveCanonicalChatContextSettingsFromConfig falls back to scoped setting
},
},
},
'https://test.sm-home.cloud',
'https://preview.sm-home.cloud',
);
assert.deepEqual(
@@ -278,7 +375,7 @@ test('resolveCanonicalChatTypesFromConfig merges global chat types with stale sc
},
],
scopedAppConfigs: {
'https://test.sm-home.cloud': {
'https://preview.sm-home.cloud': {
config: {
chatTypes: [
{
@@ -294,7 +391,7 @@ test('resolveCanonicalChatTypesFromConfig merges global chat types with stale sc
},
},
},
'https://test.sm-home.cloud',
'https://preview.sm-home.cloud',
);
assert.ok(resolved);
@@ -305,7 +402,7 @@ test('resolveCanonicalChatTypesFromConfig merges global chat types with stale sc
test('stripChatContextSettingsFromScopedAppConfigs removes stale scoped chat context settings only', () => {
const stripped = stripChatContextSettingsFromScopedAppConfigs({
scopedAppConfigs: {
'https://test.sm-home.cloud': {
'https://preview.sm-home.cloud': {
config: {
chatContextSettings: {
defaultContexts: [{ id: 'legacy', title: 'legacy', content: 'legacy', enabled: true }],
@@ -321,7 +418,7 @@ test('stripChatContextSettingsFromScopedAppConfigs removes stale scoped chat con
assert.equal(stripped.changed, true);
assert.deepEqual(stripped.scopedConfigs, {
'https://test.sm-home.cloud': {
'https://preview.sm-home.cloud': {
config: {
chat: {
receiveRoomNotifications: false,
@@ -331,3 +428,104 @@ test('stripChatContextSettingsFromScopedAppConfigs removes stale scoped chat con
},
});
});
test('stripSharedContextDataFromScopedAppConfigs removes scoped chat-type/context data and backs up non-shared origins', () => {
const stripped = stripSharedContextDataFromScopedAppConfigs(
{
scopedAppConfigs: {
'https://preview.sm-home.cloud': {
config: {
chatTypes: [
{
id: 'general-request',
name: '일반 요청',
description: 'preview-shared',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
chatContextSettings: {
defaultContexts: [
{
id: 'preview-context',
title: 'preview',
content: 'shared',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
},
chat: {
receiveRoomNotifications: false,
},
},
updatedAt: '2026-05-08T00:00:00.000Z',
appDomain: 'preview.sm-home.cloud',
},
'https://test.sm-home.cloud': {
config: {
chatTypes: [
{
id: 'chat-type-test-temp',
name: '임시 유형',
description: 'test-only',
permissions: ['token-user'],
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
chatContextSettings: {
defaultContexts: [
{
id: 'test-context',
title: 'test',
content: 'legacy',
enabled: true,
updatedAt: '2026-05-08T00:00:00.000Z',
},
],
},
automation: {
notifyOnAutomationStart: true,
},
},
updatedAt: '2026-05-08T00:00:00.000Z',
appDomain: 'test.sm-home.cloud',
},
},
},
'https://preview.sm-home.cloud',
);
assert.equal(stripped.changed, true);
assert.deepEqual(stripped.scopedConfigs, {
'https://preview.sm-home.cloud': {
config: {
chat: {
receiveRoomNotifications: false,
},
},
updatedAt: '2026-05-08T00:00:00.000Z',
appDomain: 'preview.sm-home.cloud',
},
'https://test.sm-home.cloud': {
config: {
automation: {
notifyOnAutomationStart: true,
},
},
updatedAt: '2026-05-08T00:00:00.000Z',
appDomain: 'test.sm-home.cloud',
},
});
assert.equal(
Array.isArray(stripped.backups['https://test.sm-home.cloud']?.chatTypes),
true,
);
assert.equal(
stripped.backups['https://test.sm-home.cloud']?.chatContextSettings?.defaultContexts[0]?.id,
'test-context',
);
assert.equal(stripped.backups['https://preview.sm-home.cloud'], undefined);
});