perf: 프런트엔드 import 경계를 세분화
Gateway 화면을 route 단위로 지연 로딩하고 common runtime import를 실제 소유 leaf export로 분리한다.\n\npackage boundary와 route loading 회귀 테스트로 root barrel 재유입을 차단한다.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common/util/JosaUtil';
|
||||||
|
|
||||||
import type { CommandOption, CommandTable } from './types';
|
import type { CommandOption, CommandTable } from './types';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
|
|
||||||
export type GeneralBattleSummaryData = {
|
export type GeneralBattleSummaryData = {
|
||||||
available?: boolean;
|
available?: boolean;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { resolveTournamentStageName } from '../../utils/tournamentStatus';
|
import { resolveTournamentStageName } from '../../utils/tournamentStatus';
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,8 @@ import {
|
|||||||
MESSAGE_MAILBOX_PUBLIC,
|
MESSAGE_MAILBOX_PUBLIC,
|
||||||
type MessageType,
|
type MessageType,
|
||||||
} from '@sammo-ts/logic/messages/message.js';
|
} from '@sammo-ts/logic/messages/message.js';
|
||||||
import {
|
import { applyReadModelDelta, cloneReadModelJson } from '@sammo-ts/common/realtime/delta';
|
||||||
applyReadModelDelta,
|
import type { PublicRealtimeEvent, RealtimeReadModelInvalidation } from '@sammo-ts/common/realtime/types';
|
||||||
cloneReadModelJson,
|
|
||||||
type PublicRealtimeEvent,
|
|
||||||
type RealtimeReadModelInvalidation,
|
|
||||||
} from '@sammo-ts/common';
|
|
||||||
import { trpc } from '../utils/trpc';
|
import { trpc } from '../utils/trpc';
|
||||||
import { useMapViewerStore } from './mapViewer';
|
import { useMapViewerStore } from './mapViewer';
|
||||||
import { useSessionStore } from './session';
|
import { useSessionStore } from './session';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
type RealtimeReadModelChanges,
|
type RealtimeReadModelChanges,
|
||||||
type RealtimeReadModelInvalidation,
|
type RealtimeReadModelInvalidation,
|
||||||
type RealtimeViewerIdentity,
|
type RealtimeViewerIdentity,
|
||||||
} from '@sammo-ts/common';
|
} from '@sammo-ts/common/realtime/types';
|
||||||
|
|
||||||
export type DashboardReadModelIdentity = RealtimeViewerIdentity;
|
export type DashboardReadModelIdentity = RealtimeViewerIdentity;
|
||||||
export type DashboardRefreshPlan = RealtimeReadModelInvalidation;
|
export type DashboardRefreshPlan = RealtimeReadModelInvalidation;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import { formatLegacyLogHtml } from '@sammo-ts/common';
|
import { formatLegacyLogHtml } from '@sammo-ts/common/logging/formatLegacyLogHtml';
|
||||||
|
|
||||||
export const formatLog = (text?: string): string => formatLegacyLogHtml(text);
|
export const formatLog = (text?: string): string => formatLegacyLogHtml(text);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { trpcJsonBodyHttpClientOptions } from '@sammo-ts/common';
|
import { trpcJsonBodyHttpClientOptions } from '@sammo-ts/common/http/trpcTransport';
|
||||||
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
||||||
import type { AppRouter } from '@sammo-ts/gateway-api';
|
import type { AppRouter } from '@sammo-ts/gateway-api';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
|
|
||||||
export const formatSeoulDateTime = (value: string | Date): string => formatServerDateTime(value);
|
export const formatSeoulDateTime = (value: string | Date): string => formatServerDateTime(value);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { REALTIME_ACCESS_GRANT_HEADER, trpcJsonBodyHttpClientOptions } from '@sammo-ts/common';
|
import { trpcJsonBodyHttpClientOptions } from '@sammo-ts/common/http/trpcTransport';
|
||||||
|
import { REALTIME_ACCESS_GRANT_HEADER } from '@sammo-ts/common/realtime/types';
|
||||||
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
||||||
import type { AppRouter } from '@sammo-ts/game-api';
|
import type { AppRouter } from '@sammo-ts/game-api';
|
||||||
import { resolveBatchRealtimeAccessGrant } from './realtimeAccessGrant';
|
import { resolveBatchRealtimeAccessGrant } from './realtimeAccessGrant';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import PanelCard from '../components/ui/PanelCard.vue';
|
import PanelCard from '../components/ui/PanelCard.vue';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import TournamentBracket from '../components/tournament/TournamentBracket.vue';
|
import TournamentBracket from '../components/tournament/TournamentBracket.vue';
|
||||||
import TournamentPageHeader from '../components/tournament/TournamentPageHeader.vue';
|
import TournamentPageHeader from '../components/tournament/TournamentPageHeader.vue';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
|
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime, JosaUtil } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
|
import { JosaUtil } from '@sammo-ts/common/util/JosaUtil';
|
||||||
import { computed, onMounted, reactive, ref } from 'vue';
|
import { computed, onMounted, reactive, ref } from 'vue';
|
||||||
import { trpc } from '../utils/trpc';
|
import { trpc } from '../utils/trpc';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import type { RuntimeNavigationConfig } from '@sammo-ts/common/navigation/menuConfig';
|
import type { RuntimeNavigationConfig } from '@sammo-ts/common/navigation/menuConfig';
|
||||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common/util/JosaUtil';
|
||||||
|
|
||||||
import PersonnelSelectionDialog from '../components/personnel/PersonnelSelectionDialog.vue';
|
import PersonnelSelectionDialog from '../components/personnel/PersonnelSelectionDialog.vue';
|
||||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { trpc } from '../utils/trpc';
|
import { trpc } from '../utils/trpc';
|
||||||
type Result = Awaited<ReturnType<typeof trpc.nation.getSecretGeneralList.query>>;
|
type Result = Awaited<ReturnType<typeof trpc.nation.getSecretGeneralList.query>>;
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { isLegacyArchiveProfile, type LegacyArchiveProfile } from '@sammo-ts/common';
|
import {
|
||||||
|
isLegacyArchiveProfile,
|
||||||
|
type LegacyArchiveProfile,
|
||||||
|
} from '@sammo-ts/common/legacyArchive/ArchivedGeneralSnapshot';
|
||||||
|
|
||||||
import GeneralBasicCard from '../components/main/GeneralBasicCard.vue';
|
import GeneralBasicCard from '../components/main/GeneralBasicCard.vue';
|
||||||
import GeneralBattleSummary, { type GeneralBattleSummaryData } from '../components/main/GeneralBattleSummary.vue';
|
import GeneralBattleSummary, { type GeneralBattleSummaryData } from '../components/main/GeneralBattleSummary.vue';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import TournamentBracket from '../components/tournament/TournamentBracket.vue';
|
import TournamentBracket from '../components/tournament/TournamentBracket.vue';
|
||||||
import TournamentPageHeader from '../components/tournament/TournamentPageHeader.vue';
|
import TournamentPageHeader from '../components/tournament/TournamentPageHeader.vue';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
import HomeView from '../views/HomeView.vue';
|
|
||||||
import LobbyView from '../views/LobbyView.vue';
|
const HomeView = () => import('../views/HomeView.vue');
|
||||||
import AdminOverviewView from '../views/AdminOverviewView.vue';
|
const LobbyView = () => import('../views/LobbyView.vue');
|
||||||
import AdminView from '../views/AdminView.vue';
|
const AdminOverviewView = () => import('../views/AdminOverviewView.vue');
|
||||||
import ServerOperationsView from '../views/ServerOperationsView.vue';
|
const AdminView = () => import('../views/AdminView.vue');
|
||||||
import AccountView from '../views/AccountView.vue';
|
const ServerOperationsView = () => import('../views/ServerOperationsView.vue');
|
||||||
import OAuthCallbackView from '../views/OAuthCallbackView.vue';
|
const AccountView = () => import('../views/AccountView.vue');
|
||||||
import SignupView from '../views/SignupView.vue';
|
const OAuthCallbackView = () => import('../views/OAuthCallbackView.vue');
|
||||||
|
const SignupView = () => import('../views/SignupView.vue');
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import { formatLegacyLogHtml } from '@sammo-ts/common';
|
import { formatLegacyLogHtml } from '@sammo-ts/common/logging/formatLegacyLogHtml';
|
||||||
|
|
||||||
export const formatLog = (text: string): string => formatLegacyLogHtml(text);
|
export const formatLog = (text: string): string => formatLegacyLogHtml(text);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { trpcJsonBodyHttpClientOptions } from '@sammo-ts/common';
|
import { trpcJsonBodyHttpClientOptions } from '@sammo-ts/common/http/trpcTransport';
|
||||||
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
||||||
import type { appRouter } from '@sammo-ts/game-api';
|
import type { appRouter } from '@sammo-ts/game-api';
|
||||||
|
|
||||||
@@ -9,9 +9,7 @@ const resolveProfileUrl = (template: string, profile: string): string =>
|
|||||||
|
|
||||||
export const createGameTrpc = (profile: string, port: number, gameToken?: string) => {
|
export const createGameTrpc = (profile: string, port: number, gameToken?: string) => {
|
||||||
const urlTemplate = import.meta.env.VITE_GAME_API_URL_TEMPLATE;
|
const urlTemplate = import.meta.env.VITE_GAME_API_URL_TEMPLATE;
|
||||||
const url = urlTemplate
|
const url = urlTemplate ? resolveProfileUrl(urlTemplate, profile) : `http://localhost:${port}/api/trpc`;
|
||||||
? resolveProfileUrl(urlTemplate, profile)
|
|
||||||
: `http://localhost:${port}/api/trpc`;
|
|
||||||
return createTRPCProxyClient<GameRouter>({
|
return createTRPCProxyClient<GameRouter>({
|
||||||
links: [
|
links: [
|
||||||
httpBatchLink({
|
httpBatchLink({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { trpcJsonBodyHttpClientOptions } from '@sammo-ts/common';
|
import { trpcJsonBodyHttpClientOptions } from '@sammo-ts/common/http/trpcTransport';
|
||||||
import { createTRPCProxyClient, httpBatchLink, httpLink } from '@trpc/client';
|
import { createTRPCProxyClient, httpBatchLink, httpLink } from '@trpc/client';
|
||||||
import type { AppRouter } from '@sammo-ts/gateway-api';
|
import type { AppRouter } from '@sammo-ts/gateway-api';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import {
|
||||||
formatServerDateTime,
|
formatServerDateTime,
|
||||||
gatewayProfileCapabilities,
|
|
||||||
serverDateTimeInputToIso,
|
serverDateTimeInputToIso,
|
||||||
toServerDateTimeInputValue,
|
toServerDateTimeInputValue,
|
||||||
type GatewayProfileStatus,
|
} from '@sammo-ts/common/time/ServerDateTime';
|
||||||
} from '@sammo-ts/common';
|
import { gatewayProfileCapabilities, type GatewayProfileStatus } from '@sammo-ts/common/gateway/profileStatus';
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import ServerProfileTabs from '../components/ServerProfileTabs.vue';
|
import ServerProfileTabs from '../components/ServerProfileTabs.vue';
|
||||||
import AdminConsoleLayout from '../layouts/AdminConsoleLayout.vue';
|
import AdminConsoleLayout from '../layouts/AdminConsoleLayout.vue';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { computed, onMounted, ref } from 'vue';
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import type { inferRouterOutputs } from '@trpc/server';
|
import type { inferRouterOutputs } from '@trpc/server';
|
||||||
import type { AppRouter } from '@sammo-ts/gateway-api';
|
import type { AppRouter } from '@sammo-ts/gateway-api';
|
||||||
import { gatewayProfileCapabilities } from '@sammo-ts/common';
|
import { gatewayProfileCapabilities } from '@sammo-ts/common/gateway/profileStatus';
|
||||||
|
|
||||||
import MapPreview from '../components/MapPreview.vue';
|
import MapPreview from '../components/MapPreview.vue';
|
||||||
import KakaoOtpDialog from '../components/KakaoOtpDialog.vue';
|
import KakaoOtpDialog from '../components/KakaoOtpDialog.vue';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime } from '@sammo-ts/common';
|
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, ref, onMounted, onUnmounted, watch } from 'vue';
|
import { computed, ref, onMounted, onUnmounted, watch } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import type { inferRouterOutputs } from '@trpc/server';
|
import type { inferRouterOutputs } from '@trpc/server';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { formatServerDateTime, serverDateTimeInputToIso } from '@sammo-ts/common';
|
import { formatServerDateTime, serverDateTimeInputToIso } from '@sammo-ts/common/time/ServerDateTime';
|
||||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
||||||
|
|
||||||
import CompactHelp from '../components/CompactHelp.vue';
|
import CompactHelp from '../components/CompactHelp.vue';
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
|
const routerSourcePath = path.resolve(import.meta.dirname, '../src/router/index.ts');
|
||||||
|
|
||||||
|
void describe('gateway route loading contract', () => {
|
||||||
|
void it('loads view components through route-level dynamic imports', async () => {
|
||||||
|
const source = await readFile(routerSourcePath, 'utf8');
|
||||||
|
const staticViewImports = [...source.matchAll(/^import\s+.+\s+from\s+['"]\.\.\/views\//gm)];
|
||||||
|
const lazyViewComponents = new Set(
|
||||||
|
[...source.matchAll(/^const\s+([A-Z][A-Za-z0-9]+View)\s*=\s*\(\)\s*=>\s*import\(['"]\.\.\/views\//gm)].map(
|
||||||
|
(match) => match[1]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const routedViewComponents = new Set(
|
||||||
|
[...source.matchAll(/^\s*component:\s*([A-Z][A-Za-z0-9]+View),?$/gm)].map((match) => match[1])
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(staticViewImports, []);
|
||||||
|
assert.deepEqual(lazyViewComponents, routedViewComponents);
|
||||||
|
assert.ok(lazyViewComponents.size >= 8);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -22,9 +22,41 @@
|
|||||||
"types": "./dist/auth/gameSessionTransfer.d.ts",
|
"types": "./dist/auth/gameSessionTransfer.d.ts",
|
||||||
"default": "./dist/auth/gameSessionTransfer.js"
|
"default": "./dist/auth/gameSessionTransfer.js"
|
||||||
},
|
},
|
||||||
|
"./gateway/profileStatus": {
|
||||||
|
"types": "./dist/gateway/profileStatus.d.ts",
|
||||||
|
"default": "./dist/gateway/profileStatus.js"
|
||||||
|
},
|
||||||
|
"./http/trpcTransport": {
|
||||||
|
"types": "./dist/http/trpcTransport.d.ts",
|
||||||
|
"default": "./dist/http/trpcTransport.js"
|
||||||
|
},
|
||||||
|
"./legacyArchive/ArchivedGeneralSnapshot": {
|
||||||
|
"types": "./dist/legacyArchive/ArchivedGeneralSnapshot.d.ts",
|
||||||
|
"default": "./dist/legacyArchive/ArchivedGeneralSnapshot.js"
|
||||||
|
},
|
||||||
|
"./logging/formatLegacyLogHtml": {
|
||||||
|
"types": "./dist/logging/formatLegacyLogHtml.d.ts",
|
||||||
|
"default": "./dist/logging/formatLegacyLogHtml.js"
|
||||||
|
},
|
||||||
"./navigation/menuConfig": {
|
"./navigation/menuConfig": {
|
||||||
"types": "./dist/navigation/menuConfig.d.ts",
|
"types": "./dist/navigation/menuConfig.d.ts",
|
||||||
"default": "./dist/navigation/menuConfig.js"
|
"default": "./dist/navigation/menuConfig.js"
|
||||||
|
},
|
||||||
|
"./realtime/delta": {
|
||||||
|
"types": "./dist/realtime/delta.d.ts",
|
||||||
|
"default": "./dist/realtime/delta.js"
|
||||||
|
},
|
||||||
|
"./realtime/types": {
|
||||||
|
"types": "./dist/realtime/types.d.ts",
|
||||||
|
"default": "./dist/realtime/types.js"
|
||||||
|
},
|
||||||
|
"./time/ServerDateTime": {
|
||||||
|
"types": "./dist/time/ServerDateTime.d.ts",
|
||||||
|
"default": "./dist/time/ServerDateTime.js"
|
||||||
|
},
|
||||||
|
"./util/JosaUtil": {
|
||||||
|
"types": "./dist/util/JosaUtil.d.ts",
|
||||||
|
"default": "./dist/util/JosaUtil.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -6,7 +6,15 @@ export default defineConfig({
|
|||||||
'auth/gameToken': 'src/auth/gameToken.ts',
|
'auth/gameToken': 'src/auth/gameToken.ts',
|
||||||
'auth/gameSessionTransfer': 'src/auth/gameSessionTransfer.ts',
|
'auth/gameSessionTransfer': 'src/auth/gameSessionTransfer.ts',
|
||||||
'auth/sanctions': 'src/auth/sanctions.ts',
|
'auth/sanctions': 'src/auth/sanctions.ts',
|
||||||
|
'gateway/profileStatus': 'src/gateway/profileStatus.ts',
|
||||||
|
'http/trpcTransport': 'src/http/trpcTransport.ts',
|
||||||
|
'legacyArchive/ArchivedGeneralSnapshot': 'src/legacyArchive/ArchivedGeneralSnapshot.ts',
|
||||||
|
'logging/formatLegacyLogHtml': 'src/logging/formatLegacyLogHtml.ts',
|
||||||
'navigation/menuConfig': 'src/navigation/menuConfig.ts',
|
'navigation/menuConfig': 'src/navigation/menuConfig.ts',
|
||||||
|
'realtime/delta': 'src/realtime/delta.ts',
|
||||||
|
'realtime/types': 'src/realtime/types.ts',
|
||||||
|
'time/ServerDateTime': 'src/time/ServerDateTime.ts',
|
||||||
|
'util/JosaUtil': 'src/util/JosaUtil.ts',
|
||||||
},
|
},
|
||||||
format: 'es',
|
format: 'es',
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ const persistenceModules = new Set([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const backendPackages = new Set(['@sammo-ts/game-api', '@sammo-ts/gateway-api']);
|
const backendPackages = new Set(['@sammo-ts/game-api', '@sammo-ts/gateway-api']);
|
||||||
|
const frontendRuntimeRootBarrels = new Set(['@sammo-ts/common', '@sammo-ts/logic']);
|
||||||
|
const frontendRuntimeRootAllowlist = new Map([
|
||||||
|
['app/game-frontend/src/workers/battleSimulator.worker.ts', new Set(['@sammo-ts/logic'])],
|
||||||
|
]);
|
||||||
const nodeBuiltins = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));
|
const nodeBuiltins = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));
|
||||||
|
|
||||||
const isPersistenceModule = (specifier) =>
|
const isPersistenceModule = (specifier) =>
|
||||||
@@ -101,7 +105,19 @@ export const extractImports = (source) => {
|
|||||||
const dynamicPattern = /\bimport\(\s*['"]([^'"]+)['"]\s*\)/g;
|
const dynamicPattern = /\bimport\(\s*['"]([^'"]+)['"]\s*\)/g;
|
||||||
let match;
|
let match;
|
||||||
while ((match = fromPattern.exec(source))) {
|
while ((match = fromPattern.exec(source))) {
|
||||||
imports.push({ specifier: match[3], typeOnly: Boolean(match[1]), clause: match[2] });
|
const clause = match[2].trim();
|
||||||
|
const namedElements =
|
||||||
|
clause.startsWith('{') && clause.endsWith('}')
|
||||||
|
? clause
|
||||||
|
.slice(1, -1)
|
||||||
|
.split(',')
|
||||||
|
.map((element) => element.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
: [];
|
||||||
|
const typeOnly =
|
||||||
|
Boolean(match[1]) ||
|
||||||
|
(namedElements.length > 0 && namedElements.every((element) => element.startsWith('type ')));
|
||||||
|
imports.push({ specifier: match[3], typeOnly, clause: match[2] });
|
||||||
}
|
}
|
||||||
while ((match = sideEffectPattern.exec(source))) {
|
while ((match = sideEffectPattern.exec(source))) {
|
||||||
imports.push({ specifier: match[1], typeOnly: false, clause: '' });
|
imports.push({ specifier: match[1], typeOnly: false, clause: '' });
|
||||||
@@ -130,6 +146,14 @@ export const checkSource = ({ source, relativePath, zone }) => {
|
|||||||
if (zone.frontend && packageName && backendPackages.has(packageName) && !imported.typeOnly) {
|
if (zone.frontend && packageName && backendPackages.has(packageName) && !imported.typeOnly) {
|
||||||
violations.push(`${relativePath}: frontend may reference ${packageName} only through import type`);
|
violations.push(`${relativePath}: frontend may reference ${packageName} only through import type`);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
zone.frontend &&
|
||||||
|
frontendRuntimeRootBarrels.has(imported.specifier) &&
|
||||||
|
!imported.typeOnly &&
|
||||||
|
!frontendRuntimeRootAllowlist.get(relativePath)?.has(imported.specifier)
|
||||||
|
) {
|
||||||
|
violations.push(`${relativePath}: frontend runtime must import a leaf subpath from ${imported.specifier}`);
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
(zone.name === 'game-api' || zone.name === 'gateway-api') &&
|
(zone.name === 'game-api' || zone.name === 'gateway-api') &&
|
||||||
imported.specifier === '@sammo-ts/game-engine'
|
imported.specifier === '@sammo-ts/game-engine'
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ test('extracts multiline and type-only package imports', () => {
|
|||||||
extractImports("import {\n GamePrisma,\n type DatabaseClient\n} from '@sammo-ts/infra';")[0]?.specifier,
|
extractImports("import {\n GamePrisma,\n type DatabaseClient\n} from '@sammo-ts/infra';")[0]?.specifier,
|
||||||
'@sammo-ts/infra'
|
'@sammo-ts/infra'
|
||||||
);
|
);
|
||||||
|
assert.equal(
|
||||||
|
extractImports("import { type AppRouter, type Profile } from '@sammo-ts/gateway-api';")[0]?.typeOnly,
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rejects infrastructure access and process diagnostics in logic', () => {
|
test('rejects infrastructure access and process diagnostics in logic', () => {
|
||||||
@@ -51,3 +55,35 @@ test('rejects prefixed and bare Node builtins in frontend source', () => {
|
|||||||
'app/game-frontend/src/example.ts: frontend production code may not import node:fs',
|
'app/game-frontend/src/example.ts: frontend production code may not import node:fs',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('requires frontend common and logic runtime imports to use leaf subpaths', () => {
|
||||||
|
const zone = {
|
||||||
|
name: 'game-frontend',
|
||||||
|
allowed: ['@sammo-ts/common', '@sammo-ts/logic'],
|
||||||
|
frontend: true,
|
||||||
|
};
|
||||||
|
const violations = checkSource({
|
||||||
|
source: [
|
||||||
|
"import { formatServerDateTime } from '@sammo-ts/common';",
|
||||||
|
"import { MESSAGE_MAILBOX_PUBLIC } from '@sammo-ts/logic';",
|
||||||
|
"import type { MessageType } from '@sammo-ts/logic';",
|
||||||
|
].join('\n'),
|
||||||
|
relativePath: 'app/game-frontend/src/example.ts',
|
||||||
|
zone,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(violations, [
|
||||||
|
'app/game-frontend/src/example.ts: frontend runtime must import a leaf subpath from @sammo-ts/common',
|
||||||
|
'app/game-frontend/src/example.ts: frontend runtime must import a leaf subpath from @sammo-ts/logic',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('allows the isolated battle simulator worker to load the logic runtime root', () => {
|
||||||
|
const violations = checkSource({
|
||||||
|
source: "const loadProcessor = () => import('@sammo-ts/logic');",
|
||||||
|
relativePath: 'app/game-frontend/src/workers/battleSimulator.worker.ts',
|
||||||
|
zone: { name: 'game-frontend', allowed: ['@sammo-ts/logic'], frontend: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(violations, []);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user